Daily paper · Monday, September 21

Agent memory is infrastructure: health-gate it, heartbeat it, and let it stay silent

cs.SE · Helwig · arXiv:2609.05510

One person ran a Claude Code session line for eight months on a 633,000-line codebase and found that agent memory fails like infrastructure: quietly, and in two directions at once. A session-start health gate, per-hook heartbeats, and injection that defaults to silence recorded all 85 failures, and in a ten-day window fired zero false injections.

The problem

A coding-agent session used to last one afternoon. This paper describes a much longer one: one person, one codebase, and one continuous Claude Code session line that has run since January 2026. The codebase holds 633,446 lines. The session crosses a context compaction, the step where the harness summarizes old conversation to free space, about 90 times in two months.

At this scale, the author argues, the failures that matter are memory failures, of four kinds. Knowledge loss: compaction keeps the plan but drops the reason for it. Repeated work: early in the project, three consecutive sessions each proposed to build a subsystem that already existed, while its design documents were in context every time. Context degradation: injecting more retrieved text into every prompt trains both the human and the agent to skip the injected block. Silent memory death: the index, the embedding server, or the hook pipeline stops working, and nobody notices because nothing crashes.

The fourth failure hides the other three. So the author's central claim is that persistent agent memory is infrastructure. It needs what a production service gets: health checks, heartbeats, freshness targets, and a budget for how often it may alarm.

The harness

The system, SIx Harness, is open source (MIT) and installs into a Claude Code project with one command. It has five parts.

A plain memory store. Each project gets one SQLite file with a keyword index (BM25) and a vector table. Ingesters feed it from docs, memory files, ledgers, transcripts, and git history. A local Ollama server makes the embeddings. Two contracts matter. If the embedding server fails, search falls back to keyword-only, writes one log line, and never blocks a hook. If a vector has the wrong width for the index, the store refuses it. That turns a silent corruption into a visible fault.

Anti-recurrence stores. At session end, an extraction pass proposes candidate decisions and dead-ends from the transcript. Of 154 captured decisions and 186 dead-ends, only 59 and 47 survived. The high reject rate is intentional: a store that accepts everything becomes the noise channel of the third failure, context degradation.

Precision-gated injection. On every prompt, a chain of cheap checks decides whether to inject anything. An intent gate runs first: only prompts that show build, investigate, or decide intent trigger any retrieval. A relevance gate runs next: a memory item must share rare words with the prompt, scored by inverse document frequency, so common vocabulary cannot trigger it. A per-session cap stops repeats. A system-turn exemption skips machine-generated prompts, such as subagent completion callbacks. What passes is injected as one of three blocks: a DO-NOT-REBUILD warning that names the existing subsystem, a stale-claim warning, or a decision lineage (the history of a past decision). No model decides when memory may take the reader's attention.

Per-prompt injection gate chain: a prompt must pass an intent gate, a relevance gate, a per-session cap, and a system-turn exemption before one memory block is injected. If any gate says no, nothing is injected, which is the default. Prompt Intent gate build, investigate, or decide? Relevance gate shares rare words with the prompt? Per-session cap not a repeat this session? System-turn exemption not a machine- generated turn? nononono Nothing injected (the default) Inject one block DO-NOT-REBUILD stale-claim warning decision lineage
The per-prompt gate chain. A prompt must pass all four checks before one of three blocks is injected. If any check says no, nothing is injected. Silence is the default.

The reliability layer. This is the main proposal. At every session start, a health gate runs eleven checks and prints one line: MEMORY-HEALTH: 11/11 GREEN, or the name of what is broken and how to fix it. The checks cover ingest freshness, vector coverage, heartbeats, index integrity, and an embedding probe that tells apart "server unreachable", "model missing", "cold load", and "wedged", because each needs a different fix. Every hook invocation writes a success-or-failure row before it does its work. A hook that stops firing therefore shows up as a missing row, which the next gate run turns into RED. The gate follows the site-reliability rule that every alarm must be actionable. A cold embedding server gets one warm-up retry and reports GREEN with a note. An integration that was never configured is not RED. A misconfiguration is caught when it is configured, not months later.

Session lifecycle of the harness: at session start a health gate runs eleven checks and prints one line; on every prompt the gate chain injects one block or stays silent; at session end an extraction pass proposes decisions and dead-ends and triage keeps a few. Underneath, every hook writes a success-or-failure row before it does its work, and a missing row turns the next health gate RED. Session start Every prompt Session end Health gate runs 11 checks and prints one line: MEMORY-HEALTH: 11/11 GREEN or what is broken, and the fix Gate chain decides: inject one block, or stay silent (the default) Extraction pass proposes decisions and dead-ends; triage keeps a few 154 to 59, and 186 to 47 Every hook writes a success-or-failure row before it does its work. A missing row turns the next health gate RED.
One session, three moments. At session start the health gate prints its one line. On every prompt the gate chain injects one block or stays silent. At session end the extraction pass proposes decisions and dead-ends, and triage keeps a few. Every hook writes its heartbeat row first, so a hook that stops firing shows up as an absence.

Conventions shipped as files. Some continuity only survives compaction as a file the workflow must revisit: an index with one line per memory and a resume anchor (where to pick up), read first after every compaction; invariant files re-read at each work boundary; append-only ledgers; and a constitution of standing rules. One rule resolves what the author calls the two-directions problem. Memory fails toward rediscovery (what exists is ignored) and toward decay (what is recorded is wrong), and the fixes for the two are opposed. So the constitution sets a hierarchy of ground truth, shown below, from running code and live terminal output at the top down to the model's training knowledge. Top-tier facts must be used without re-derivation. Claims from memory must be verified before the agent builds on them.

The ground-truth hierarchy from the constitution: running code and live terminal output outrank facts derived this session, which outrank documents and memory, which outrank the model's training knowledge. Top-tier facts must be used without re-derivation. Claims from memory must be verified before the agent builds on them. Running code and live terminal output Facts derived this session Documents and memory The model's training knowledge outranks outranks outranks Obligation: use it as it is. Do not re-derive it. Obligation: verify it first. Then build on it.
The hierarchy of ground truth in the constitution. Each tier outranks the one below it. Top-tier facts must be used without re-derivation. Claims from memory must be verified before the agent builds on them.

Results

The reliability layer started running on 2 July 2026. Through 30 August it recorded 78,933 hook invocations. Eighty-five failed: 84 in the first three weeks, one on 10 August, none in the final 20 days. The failures fall into four families, and a structural fix ended each one: text-encoding errors, SQLite faults from an unbounded query, aborts from writing to a closed output pipe, and parse errors from control characters. Four duplicate-chunk collisions stopped on their own; the author records those as luck, not maturation.

A ten-day window from 19 to 28 August added full injection telemetry. Every prompt wrote a row, so the denominator is complete. Of 68 prompts, 14 carried intent. Three injections fired on real-use turns, and the author judged all three on topic, although two of them reached no reader (the third incident below). Zero fired on the 54 non-intent prompts. Median retrieval latency was 0 ms because most prompts triggered no retrieval. Before the gates, the stale-claim block had fired on about four in five intent-bearing prompts, so the same window would have produced about eleven noise firings.

Three incidents show what the instruments caught. On the first day of the window, hook wall time (elapsed real time) was 11.3 seconds against a 3-second budget. The client resolved localhost to IPv6 while the server listened on IPv4 only, and a mismatched warm-up probe made the server reload the model twice per hook. The fix brought the time to 1.6 seconds; the kit's 580 offline tests could not have caught either fault. In the second incident, a fallback embedding model produced 768-wide vectors against a 1,024-wide index. The guard rejected it every time, so the fallback only added an 18-second model load to every failure path. The fix was a circuit breaker and a configuration-time check. In the third, two of the three real-use injections had fired on machine-generated turns that nobody would read. The fix was the system-turn exemption.

The author states the limits plainly. This is one project, one operator, one agent, one stack, with no control arm (no comparison run). The labels "relevant" and "intent-bearing" are the author's own judgment. The precision window carried about one sixth of the average load. The agent the system serves helped produce the record, and the harness's own cost in triage minutes and injected tokens was not measured. And the quantity that matters most, rediscoveries prevented, is a counterfactual: observation cannot count what did not happen. So the author published a pre-registered ablation protocol (an experiment plan fixed in advance): 14 days with injection off, and 14 days with the gate off, with the telemetry still running.

What you can do with it

If you run long-lived agent sessions with hooks, memory files, or a retrieval layer, the paper's seven principles work as a checklist. Print a one-line health verdict for memory at session start. Write a heartbeat row for every hook before it does work, so "did it stop firing?" is a query, not a recollection. Default injection to silence, and gate on intent and rare-word overlap first. Make every alarm actionable. Put a ground-truth hierarchy in the agent's standing rules, with opposite obligations for fresh facts and old records. Keep continuity in files the workflow must re-read, not in habits. The kit, its tests, and the ablation protocol are on GitHub, so anyone can run the experiment the author could not.