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.
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 fired | What it caught |
|---|---|
.githooks/pre-push | A push carrying a stale generated stamp |
lint-dead-selectors.mjs | Two CSS rules added “for symmetry” that matched nothing on any page it tests |
lint-no-left-border.mjs | A coloured border I had banned on 2026-08-19 |
render-stamp-inputs.test.js | A static import that worked locally and broke in an isolated tree |
A UserPromptSubmit hook | The 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:

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:
- Why Claude Code Ignores Your CLAUDE.md (and the Fix)
- Claude Code Hooks: Make the Agent’s Behavior Deterministic
- Your Coding Agent Has Memory. Does It Actually Arrive?
- What 17 Retrospectives Taught Me About Coding With AI
Sources
- anthropics/claude-code#37314: “Claude repeatedly fails to apply its own memory/feedback — same mistakes recur across sessions.” Filed 2026-03-22, labelled
bugandmemory, closed stale. - Prakhar Khatri, Do Context Files Help Coding Agents? A Two-Agent Ablation Study on Real Repositories (arXiv 2607.27250, July 2026): 288 evaluated runs, 17 tasks, Claude Code and Codex.
- Claude Code docs, Hooks: the
UserPromptSubmitevent the router runs on. LEARNED.md,AGENTS-SOP.mdand.githooks/pre-pushare in uxxray, a private repository. Figures are from its git history, frozen at 2026-08-27.- Claude Code Memory: 4 Types, a 200-Line Cap: what the built-in memory system stores, and what loads at session start.