DEV Community

Cover image for The Three-File System That Fixed Claude Code's Amnesia Across 11 Projects
ZTW
ZTW

Posted on

The Three-File System That Fixed Claude Code's Amnesia Across 11 Projects

I run Claude Code across eleven projects at the same time.

Not eleven files. Eleven separate products, each with its own stack, its own history, and its own set of decisions I made months ago and no longer remember making.

At one project, session amnesia is a papercut. At eleven, it is the job.

This is the structure that finally fixed it. No prompt engineering, no clever wording — just files, and hooks that enforce them.

The problem isn't that CLAUDE.md doesn't work

It works fine. That's what makes the failure so slow to notice.

You write a good CLAUDE.md. The agent reads it. Things improve. So when a new problem appears, you add a section. Then another. Six weeks later the file is 400 lines, half of it is stale project state, and the agent is quietly ignoring the middle of it because the rules are buried under a changelog.

The mistake isn't the length. The mistake is that you put three different kinds of information in one file, and they change at completely different rates.

Split by rate of change, not by topic

Here's the split that fixed it:

Layer File Changes Compressed?
Law CLAUDE.md Rarely, deliberately Never
State PROGRESS.md Every work turn After 24h
Wisdom LESSONS.md When you correct the agent Never

Law is rules. "Always show physical evidence before claiming success." "Never edit .env." These change maybe once a month, when you decide they change.

State is where the project is right now. Current phase, what's in flight, what's verified, what's broken. This churns constantly.

Wisdom is what you learned the hard way. Corrections you issued. Traps that cost you an afternoon. This only ever grows.

Why the separation is the whole trick

Because compression has to happen, and it has to happen selectively.

State churns daily. If you never compress it, every session start re-reads weeks of narrative you'll never need again, and you pay tokens for it on every single project, every single day.

Wisdom is permanent. Compressing it destroys the exact thing you kept it for — a lesson summarized into a hint stops being a lesson.

Put them in one file and there is no setting that works. Compress aggressively and you shred your hard-won lessons. Don't compress and you bleed tokens forever. The only way out is to stop asking one file to do both jobs.

The rule with the best cost-to-value ratio

At the start of every session, before anything else:

Read PROGRESS.md and open with exactly three lines: current phase, what was in progress, what's next.

That's it. Roughly 50 tokens.

It removed more daily friction than anything else I did. Instead of "what were we doing?" followed by three minutes of re-explaining, the session opens with:

1. Phase: auth rewrite
2. In progress: token refresh, 2 tests still red
3. Next: fix the expiry edge case, then ship
Enter fullscreen mode Exit fullscreen mode

The agent knows. You didn't have to tell it.

Don't ask the agent nicely. Use hooks.

This is where most CLAUDE.md setups stop, and it's why they drift.

A rule in a markdown file is a request. The agent usually honors it. Usually is doing a lot of work in that sentence.

Two things I moved from request to enforcement:

1. Secret files. Instead of "please don't edit .env", a PreToolUse hook that denies the write outright:

BLOCKED_PATTERNS = [".env", ".env.*", "*credential*.json",
                    "client_secret*", "*.pem", "*.key", "id_rsa*"]

def is_blocked(basename):
    if any(fnmatch(basename, p) for p in ALLOWED_PATTERNS):
        return False
    return any(fnmatch(basename, p) for p in BLOCKED_PATTERNS)
Enter fullscreen mode Exit fullscreen mode

The agent is good at deciding what code should say. It's bad at deciding what a secret file should say. So I removed the decision entirely.

2. Tests on save. A PostToolUse hook that runs the test suite the instant code changes and feeds failures straight back to the agent. Self-review doesn't catch what an adversarial step catches.

One detail that cost me an afternoon: run the test command from the project root, not from the edited file's directory. Projects with tests/ separate from src/ report "0 tests collected" when the runner starts in the wrong place — and a green zero looks exactly like a pass.

The failure that took longest to notice

This one is worth the whole post.

The agent would diligently update the local progress file, and silently skip the shared knowledge log.

Nothing errors. Nothing looks wrong. You find out weeks later, when you go looking for an answer that should be there and isn't.

Silent gaps are worse than loud failures. A loud failure interrupts you. A silent gap accumulates.

The fix is to treat the two writes as one action, with an explicit self-check before the agent reports anything: did both get written? If either is missing, write it before reporting.

What breaks first, in order

If you're scaling up, this is the order the failures arrive:

  1. Session amnesia (project 1) → wake-up briefing
  2. Cross-project blindness (project 3) → a registry the agent can read
  3. Repeated mistakes (project 4) → a lessons file separate from state
  4. Token bleed (project 8) → compression discipline
  5. Silent write gaps (project 10) → same-turn write pairing

You don't need to solve five before you have one. But knowing the order means you recognize each failure when it shows up, instead of concluding the whole approach doesn't work.

Try the ideas free

Everything above is structural — you can build it yourself in an afternoon with the table and the two hook snippets. That's genuinely the point of the post.

If you'd rather not spend the afternoon, I packaged the whole thing: four document templates, both hooks, a scaffolding script that lays down a project's doc kit in one command, a registry audit script, and the twelve rules each written next to the specific failure that produced it.

Every script ships with a --demo self-check so you can verify it before trusting it with your repo:

$ python hooks/guard_secrets.py --demo
guard_secrets: all checks passed
Enter fullscreen mode Exit fullscreen mode

If you just want the structure, the three templates are free and MIT-licensed:

github.com/wondi81/agent-os-lite

That's the part you should have for nothing — you can rebuild it yourself in an
afternoon once you've seen the shape, so there's no reason to charge for it. What
it doesn't do is enforce anything; markdown asks nicely and an agent can talk
itself out of a request.

The full version is where the hooks live, plus the scaffolding and the registry
audit:

Agent OS — $29 · zero dependencies, 30-day refund.


If you're running Claude Code across multiple projects, I'd genuinely like to hear which of the five failures hit you first. My guess is #3 catches more people than they realize.

Top comments (4)

Collapse
 
hamid_ahmadian_3570449f72 profile image
Hamid Ahmadian •

This resonates a lot — #3 (repeated mistakes) got me too, but for a slightly different reason than pure scale: the agent would happily re-make a mistake I'd already corrected in the same session, because the correction lived in conversation history rather than a file, and history doesn't get reloaded/weighted the way a written rule does. Splitting "wisdom" into its own append-only file the way you describe is the right fix, and I'd guess it works less because of token cost and more because a growing pile of corrections folded into CLAUDE.md demotes the rules around it — they start reading like changelog noise instead of law, which is the same failure mode you called out with CLAUDE.md ballooning to 400 lines.

The silent-gap point (#5) is the sharpest thing here though. It maps to a real limitation in Claude Code's own checkpoint system: /rewind only tracks the Edit/Write tools, not file changes made via Bash — so if an agent updates state through a shell redirect instead of Edit, that write is invisible to your own history the same way it's invisible to a human skimming the diff. Treating "did both files actually get written" as an explicit self-check before reporting done, instead of trusting the agent's own narration of what it did, is exactly the right instinct.

Collapse
 
won_ztw profile image
ZTW •

That /rewind gap is sharp - hadn't put it into words but it explains a specific failure I hit: an agent "fixed" something via a shell redirect instead of Edit, and my own review missed it because I was skimming Edit/Write tool calls in the transcript, not the whole session for file writes.

The check I ended up needing was dumber than a checkpoint system: after any turn claiming "done," run git status --short and only trust what actually shows as modified. Doesn't give you the undo /rewind would, but it catches exactly the case you're describing, since git doesn't care which tool touched the file.

Collapse
 
hamid_ahmadian_3570449f72 profile image
Hamid Ahmadian •

That's a good instinct — git status --short catches the modification regardless of which tool wrote it, which is the part that actually matters. One gap I've hit with it: it tells you something changed but not what, so a shell redirect that silently truncates a file to empty still just shows as "modified" and looks identical to a clean edit until you diff it. I've started pairing it with git diff --stat right after — mostly to catch the "0 insertions, N deletions" shape a truncation leaves behind. Cheap enough to run every turn, and it's caught a couple of cases git status alone made look fine.

Collapse
 
eduzsh profile image
Edu Peralta •

The split by rate of change is the part that finally clicked. Once state and lessons share a file with the durable rules, every compression choice is wrong. Either you shred the lessons or you burn tokens rereading last week's narrative on every session start. The three line opener from PROGRESS.md removes more daily friction than most of the prompt tricks people stack on CLAUDE.md. One thing I'd add: make that session start a hook, not a request, otherwise the agent "usually" does it and you only notice the miss after you've already re-explained the project.