Some of the rules in your CLAUDE.md should not be rules at all.
Not because they are wrong. Because you have written the things you cannot afford to lose into a file the model reads once and then slowly forgets. A preference survives that. A constraint does not.
A month ago I posted ten CLAUDE.md rules. The most common reply was not "add an eleventh." It was quieter than that: the rules stop getting followed. Forty thousand tokens into a session, the model edits the file you told it never to touch, or commits straight to main after you wrote, in bold, that it never should. Maybe half of what is in my own file is decoration. The half that is not decoration is the half that scares me.
The File Is Read Once. Your Session Isn't.
Claude Code reads CLAUDE.md once, at the start of a session. The instructions then sit in the context window and compete with everything else for the model's attention. As the session grows, the rules near the bottom lose weight. The model is not disobeying. The instruction stopped being load-bearing.
That is the part nobody demos. The screenshot of a clean CLAUDE.md at token zero tells you nothing about token ninety thousand, which is where you actually live when the work gets hard.
The First Instinct Is to Write the Rule Louder
So you do what I did. ALL CAPS. "IMPORTANT." "You MUST." A box of warning emojis.
It works. For a while. A louder line holds attention longer than a quiet one. Then the session gets long and busy, the diff gets large, the model is three tool calls deep into a refactor, and the loud line is now buried under ten thousand tokens of its own output. It decays anyway. You bought yourself an hour.
The instinct is right about one thing and wrong about the rest. It is right that some rules cannot be allowed to fail. It is wrong that emphasis is how you stop them failing.
Stop Writing Constraints as Sentences
So here is the move I opened with, made concrete. Open your CLAUDE.md and split every line into two piles.
Pile one: preferences. Naming style. Comment density. Which library you like. If the model misses one of these at token ninety thousand, you shrug and fix it. These belong in CLAUDE.md. A suggestion is exactly the right shape for them.
Pile two: the lines where a single miss is expensive. Never commit to main. Always run the formatter before claiming done. Never touch the production config. These are not preferences. They are constraints. And a constraint written as a sentence in a file is a hope.
Move pile two into hooks.
A hook is code the harness runs around tool calls. It fires whether the model remembers the rule or not. "Never commit to main" as a CLAUDE.md line survives until it doesn't. As a pre-commit hook, the commit is blocked, by code, at token five and at token two hundred thousand, on a good day and a bad one. The model cannot decay past it because it was never asking the model.
The One That Gets Through
The line in my file said never run the migration without confirming first. It sat there for weeks, doing its job, because nothing pushed against it. Then one long debugging session, deep in a chain of tool calls, the model ran it. The rule was still in the file. It had scrolled out of reach an hour earlier.
That is the shape of the cost. An expensive rule left as a suggestion works ninety-nine sessions. The hundredth is the one you tell people about. A hook would have refused the call and moved on, and I would have nothing to tell.
The rules I actually depend on are now a short list, and not one of them lives in CLAUDE.md anymore. They live in code that does not get tired.
Read Your Own File Back
I build agent setups that hold at token two hundred thousand. The screenshot that looks clean at token zero was never the hard part.
So read your own file back. For each line, ask: if the model ignored this ninety thousand tokens from now, would I notice, and would it cost me?
The lines where the answer is yes were never rules. They were hopes wearing bold text. Which of yours are suggestions, and which are actually enforced?
I write field notes from real builds: AI integration, cron-driven automation, and the parts that break in production. New posts every two weeks. If this one was useful, the human-in-the-loop approval playbook is the companion download.
Top comments (2)
The "preferences vs constraints" split is the right move, and the bit I want to add is that the kind of constraint determines the right enforcement shape. There are at least three:
pre-commithook that refuses a commit to main is a constraint the file system can enforce. The model never has to remember it because the gate is in the loop, not in the prompt.The hard part is figuring out which of the three categories any given rule is in. Most teams default to "write a louder rule" because the third category is small and the second category is rare in a fresh repo. The first one — pre-commit, pre-push, CI — is where almost all enforcement should live, and most projects have it half-built.
A 30-minute audit: list every line in CLAUDE.md, mark each one "hook exists / can hook / no hook possible", and rewrite the file down to just the third column. The file will shrink by 80%. The model will start following it 100% of the time, because the rules that survive are the ones that genuinely need to be in the conversation.
Yes! When I write software I put linters and fast running unit tests in the pre hook, with success. For more complex skills, a dozen or more gates, I write a single reusable CLI per skill first und enforce it to be reusable. That doesn't work from the start so I keep asking the model to get back in line for a couple of times and then the machine runs well:)