A memory system for coding agents

Most coding-agent memory systems fail by remembering too much, not too little. The one I run on a client fintech codebase works because writing is gated: a memory earns a slot only by passing four rules and an adversarial five-challenge review, and lessons must be re-validated across sessions before they’re promoted into standing instructions.

Agent memory fails by writing too much

Claude Code gives each project a persistent memory directory whose index is loaded into every session, and the default failure mode is hoarding, not forgetting. Left to its own judgement, an agent saves session summaries, research notes, TODO state, and the status of work that has since merged — all of it either derivable from the repository or perishable within weeks. Derivable facts go stale the moment the code moves, and every stale entry is a false statement injected into every future session. The index doesn’t degrade because it’s too small; it degrades because it’s polluted, and the agent has no way to know which entries to distrust.

So the design premise of this system is that the scarce resource isn’t storage or recall — it’s trust in what’s already written. Everything below is machinery for protecting that trust at write time.

Four rules a memory must pass

A memory earns a slot only if it is all four of: durable — still true in six months; non-derivable — can’t be reconstructed from the code, the git history, or the ticket tracker; overrides a default — without it the agent would confidently do the wrong thing; and specific enough to act on — it names a file, a command, or a concrete pattern. The index header restates the rules, so every session re-reads them before it can write, and it also names the exclusions: TODOs, research summaries, merged-phase logs, and story status don’t belong — which is to say, the four things agents most like to write down.

The entry that best shows all four rules at work: the client’s Git server enforces commit-message format with a regex anchored so strictly that it rejects the trailing newline git commit -m itself appends — every correctly formatted commit still fails to push. That fact is durable (server hooks change rarely), non-derivable (the hook is invisible from inside the repository), overrides a default (the standard commit command is the trap), and the memory carries the exact newline-free commit incantation. Learning it cost roughly nine failed pushes; re-learning it costs one line of index.

After four months the index holds 35 entries in four categories: one fact about my own access, 7 durable preferences the client team has expressed, 22 active project constraints, and 5 pointers to where non-obvious information lives. Each entry is one file holding one fact; the index carries only a one-line hook per entry, so what loads into context stays under a page.

An adversarial gatekeeper reviews every write

Rules stated in a header are advice; the gatekeeper is the enforcement. Any proposed lesson — a correction from me, a failed verification gate, a pattern noticed in review — is routed through a dedicated command whose job is stated in its first paragraph: reject slop. It runs five challenges, and the lesson must pass all five. Is it true — is there evidence in the codebase now, or is this an inference from a single incident? Inference is an automatic reject. Is it specific — could another engineer act on it without asking what it means? Is it new — a duplicate doesn’t get a second entry; it increments the existing entry’s validation counter. Is it scoped — a one-off mistake that wouldn’t plausibly recur is rejected rather than memorialised. And could it cause harm — a rule that would produce worse outcomes if followed everywhere gets narrowed before it’s written.

What survives is classified by risk: low-risk factual entries are written silently, pattern-level lessons get surfaced in a session-end summary, and anything that would change standing behaviour is flagged to me immediately. The posture throughout is refusal by default — the prompt explicitly names rubber-stamping as the failure to avoid.

The review earns its cost on subtle entries. One lesson records that a subagent’s research summary mis-grouped a design decision under the wrong person’s sign-off, and the false attribution propagated into a committed spec and two downstream documents before a primary source contradicted it. The gatekeepered lesson that came out of the cleanup is a process rule — attribution claims trace to the primary document, never to a summary, and a contradicted summary means re-checking everything written from it.

Lessons are validated across sessions, then promoted

The system has three tiers of confidence. Standing instructions in CLAUDE.md load into every session and are trusted absolutely. Memories are established facts. Lessons sit below both: provisional corrections, each carrying a Sessions validated counter that increments only when a fresh incident confirms the lesson — getting bitten again is treated as evidence, not embarrassment. The clearest example: the client’s “full CI” script turns out not to run the integration suite, and the lesson recording that has been validated by three separate incidents across three months, each one widening its trigger conditions — first for changes touching test infrastructure, later for any edit to DOM structure or accessibility attributes, because those kept breaking integration tests that unit gates can’t see.

Three validations makes a lesson a promotion candidate, tagged with a suggested target section in CLAUDE.md; the promotion itself stays manual, because standing instructions are the highest-trust tier and nothing gets in on the agent’s own say-so. Decay runs the other way: a lesson that sits 60 days without a validation is archived, and memory files untouched for 90 days get flagged for review. Right now the ledger reads: ten active lessons, one promotion candidate, none promoted, none archived.

Four months in: what’s proven and what isn’t

The write-side works, and I can see it in what’s absent: four months of heavy agent use has produced 35 memories and ten lessons, not the hundreds of entries an ungated system accumulates, and I have yet to catch a stale entry misleading a session. The honest limits are on the maintenance side. The monthly audit — the process that would archive stale lessons and flag untouched memories — has never actually run; the audit log is an empty file, so the decay rules are designed but unexercised. Most validation counters still sit at zero, which means one promotion candidate is too small a sample to say whether three is the right threshold. And the whole system is a prompt, not a mechanism: nothing physically stops a session writing to the files directly, so the gate holds only as long as the agent routes through it — the same unverified-instruction problem that made me build a trigger harness for skills.

What I’d keep even if I kept nothing else: the four write-rules. They’re the cheapest component — four tests applied in the moment before writing — and they do most of the work, because agent memory doesn’t usually fail at recall. It fails at the junk drawer, and the fix for a junk drawer is a rule about what goes in.

Revisions

  1. Published.
  2. Created; body written from the memory system's own files.