the memory firewall for AI coding agents

Your agent's memory
is lying to you.
Prove yours isn't.

Self-custodied, cross-tool memory that ties every fact to your repo. Memory whose source no longer checks out is blocked before it reaches the model - and what passes is labeled for exactly what it is. One command wires every agent you use.

$ npm install -g memwarden && memwarden up
1command wires
every tool
6agents with native hooks
one shared brain
0known-stale memories
reach the model
0cloud · self-custodied
lives at ~/.memwarden

The problem isn't forgetting. It's confidently wrong recall.

A stored fact silently goes stale - it points at code you've since changed or deleted - and the agent injects it with full confidence anyway. OWASP added Memory Poisoning (ASI06) to its 2026 Agentic Top 10. Most memory still stores everything and trusts everything. A memory that points at code you deleted is worse than none. memwarden flips the default: memory is untrusted until its source still checks out.

🩺

Verified Recall - the anti-feature

Memory is firewalled before it reaches a model. Stale memory is never injected. memwarden doctor runs the same check as a red/yellow/green audit against any existing store. Point it at your own memory and watch it light up yellow.

🪂

Self-custodied & portable

Your second brain shouldn't depend on a vendor's roadmap. memwarden is local-first, tamper-evident, and portable: one export produces a Brain Bundle you can move between machines or agents. Zero cloud - the data lives at ~/.memwarden and nowhere else.

🧱

The memory firewall

Memory whose provenance stopped checking out is dropped before it reaches the model; what passes is labeled verified / sourced / unsourced, never laundered into one pile. The unique lever - possible only for a coding tool because the repo is ground truth - is tying memory validity to source-file content hashes.

Verified Recall - four states, one firewall

Every memory is classified against the live repo before it can reach a model. memory_resume, the recall prompt, the Claude Code SessionStart hook, and the proxy all run with the firewall on. It blocks stale before injecting. It does not block unsourced - unsourced means unverified, not dangerous, so it stays available for explicit lookups. What passes is firewall-passing, trust-labeled memory - never laundered into one "verified" pile.

verified

A captured source-file hash still matches the file on disk - code-backed and current. This is the only label reserved for content-hash-confirmed memory. Auto-injected.

sourced

Has a source (a command, or files present but not hashable) but no content hash to re-check. Allowed, labeled, not content-verified.

stale → blocked

A referenced file was deleted, or its content changed since capture. Never injected into the model.

unsourced

No evidence trail. Kept for explicit lookups, labeled so the agent knows it is unverified - never silently promoted.

Two policies: balanced (default) blocks stale and keeps the rest - sourced and unsourced - each labeled; verified-only raises the floor so only hash-verified memory is ever auto-injected. memwarden why <id> explains one memory; doctor --fix-stale clears the stale inbox. No LLM, no fuzzy black box.

$ memwarden doctor .

  VERIFIED:   8 memories (code-backed, current)
  SOURCED:    3 memories (sourced, not content-verified)
  STALE:      2 memories reference files that changed/deleted
  UNSOURCED:  1 memory has no evidence

  [stale] Edit (obs_…) - references files that no longer match (changed: src/legacy.ts)

Déjà Fix - never solve the same error twice

memwarden is the one process that sees every agent's sessions, so it can do what no per-tool memory can: when any agent resolves an error, it captures {error signature → root cause + fix} with provenance file-hashes. When any agent later hits a matching error, the fix is surfaced automatically — but only if its files still hash-match. A stale fix is never surfaced.

# Codex solved a failing test yesterday. Today Claude Code hits the same failure:
Déjà Fix (memwarden): a prior session resolved this error and the fix
is verified current against your working tree.
  solved by: codex · root cause: clock skew · fix: mock NTP in conftest

# scriptable too - pipe a failing command's output straight in:
npm test 2>&1 | npx memwarden dejafix lookup

Cross-agent (a fix learned in Codex helps Claude Code), project-scoped (a fix never leaks across repos), and safe by construction - it reuses Verified Recall, so file drift or deletion auto-suppresses it. Only verified current fixes auto-inject.

Source-file hashes: the ground truth

A coding agent has something general-purpose memory doesn't: the repository on disk is the source of truth. When memwarden captures a code-backed memory it records a SHA-256 content hash for each referenced file. On recall it re-hashes the live file and compares. If the file moved or vanished, the memory is provably stale - not by heuristic, by hash.

🔗

Tamper-evident, honestly

Every write lands in an append-only SHA-256 hash-chained oplog. memory_verify recomputes the chain, so an edit or reorder of any past entry breaks it. Tamper-evident, not tamper-proof: no signing, and the chain does not detect tail-truncation.

🧾

Erasure with receipts

forget <id> returns an offline-checkable delete receipt. forget --erase nulls payloads and re-chains; compact reclaims bytes so content leaves the file. A post-erase residual scan refuses to claim contentErased while a copy survives.

🔒

Self-custodied

The brain lives at ~/.memwarden and nowhere else. On-device embeddings, two runtime dependencies, no cloud, no vendor in the loop. Once it is up you never touch it - self-healing on crash and at login.

Setup is one command

memwarden up starts a self-healing daemon (one global brain at ~/.memwarden), installs the on-device embedding runtime so recall is semantic from day one, and wires hooks + MCP into every installed tool - in that tool's own config schema, without clobbering anything you already have. No keys to paste, no cloud, no config files to hand-edit.

$ memwarden up
  daemon     http://localhost:3111   brain: ~/.memwarden
  semantic   local embeddings ready (all-MiniLM-L6-v2 - on-device)
   Claude Code   MCP + hooks - auto inject + auto capture
   Codex         MCP + hooks (run /hooks once to trust)
   Cursor        MCP + hooks
   Gemini CLI    hooks
   Kiro          MCP + hooks (per custom agent)
   OpenCode      MCP + plugin

  Done. Every agent on this machine now shares one verified brain.

Then prove it's flowing, per tool - detected (installed), configured (MCP + hooks on disk), live (a hook from that host actually reached the daemon). Wired-but-never-live is the failure every other memory layer hides; here it's a column in memwarden status.

How memory crosses your tools

Cross-tool reach is table stakes - the trust layer is the point. Still, the mechanics matter, so here they are honestly, with no "native hooks everywhere" hand-waving. There are three ways memory reaches a tool, and up wires whichever each supports.

Path 1 · automatic

Native lifecycle hooks

Claude Code, Codex, Cursor, Gemini CLI, Kiro and OpenCode get real hooks in their own config format: session-start injects this project's firewall-passing memory before you type; capture happens as tools run. The agent cannot forget - there's no instruction to follow.

mechanical
Path 2 · automatic

The proxy

Point a tool's model base URL at the memwarden proxy on :3141 and every turn is recalled and captured with no agent cooperation. On a secured install the tool's API key is your memwarden secret, so nothing else can spend your upstream key. Works where you control the endpoint: Ollama, LM Studio, custom OpenAI base URLs.

mechanical
Path 3 · manual MCP

MCP + AGENTS.md

Tools without a hook surface (Antigravity, OpenClaw) still get the MCP server - ask the agent to call memory_resume - plus an AGENTS.md instruction as a soft fallback. Explicitly the fallback, not the mechanism.

agent-driven
ToolCapture / recallExplicit recall
Claude Codeautomatic (hooks)/mcp__memwarden__recall
Cursorautomatic (hooks)call memory_resume
Gemini CLIautomatic (hooks)call memory_resume
Codexautomatic (after /hooks)call memory_resume
Kirobest-effort (per agent)call memory_resume
OpenCodebest-effort (plugin)call memory_resume
Antigravity · OpenClawmanual (MCP only)call memory_resume
Ollama · LM Studio · any OpenAI URLautomatic (proxy)n/a - automatic

How it works

Capture compresses on-device, redacts, and hashes into the store down the left; recall scopes, searches, classifies, and frames firewall-passing memory back up the right. Scoping is by canonical path, so recall never silently misses.

Your agents Claude Code · Codex · Cursor · Gemini CLI · Kiro · OpenCode Hooks · MCP · Proxy firewall-passing memory memwarden daemon ~/.memwarden · one brain, self-healing CAPTURE RECALL recall policy + framing Compress on-device, no LLM Redact private data secrets stripped before storage Hash referenced files SHA-256 provenance Project scoping canonical path - never silently misses Hybrid search · BM25 + vector RRF, TurboQuant / native turbovec Provenance classifier verified · sourced · stale · unsourced libSQL store hash-chained oplog (tamper-evident) · BM25 + vector index
Kubesimplify diagram by Kubesimplify

Measured, not claimed

The launch claim is a memory firewall, so the first number is the firewall itself - not retrieval. A deterministic corpus of 250 memories (file-backed, command-sourced, and unsourced) across 5 projects with 50 controlled staleness events, 5 poisoned-handoff traps, and 5 delimiter forgeries. Reproduce with npm run eval (CI-gated at 100% on all eight gates).

Firewall evalResult
Stale retrievable - each stale memory first proven retrievable unfiltered (so "blocked" measures work, not absence)100%
Stale refusal - known-stale memories blocked under safe_only100%
Fresh retention - verified-current memories not wrongly blocked100%
Project isolation - out-of-project results under scoping0 leaks
Label accuracy - labels match ground truth across all three classes100%
Handoff traps - hostile prompts beside fresh file hashes never laundered to verified0 laundered
Verified-only policy - sourced/unsourced/handoff refused; verified still flows100%
Injection containment - forged delimiters can't escape the untrusted-data block on any surface100%

Retrieval next. Real on-device model (all-MiniLM-L6-v2), 30 labelled memories buried in 2,000 plausible distractors, 14 paraphrased queries, and the compressed index running with no exact rescoring. Reproduce with npm run benchmark.

Retrieval - gold answer in top-kR@1R@5R@10
Full-precision vectors57%79%86%
TurboQuant (4-bit, no rescore)57%79%86%
Keyword search (lexical baseline)7%57%57%

And the engine: an optional native Rust backend built on turbovec (Google's TurboQuant algorithm - real IdMapIndex, O(1) deletion, allowlist filtering inside the SIMD kernel). Measured at 10,000 × 384-dim vectors.

Vector backendrecall@10 vs FP32search p50 / p95bytes / vector
typescript/full (baseline)100%14.96 / 16.21 ms1536
typescript/turboquant-4bit100%18.90 / 19.53 ms260
turbovec/native-4bit100%0.15 / 0.20 ms196

~125× faster search, zero recall drop. Honest defaults: the native backend is quietly selected when its prebuilt binary loads (pin with MEMWARDEN_VECTOR_BACKEND), and memwarden status always names the backend actually serving - a native backend that failed to load reports its TypeScript fallback, never a silent claim. 602 tests across the Verified Recall suite, Déjà Fix, HTTP security, per-host hook dialects, and a cross-tool reliability harness.

MCP tools & the recall command

ToolWhat it does
memory_resumeVerified recall of this project across all past sessions and tools
memory_searchHybrid semantic + keyword search (unfiltered, for explicit lookups)
memory_rememberSave a memory explicitly
memory_verifyConfirm the oplog hash chain is intact (tamper-evident; not signed)
memory_statsLive counts, compression ratio, token reduction, latency

Plus the recall MCP prompt, surfaced in Claude Code as /mcp__memwarden__recall <query>. On other MCP hosts, ask the agent to call memory_resume; where hooks are automatic, recall arrives on its own at session start.

Start where you are

Audit the memory you already have - zero install, read-only - then wire every tool with one command.

$ npx memwarden audit ~/.claude-mem/claude-mem.db --root ~/code/my-repo