One night we typed in a goal we had already typed three sessions earlier.
For weeks it had gone this way. We would tell our agent to remember a goal, an idea, a preference. It would say it saved it. The next session it acted like the conversation never happened. We would repeat ourselves, it would save again, and the loop kept going. We tried the obvious things first. We restarted sessions, re-pasted the same facts, even reworded them in case the phrasing was the problem. None of it stuck, and we had started to assume this was just what long-running AI was: confident in the moment, blank the next day.
The cause was not a flaky model. The memory file was correct on disk and wrong in practice.
What the file had been telling us
Our setup gives the agent, Claude Code in our case, a persistent memory: a plain text file it reads at the start of every session and appends to as it learns things about the work. The file’s own header had described the problem the whole time:
# Memory index (always-loaded)Only the first 200 lines / 25KB of this file load each session;past that, entries silently drop.We had scrolled past that line a hundred times without registering it as a boundary that applied to us. The harness loads the first 200 lines, or 25KB, whichever comes first, and no more. Everything past that point never reaches the model. No error. No warning we noticed. And because new memories were appended to the end, the newest things we saved were exactly the ones dropping off the edge. The agent was not ignoring our goals. It could not see them. From its side they had never been written.
That is the failure worth naming. It was not a crash.
Splitting the store in two
The fix was to stop asking one file to do two jobs. Being always present and being fetched when relevant are different jobs, and putting both in one growing file is what broke. So we split the store into two tiers.
The first is an always-loaded policy: the core rules and the handful of high-frequency facts, held under the load budget with real headroom. We keep it under 180 lines, comfortably below the 200-line wall, and a check enforces that. The second tier is a lookup catalog, the complete record of everything we have ever asked it to remember (ours is past 250 entries). It is never auto-loaded, so its raw size does not matter. The agent reaches into it when a topic actually comes up.
Making the silent failure loud
The guard is a short script that counts the always-loaded file’s lines and bytes and checks them against the cap. It exits non-zero if the file is over budget, or if a stored memory exists that nothing in the catalog points to, the kind of orphan you would otherwise only find by luck. An invisible degradation now stops us before a session even starts.
Every byte you hand a model competes for a fixed budget, and that boundary is usually enforced without notice: truncation, summarization, eviction, rarely with a stack trace and never in the file you are looking at. “It is saved” and “it is loaded” are two different claims, and the space between them is where weeks of our frustration had been hiding. On-disk completeness told us nothing about what the model was reading, and we had trusted the wrong one.
We spent those weeks blaming the model for being forgetful. We had built it a memory it was structurally unable to read past line 200.
If your AI tool has a persistent memory, find out its load limit and what happens to anything past it. In our case the cap was 200 lines or 25KB, and entries past it dropped without any error. Put a check in place that fails loudly when the always-loaded memory goes over budget, because a saved memory the model never reads does the same damage as one that was never saved.