Back to home@JingxuanC

causal-memory

Causal memory layer for AI agents — MCP server that records decision→outcome relationships. Survives compaction.

Stars
47
Language
Rust
Created
Jul 26, 2026
Updated
Aug 24, 2026
GitHub repo

Introduction

causal-memory

An agent memory system with a causal core — and the only one that models inhibition.

Facts, temporal state, and decision → outcome causal edges on one SQLite store, powered by a hippocampus-style engine: typed spreading activation (excitatory and inhibitory), Hebbian co-occurrence reinforcement, Q-value dynamics, and immutable SWR consolidation. Agents recall what happened, when it was true, why it worked — and what would happen if they acted differently.

License: Apache-2.0 Status: v0.9.0 Tests: 368 Release: v0.9.0

English · 简体中文


Why

Every agent forgets why it made past decisions after a few context compactions. It re-fixes the same bug the same wrong way, re-debates the same architecture choice, relearns the same lesson.

This happens because causal information is the most fragile type under text compaction. Real-LLM benchmark (grok-build's production compaction prompt):

Compactions (k)Textual recallCausal-table recall
1100%100%
285%100%
355%100%
545%100%

The causal table survives because it lives outside the agent's context window — compaction cannot touch it.


Demo

A 21-second hands-on demo (real memory store, no mocks): pre-action warning (intervention_query → DANGER chain) → experience recall (search_causal) → counterfactual comparison (counterfactual_query) → write loop (record_decision → immediately searchable).

21-second demo

Download video · Warning-scene screenshot · Brand card · Regenerate: scripts/render_demo.py


Benchmarks

CausalEval — the causal memory benchmark (primary)

Most agent-memory benchmarks (LoCoMo, LongMemEval, Memora) test fact recall ("what is the user's preference"). causal-memory's differentiators — typed causal edges, inhibition, intervention prediction, cross-task transfer — are invisible on those suites. CausalEval measures them.

Design: the causal graph is the answer key. Typed DAGs are generated deterministically; conversations are narrated from the graph; gold answers are derived from graph structure — zero hand annotation, zero ambiguity.

CausalEval v13 (soft supersession) — 140 questions, 20 graphs (same LLM, same judge; v12 baseline was 70q/10 graphs; mem0 comparison ran on the 70q protocol):

Capabilitycausal-memoryv12 (70q)mem0 (70q)What it tests
C7 Update100%50%80%Supersede old belief after falsification (soft superseded_by annotation)
C3 Counterfactual95%90%80%Choosing between alternatives with known outcomes
C2 Intervention75%70%40%Forward prediction: "if X again, what happens?"
C4 Inhibition80%90%50%Distinguishing root-cause fix vs blast-radius limiter (prevented edges)
C1 Attribution85%90%90%Backward causal chain → root cause
C5 Temporal-causal90%100%90%Ordering on a causal chain
C6 Lesson transfer20%20%30%Cross-task analogy via meta edges (open limitation)
Overall78%81%65%

Key result: C7 update 50% → 100% (+50pp, 20/20 questions) and it holds at doubled sample size. Soft supersession annotates superseded edges (superseded_by) instead of hiding them — the falsification signal reaches the answer model while the old lesson stays retrievable for counterfactuals (C3 unharmed at 95%). The C6 gap (20% vs mem0 30%) is the remaining open limitation; C1/C4/C5 dips vs v12 are within re-distillation variance and new-graph difficulty (v12 and v13 do not share a distilled corpus).

Fact-recall benchmarks (not our strong suit)

On traditional fact-recall suites, causal-memory performs competitively but does not beat mem0 — this is expected, because fact recall is mem0's specialty and not where causal-memory adds value.

Benchmarkcausal-memorymem0Note
LoCoMo (strict judge)79.1%91.6%mem0's home turf
LongMemEval-S (full pipeline, deepseek-chat)76.4% @ 11.5K tok/q94.4% @ 6.8K tok/q (official) · 73.8% (ind. repro)single-model stack vs platform stack; see docs/benchmarks/longmemeval.md
Memora MPA67.4%71.8%−4.4pp
Compaction survival100%45%External table = immune to compaction
Agent repeat-mistake33%67%−34pp on trap-world

Capability tests (322 across the workspace)

These test capabilities that no fact store (mem0, Zep, Letta) can offer.

CapabilityWhat it provesTests
Prevented-edge warningprevented edge spreads −0.3 activation (GABA analogue)2
Trace-cause attributionBackward CSR traversal finds root cause2
Multi-hop causal chainForward K-hop spreading reaches 2-3 hop outcomes2
Inhibitory filteringPrevented outcomes appear as negative, not false positives1
Intervention comparisonSame outcome has +0.9 for "skip tests" and −0.3 for "add tests"4
SWR consolidationLTP strengthens replayed edges, LTD weakens unvisited, GC forgets dormant5
Q-value dynamicsGood decisions rank higher; Bellman propagates to parents3
Novelty entropyDiverse experience triggers consolidation; uniform does not3
Meta-edge miningCross-session pattern discovery (similar_to / repeated)3
Hebbian co-occurrenceRepeated co-activation strengthens connection3

What makes it different

Capabilitycausal-memorymem0ZepLettaHeLa-Mem
Typed causal semantics (caused/enabled/prevented)
prevented negative spread (inhibitory)
Hebbian co-occurrence edges (excitatory)
Immutable consolidation (delta + clone)
Q-value dynamic utility
Forward simulation (intervention_query)
SWR offline consolidation (LTP/LTD/GC)
Novelty-entropy consolidation trigger
Meta-edge cross-session pattern mining
Compaction survival evidence✅ +20.8pp
One graph unifying all memory types⚠️⚠️
Write-time gatekeeping (raw → session_logs)
Local ONNX embedding (offline)

Core innovation: the excitatory/inhibitory duality. HeLa-Mem (ACL 2026) builds the excitatory side (Hebbian co-activation, positive spread). causal-memory adds the inhibitory side (prevented edges spread negative activation — a GABA analogue). A complete memory needs both: "what caused this" and "what prevents this from happening again."


Architecture

architecture

Interactive version: docs/architecture.html

  ┌───────────────────────────────────────────────┐
  │           causal-memory (Rust, MCP)            │
  │                                                │
  │  14 tools ← Agent (stdio / HTTP)                 │
  │    ↓                                           │
  │  Write-time gatekeeping                        │
  │    raw turns → session_logs (audit only)       │
  │    distill → facts + causal edges (searchable) │
  │    ↓                                           │
  │  Unified retrieval (RRF fusion)                │
  │    BM25 + semantic cosine → RRF merge          │
  │    Fact layer (BM25 + embeddings)              │
  │    ↓                                           │
  │  ┌──── Hippocampus engine ──────────────────┐  │
  │  │ CSR graph + spreading activation          │  │
  │  │  caused (+1.0)   enabled (+0.5)           │  │
  │  │  prevented (−0.3) ← GABA inhibitory       │  │
  │  │  fact (+0.8)     meta (+0.6)              │  │
  │  │  co_occurrence (Hebbian, dynamic)         │  │
  │  │                                            │  │
  │  │ DG: SimHash pattern separation             │  │
  │  │ CA3: K-hop spreading (forward + reverse)   │  │
  │  │ CA1: Novelty entropy trigger               │  │
  │  │ SWR: LTP/LTD/GC (immutable delta + clone)  │  │
  │  │ Q-value: Bellman dynamics (MemRL-style)    │  │
  │  └────────────────────────────────────────────┘  │
  │    ↓                                           │
  │  SQLite (causal.db) — never compacted          │
  └───────────────────────────────────────────────┘

The causal_edges table is never compacted — it lives outside the agent's context window. That's the entire point.


Edge types

Edge typeSpread coeffBiological analogueMeaning
caused+1.0Glutamate (strong excitatory)"Doing X caused Y"
fact+0.8Semantic association"User is/has Z"
meta+0.6Cortical top-downCross-task pattern link
enabled+0.5Weak excitatory"Doing X enabled Y"
co_occurrencedynamicHebbian LTP"X and Y frequently co-occur"
prevented−0.3GABA (inhibitory)"Doing X prevented Y"
no_effect0.0No causal relationship

Quick start

git clone https://github.com/JingxuanC/causal-memory.git
cd causal-memory
cargo build --release

MCP integration (Claude Code, Cursor, grok-build, etc.)

{
  "mcpServers": {
    "causal-memory": {
      "command": "/path/to/causal-memory/target/release/causal-memory",
      "env": {
        "CAUSAL_MEMORY_DB": "~/.local/share/causal-memory/causal.db"
      }
    }
  }
}

HTTP transport (remote agents, multi-agent shared memory)

./target/release/causal-memory http --port 9938   # MCP Streamable HTTP

With local embeddings (no API key needed)

cargo build --release --features local-embed
# Uses BAAI/bge-small-en-v1.5 (384 dims, ~130MB, downloads once then offline)

With HTTP embeddings (OpenAI/ZhiPu/etc.)

export CAUSAL_MEMORY_EMBED_API=https://open.bigmodel.cn/api/paas/v4
export CAUSAL_MEMORY_EMBED_KEY=your-key
export CAUSAL_MEMORY_EMBED_MODEL=embedding-3

Python bindings (PyO3)

All 14 memory operations are also available as a Python package, built on the same causal_memory::memory::Memory facade the MCP server uses:

cd crates/causal-memory-py
pip install maturin
maturin develop          # builds and installs into the active venv
from causal_memory import CausalMemory

mem = CausalMemory("~/.local/share/causal-memory/causal.db")  # or CausalMemory.in_memory()
mem.record_decision("used Redis mutex for cache stampede protection",
                    "deadlock under load", "caused", "concurrency")
print(mem.search_causal(query="cache stampede protection"))
print(mem.intervention_query("skip the test suite before shipping"))

Methods mirror the 14 MCP tools one-to-one and return the same text. Embedding and LLM features use the same CAUSAL_MEMORY_EMBED_* / CAUSAL_MEMORY_LLM_* environment variables; without them the bindings degrade gracefully to BM25-only retrieval. Smoke tests: maturin develop && pytest tests/.

macOS note: always build the bindings through maturin. Plain cargo build -p causal-memory-py --release fails to link — the Xcode CLT Python ships no libpython3.9 dylib (this is why the py crate sits outside the workspace default-members).


Fourteen MCP tools

ToolWhen to callWhat it does
record_decisionAfter acting on a decisionLogs decision → outcome as a causal edge with relation type
rememberAfter any meaningful exchangeZero-friction alternative: paste conversation text, LLM auto-extracts facts/lessons/causal edges
search_causalBefore a non-trivial decisionBM25 + semantic retrieval of past causal episodes
record_factWhen learning a stable factRecords flat facts with scope + confidence; idempotent
search_factsWhen you need "what is" infoBM25 + semantic retrieval over the fact layer
search_memoryWhen unsure which typeUnified: facts + causal lessons fused by RRF
trace_causeWhen something failsSingle-hop reverse: which decision caused this outcome
trace_cause_chainDeep failure analysisMulti-hop backward traversal through the causal graph
invalidate_decisionWhen a lesson is wrongSoft-invalidate (hidden from search, kept for audit)
search_patternsTo recall cross-task lessonsMined meta edges: similar_to / repeated / contradicts / refines
causal_directoryPinned in system promptL0 compact pointer list of what the agent knows
intervention_queryBefore taking an actionForward simulation: predicts outcomes (safe/warning/danger)
counterfactual_queryWhen choosing between optionsContrastive: compares recorded outcomes of two alternatives
reconstruct_lessonWhen you want the distilled lessonReconstructive retrieval: Markov-blanket subgraph → coherent narrative, with optional N-way calibration

Sleep consolidation

causal-memory sleep --dry-run   # preview what would change
causal-memory sleep             # run consolidation cycle

Immutable SWR 2.0: produces a delta + clone (original graph untouched), with full audit log. Triple-criterion GC (weak AND dormant AND zero-access). Triggers automatically when novelty entropy exceeds threshold.


Causal distill pipeline

The distiller extracts structured memories from raw conversations:

Raw conversation → V3 extraction prompt (130 lines, 6 rules, 5 few-shot)
                   ↓
  Fact/Preference → agent_facts table (BM25 + embedding searchable)
  Lesson/Event    → causal edges (self-referential, searchable)
  Causal          → proper directed edge: decision → outcome
                    with relation type (caused/enabled/prevented)

Raw turns go to session_logs (audit/replay only) — they never enter the retrieval pool. This write-time gatekeeping keeps BM25 precision high.


System layer coverage

All 16 designed layers have end-to-end validation (322 workspace tests):

LayerBenchmarkTests
Fact layerMemora / LoCoMo
Causal edges (caused/enabled/prevented)Capability12
Hippocampus spreading activationCapability
SWR consolidation (LTP/LTD/GC)Longitudinal5
Q-value dynamicsLongitudinal3
Novelty entropy triggerLongitudinal3
Sleep-wake cycleLongitudinal1
Meta-edge pattern miningAdvanced3
Co-occurrence HebbianAdvanced3
Intervention query (forward sim)Advanced4
Trace cause chainCapability2
Inhibitory ablationInhibition2
Distill / retrieval / factsMemora / LoCoMo / LME
Compaction survivalCompact
Agent trap-worldAgent
Pipeline e2eMigration / Pipeline2

Build & test

cargo build --release                    # Build binary
cargo test --workspace --no-fail-fast  # Run 322 tests
cargo test --features local-embed     # Run with ONNX embedding tests
cargo clippy --workspace -- -D warnings # Lint

Agent Memory Challenge (AMC/01)

causal-memory enters the Agent Memory Leaderboard first evaluation cycle via an Add/Search integration server — a thin HTTP frontend over the same Memory facade the MCP server runs (BM25 + semantic + entity retrieval, RRF-fused; one store per user_id):

cargo build --release --bin causal-memory-amc
./target/release/causal-memory-amc --db-dir amc_data --port 8787 --write-mode raw
# --write-mode raw (no LLM, platform default) | distill (write-time LLM extraction)
# POST /add (store memory, user_id-isolated) · POST /search (ordered evidence) · GET /health

Docker route: docker build -t causal-memory-amc . && docker run -p 8787:8787 -v amc-data:/data causal-memory-amc. Submission details, method description, and the participation checklist live in docs/benchmarks/amc-2026.md.

Test suite breakdown:

  • 186 library unit tests (types, store, distill, patterns, hippocampus)
  • 45 library integration tests (capability, longitudinal, advanced, pipeline)
  • 91 CLI, benchmark-harness & MCP e2e tests

Research background

Full documentation map: docs/README.md — design docs, benchmark protocols, evaluation reports, paper drafts, and the literature survey.

This project is the engineering output of 17 research notes on agent memory architecture (insights/01-17), a teardown of 7 production agent frameworks, and deep analysis of 10+ memory research papers. Key references:

  • HeLa-Mem (ACL 2026) — Hebbian spreading activation (our closest competitor; we add the inhibitory side)
  • Anthropic Dreams API — immutable consolidation pattern (aligned in SWR 2.0)
  • mem0 — write-time gatekeeping architecture (adopted: session_logs separation)
  • MemRL (arXiv:2601.03192) — Q-value memory dynamics (implemented)
  • Graph World Models — causal-memory maps to "Graph as Reasoner"

Status

v0.9.0 — alpha.

What works (16/16 layers with end-to-end validation):

  • ✅ 14 MCP tools (stdio + HTTP transport)
  • ✅ Write-time gatekeeping (session_logs separation, V3 distill prompt)
  • ✅ BM25 + semantic RRF unified retrieval
  • ✅ Hippocampus engine: CSR spreading activation, DG SimHash, CA1 novelty, SWR 2.0
  • ✅ 7 edge types: caused/enabled/prevented/fact/meta/co_occurrence/no_effect
  • ✅ Causal distill: extracts typed causal edges (caused/enabled/prevented) from conversations
  • ✅ Hebbian co-occurrence reinforcement
  • ✅ Q-value Bellman dynamics
  • ✅ Novelty-entropy consolidation trigger + sleep-wake cycle
  • ✅ Meta-edge cross-session pattern mining
  • ✅ Forward simulation (intervention_query) with prevented-edge warnings
  • ✅ Benchmark harnesses: LoCoMo, LongMemEval, Memora, CausalEval, compaction, agent ablation, capability, longitudinal, advanced
  • ✅ C7 LLM update-resolver (resolve-updates CLI + sleep stage 1.7 supersession)
  • ✅ Vela-style half-life decay tiers (90d / 7d / legacy 0.99-per-day)
  • ✅ Multi-session multi-pass retrieval (LongMemEval multi-session 42.9% → 57.9%, same-codebase)
  • ✅ PyO3 Python bindings (crates/causal-memory-py)
  • ✅ DSH native plugin (dsh-plugin/) + architecture visualization (docs/architecture.html)
  • ✅ 368/368 tests passing + clippy clean

What's not done yet:

  • ❌ TS bindings
  • ❌ Forward-simulation prediction-accuracy benchmark (designed, not yet run)
  • ❌ 7×24 production deployment validation

License

Apache-2.0. See LICENSE.