My Agent's Memory File Wasn't Wrong. It Was Just Six Weeks Stale.
I built a cross-session memory system for my agent a few weeks back - four markdown files it reads before doing anything non-trivial: bugs.md for known issues and their fixes, decisions.md for why things were built the way they were, key_facts.md for usernames, endpoints, scopes, run commands, and issues.md as a work log.
It fixed the thing I built it for: the agent used to forget everything between sessions and re-litigate decisions I'd already made. Problem solved.
Then last week I asked it to set up a GitHub token for a new OSS contribution, and it confidently told me: "scopes needed: repo, user - add delete_repo if you'll be deleting repos." Straight from key_facts.md. Completely accurate quote. Also missing a scope, because three weeks earlier I'd hit a wall pushing a branch to a stale fork - GitHub rejected the push because the branch dragged in upstream's .github/workflows/*.yml changes, and OAuth apps need an explicit workflow scope to touch those. I fixed it, wrote it up in bugs.md the same day, and never went back to update the one-line scope summary in key_facts.md.
The agent wasn't hallucinating. It was citing a real file, accurately, that had quietly stopped being complete. That's a different failure than "the agent forgot." Forgetting, you can at least detect - the agent says "I don't know" or asks. This is worse: the agent says something true-shaped, sourced, and stale, with the exact same confidence it would use for something current.
There's a trending thread on here this week calling this "the citation that lied without lying" - a system with a real memory gate that still misleads you, not through fabrication but through drift. I don't love that I have a live example of it in my own repo, but I do.
Why it happened
My memory system has four files with different jobs, and I never built anything that keeps them in sync with each other:
bugs.md- narrative, one entry per incident, datedkey_facts.md- reference, meant to be the current-state summarydecisions.md- ADRs, append-only by design (that's correct for decisions, wrong for facts)issues.md- work log
The workflow-scope incident got written into bugs.md because that's where CLAUDE.md's protocol says errors go ("encountering an error โ search bugs.md first"). But nothing in that protocol says "if the fix changes a fact that's summarized elsewhere, go update the summary too." bugs.md is append-only history; key_facts.md is supposed to be current truth. I'd built the append-only log correctly and never built the sync step, so the two files silently disagreed and nothing surfaced that.
key_facts.md (2026-06-21, never touched since):
Token scopes needed:
repo,user- adddelete_repoif...
bugs.md (2026-06-23):
GitHub Token Missing
workflowScope (fork push/sync blocked)...token lacks the
workflowOAuth scope...
Two files, two true statements at the time each was written, one of them silently downstream of the other and never corrected.
The actual fix
I didn't build tooling for this - a markdown-diffing sync bot felt like solving a two-person problem with infrastructure. I just closed the specific gap and adjusted the habit:
- Token scopes needed:
repo,user- adddelete_repoif repo deletion via API is required - Token scopes needed:
repo,user- adddelete_repoif repo deletion via API is required, addworkflowif you'll ever push a branch that pulls in upstream.github/workflows/*.ymlchanges (fork OSS contributions) - seebugs.md2026-06-23
And the protocol change, which matters more than the one-line fix: when a bugs.md entry corrects a fact that's also summarized in key_facts.md, the key_facts.md line gets updated in the same sitting, not "later." Not because I don't trust myself to remember - the whole point of this system is that I don't have to remember - but because the summary file is the one the agent reads first and treats as authoritative. If the correction only lives in the narrative log, it only helps someone who reads sequentially through incident history before doing the task, which nobody does. The reference file is where staleness actually costs you, because it's the one place designed to be read instead of the raw history.
What I'd tell someone building a similar system
If you're giving your agent a memory file - project notes, a wiki, a CLAUDE.md, whatever - split it mentally into two categories and treat them differently:
- Append-only, narrative, dated (incident logs, ADRs, work logs). These are allowed to go stale in the sense that old entries stay true forever - they're a record of what happened, not a claim about right now.
- Current-state summaries (scope lists, endpoint tables, "how to run this"). These have an implicit "as of now" attached to every line, and nothing enforces that the "now" is actually now.
The failure mode isn't in category one - nobody's confused by an old bug report having an old date on it. It's category two, because a summary file reads with the same confident, timeless tone whether it was updated yesterday or six weeks ago, and there's no visual difference between "still true" and "was true."
If your agent treats a stale summary line exactly the same as a fresh one - same font, same certainty, same lack of a timestamp in the sentence itself - you've built a system that can mislead you while being completely honest about everything it's ever said.
The fix isn't more memory. It's making the summary file's freshness someone's explicit job, the same sitting as the fix that invalidated it.
Comments
No comments yet. Start the discussion.