Strategist · Designer · Operator

Launch
with Ben



Claude Code

Claude Code Repeats the Same Mistakes: Memory Won't Fix It

I built the memory file. 121 entries in 18 days, then 55 commits added nothing. Why a repeating agent isn't a storage problem, and the hook that fixed it.


The agent cannot decide to check the doc that would tell it that it is wrong.

Your agent makes the same mistake it made last week, so you reach for memory: a file it writes lessons to, a hook that captures them, something that persists. Anthropic’s own tracker carries the complaint, titled “Claude repeatedly fails to apply its own memory/feedback.”

I built that memory. It works exactly as designed, and it did not stop anything. I can show you the file.

Claude Code already treats your CLAUDE.md as a suggestion. This is a layer below that, because it is about the lessons the agent recorded for itself.

121 entries, then nothing

LEARNED.md lives in uxxray. A lesson gets written the moment it is learned, in its strongest form.

121entries written
164 KBof recorded lessons
18days it took to write them
0added in the 55 commits since

Here is every day it was touched, from git log --format='%ad' --date=short -- LEARNED.md | sort | uniq -c. Each bar is one day’s commits to the file, 107 in total:

The last write landed on 25 August. Every day after it is a working day on the same repo with nothing recorded.

Seven bugs got fixed in those 55 commits. The file did not move.

That is not laziness. Every lesson had a better home and went there instead, which raises the question I had been avoiding: what was the memory file ever for?

The answer was already written down. Twice

Both of these happened in one session, on a repo whose documentation I maintain carefully.

One. The agent hit a caching problem and proposed purging the entire Cloudflare zone. Confident, reasoned, wrong. The answer was already in AGENTS-SOP.md under a heading that could not be more direct: “A CDN Question Starts With cf-cache-status.”

The agent ran that exact header check twenty minutes later, as though deriving it. Then it read the section, and retracted.

Two. It needed one command to regenerate a chain of generated files, so it listed the project’s npm scripts and piped the output through head -20. verify is the 40th of 41, so it sorted below the cut. The agent built a replacement, wrote a test for it, and added a doc section listing six manual commands, contradicting a line already in AGENTS.md: “Do NOT run the individual lints by hand.”

npm run verify had done that job, in that order, since 2026-08-19. Its header comment already explained the reasoning the agent thought it was working out.

Both times the content was correct, current, and in the repo. It was not read at the moment it mattered. Storage was never the problem.

Memory is pull, and pull needs attention

A memory file is a pull mechanism. So is a doc. So is a vector store of past sessions. They share one requirement, and it is the one an agent cannot meet.

What a written lesson needs

All four. The agent notices it might be wrong, decides to go looking, opens the right file, reads the part that matters.

What a gate needs

None. It runs whether or not the agent is having a good day, and whether this is session one or session fifty.

Four things have to happen before a written lesson can change an outcome. A gate needs none of them, which is the whole difference.

Step one is where it dies. An agent about to propose the wrong cache fix has no signal telling it to go read the cache section. It feels informed. It has reasons. The document that would stop it is the one it has no reason to open.

This is not only my experience. Prakhar Khatri’s Do Context Files Help Coding Agents? ran 288 evaluated runs across 17 tasks on Claude Code and Codex and found context strategy “does not measurably move correctness on either agent.” That studies context files rather than memory, so it supports my case without proving it.

So a fifth memory system is a fifth thing nobody consults. When I instrumented a different one to see how often its knowledge even reached the agent mid-edit, the answer was 24.6% of the time.

What actually caught the mistakes

Seven defects surfaced in that session. Not one came from the agent reviewing its own work. Every one was caught by something that fired on its own:

What firedWhat it caught
.githooks/pre-pushA push carrying a stale generated stamp
lint-dead-selectors.mjsTwo CSS rules added “for symmetry” that matched nothing on any page it tests
lint-no-left-border.mjsA coloured border I had banned on 2026-08-19
render-stamp-inputs.test.jsA static import that worked locally and broke in an isolated tree
A UserPromptSubmit hookThe cache rule, again, later that night

That last one is the reason I am writing this.

The hook that fires on your words, not its memory

UserPromptSubmit is one of the four Claude Code hook events, and it runs before Claude reads your message. Most people use it to inject project context. Mine does something narrower: it reads the prompt, matches it against a routing table in AGENTS.md, and prints the matching rows.

Later that night I typed a message containing the word “purge.” Here is what the hook did with it, reproduced by piping a prompt straight into the script:

The router matching the word purge and printing a pointer to the cf-cache-status section of AGENTS-SOP.md, before the agent has read the prompt

It printed that pointer before the agent composed a line. Same rule it had violated an hour earlier, in a session where it had no memory of the mistake at all. The correction did not come from the agent remembering. It came from me typing a word. The script is 153 lines, fail-silent by contract, and walks up to the nearest AGENTS.md, so it works in any repo without configuration.

It is also dumb, and I should say so. Keyword matching misfires. Writing this post, it saw the word “writing” and served me a section about writing gates, which was not what I meant. That cost three lines of context. A missed match cost a purged CDN zone. I will take that trade.

The fix was mostly deletion

The session ended with three changes. The agent deleted the tool it had built, because the existing one was better. It wired the staleness check into the pre-push hook, so it runs whether or not anyone remembers it exists. It removed its own doc section, because that section contradicted a line already there.

The documentation got shorter. One command became mandatory instead of optional. Nothing was memorised.

That same AGENTS-SOP.md section ends with the rule stated plainly: “A purge that cannot be observed must not print a checkmark.” Underneath it, a gate. That is what a lesson looks like once it stops being a lesson.

Your agent will not learn your codebase. Build a codebase that does not require it to.


Related:

Sources

Ben Peetermans

Ben Peetermans

I build MVPs and run ad campaigns with AI, and I write these notes from real projects. Twenty years shipping for the web. If you want someone who works with these tools every day to build yours, that is what I do.