DEV Community

Youfu Hsu
Youfu Hsu

Posted on

Giving an AI agent memory is easy. Keeping it true is the hard part.

Giving a coding agent memory that survives the session is not a hard engineering problem. A directory of markdown files outside any repo, one fact per file, an index that gets loaded at the start of every session. That is the whole mechanism, and it takes an afternoon.

I have been running one for about four months across roughly forty projects. The mechanism has never been the problem. In a single working day last week, four separate memory entries turned out to be confidently wrong, and each one had been steering decisions for weeks.

The four

"Schema fix committed locally, not yet pushed." Read as: there is unpushed work sitting on this machine. Actually: that repo has no remote at all and never did. The deploy path was a script hitting the platform's API directly, so nothing was ever supposed to be pushed. The entry had turned a fact about one repo's setup into a phantom to-do that survived several audits.

"Template fatigue in the post generator: fixed and deployed." Green checkmark, verification notes, an A/B comparison in the file. All true. The fix was deployed to a queue worker whose last log line was from six weeks earlier and which had no scheduled task pointing at it. The pipeline that actually posts every morning is a different script that never imports the fixed module. The fix was real, verified, deployed, and had zero effect on anything anyone could see.

"600 platform credits banked, use before November." Actually the credits had already been converted into a different resource with a 30-day expiry, and the deadline was five weeks earlier than the memory claimed. The entry was written on the day of purchase and described the plan, not the outcome.

"Two recordings missed last night." Written by an automated job that judged success from a process exit code. The recordings were on disk, complete, and had already been transcribed. The exit code was a red herring from a downloader that returns non-zero while cleaning up after a perfectly good capture.

Different projects, different weeks, one shape.

What they have in common

None of these were sloppy notes. They were all written carefully, at the moment of the work, by someone (or something) with full context.

Every one of them recorded a judgment and formatted it as a fact.

"Not yet pushed" is an inference from "I did not push." "Fixed and deployed" is an inference from "the deploy script exited zero." "Missed" is an inference from "exit code was 1." The inference was reasonable when it was written. The problem is that once it is a line in a file, the reasoning is gone and only the conclusion is left — and conclusions do not carry their own expiry date.

This gets worse specifically because the memory works. An agent that reads its memory and acts on it is doing the right thing. A wrong entry does not cause an error; it causes confident, efficient work in the wrong direction. My agent spent weeks not investigating the post generator, because the file said it was fixed.

What actually helps

Write the re-check, not just the claim

Any entry that asserts a state — done, fixed, deployed, live, expired — should carry the command that re-establishes it:

✅ Subtitle pipeline deployed and verified 08-18.
Re-check: `grep "card1:" <log> | tail -3` — openers should not
all share one skeleton. If they do, the fix is not on the live path.
Enter fullscreen mode Exit fullscreen mode

Now the claim is falsifiable by anyone who reads it, including a future session with no context. Half of my four would have been caught in seconds by their own re-check line.

Distinguish observed from inferred

I now try to write what was seen, and separately what it was taken to mean:

Observed: deploy script exit 0, target file contains the new function.
Inferred: the fix is live.   ← this is the part that can rot
Enter fullscreen mode Exit fullscreen mode

The inference is usually still right. But when something later contradicts the memory, you know which half to attack first.

Let files outrank memory

When memory and the filesystem disagree, the filesystem wins. This is worth writing as code rather than as a habit. Correcting that "two recordings missed" entry was six lines:

for slug, rec in state.items():
    # source of truth is the artifact, not what the job concluded at the time
    if os.path.exists(f"{WORK}/{slug}/summary.md") and not rec.get("done"):
        state[slug] = {**rec, "done": True,
                       "note": "corrected: exit code misjudged; output is complete"}
Enter fullscreen mode Exit fullscreen mode

Note what it does not do: regenerate the state file from scratch. It patches only the rows contradicted by evidence and leaves everything else alone. I have destroyed hand-maintained data by "regenerating" it from rules before, and that is a genuinely bad afternoon.

Verify from outside the system that made the claim

The strongest habit of the four. A deploy script reporting success is the deploy script's opinion. Ask something that has no stake in the answer.

This cuts both ways, and the false negative is the one that wastes your time. On the same day I fixed the four entries above, I updated 23 listings on a platform, got 23 success responses back, then checked the public search index and saw zero of the changes. Looked exactly like "claimed success, not actually live." It was a caching layer on the search endpoint; the per-item public endpoint had all 23 updates with the correct timestamp.

So: verify externally, but when the external check disagrees, suspect the checker before you rip out the work. The rule is not "the external check is right." It is "one source is never enough."

The part I did not expect

I assumed the risk of agent memory was the model hallucinating something into a file. Four months in, that has not happened once. Everything in my memory directory was written from real work.

The risk is decay. Every entry is a snapshot of a moment, and the world keeps going. A memory system does not fail by filling with lies. It fails by filling with things that were carefully, honestly true in July.

Which means the maintenance job is not "keep the notes tidy." It is: for anything currently steering a decision, go look again.


I write about running unattended automation and AI agents in production, including the parts where the agent — or I — confidently get it wrong. The full system I use for this is the Claude Code Automation Playbook.

Top comments (1)

Collapse
 
glenallen profile image
Glen Allen

The distinction between “wrong memory” and “stale memory” is a really important one. An entry can be completely accurate when it is written and still become dangerous later when an agent treats it as current state. I especially like the idea of storing a re-check alongside the claim — it turns memory from a static note into something that can be challenged by evidence. That feels like a much more reliable pattern for long-running agents.