Every repository we work in has a CLAUDE.md, and most of the work in them is done by an AI agent. At first we wrote that file the way you'd write onboarding docs for a new hire: what the project is, the stack, a tour of the folders, the coding conventions. Thorough and welcoming.
The agent ignored roughly half of it. So we wrote more rules, the file got longer, and compliance got worse.
The problem wasn't the amount of documentation. It was the kind. We had written a README; what the job needed was a contract.
CLAUDE.md in this repository is 164 lines, about ten thousand characters.
Twelve ## sections. Four of them are "things this repo does differently," three are "what the build checks and what it doesn't." The project introduction is five lines. The first version was longer, and most of that length was introduction and general advice.
1. Where Does a Given Rule Belong?
Held against each rule, it came down to four questions. The answers decide where that rule lives.
The order matters. Skip Q1 and the file keeps inflating. Ask Q2 first and you get "write it down now, automate it later" — and later never arrives.
Here's how rules in this repository actually sorted:
The last row is the awkward one. It is checkable; we just haven't built the check. So it stays in the document, labeled explicitly as "the one part the build will not catch for you." The absence of automation is itself information worth stating.
2. Don't Write Down What the Agent Already Does
The early version contained lines like these.
All true. All unnecessary. An agent does these without being asked — they're general good practice, already baked in.
And they aren't free. A long file buries the rules that matter. If 27 lines out of 30 are things anyone would do anyway, the other three read like more of the same.
If no, delete it. What survives is the things this repository does differently — which is the only reason the file exists.
3. Keep Only the Judgment Calls
After the cut, the surviving rules mostly looked like this.
The second rule is the interesting one. General good practice says "move inline styles into a stylesheet." Here the opposite is correct. Leave it unwritten and the agent helpfully refactors — pulling the inline styles out of a passthrough-copied page and quietly breaking something.
The third rule points the other way, in the same repository. Policy splits by page type. Nothing in the code tells you whether that split is intentional or an accident.
So there are three kinds of rule worth writing down:
- Things that contradict general practice — otherwise the agent will "fix" them.
- Things that split within one repository — otherwise it generalizes from the first example it sees.
- Things that leave no trace in the code — external systems, deploy procedures, agreements with other repos.
4. Every Prohibition Needs a Reason
Bare prohibitions hold poorly. A prohibition with a reason generalizes to adjacent cases.
An agent that read the second version makes the same call later when it meets app-ads.txt or a .well-known domain-verification file. The first version says nothing about those.
For the same reason, "do X" beats "don't do Y." A prohibition with no alternative just sends the agent looking for a way around it. "Write vanilla JS; don't introduce a new client framework" held up far better than "don't use React."
5. Spell Out How to Verify
This section had the largest effect of anything we added. It defines what "done" means.
The second half matters far more than the first. The default assumption is that a green build means the work is done; this states explicitly what the build cannot see.
That last line earns its place surprisingly often. It's a one-sentence rule against reporting a check that never happened.
6. Rules a Document Can't Enforce Belong in Code
This is the real conclusion. The more important a rule is, the less it belongs in the document.
Every post on this site has to exist in Korean and English. Originally that was just a bold line in the rules file — and posts still shipped in one locale only. A document can go unread, and even when read it fades partway through a long task.
So we moved it into a build hook. Add a post in one locale now and the build fails.
The difference is categorical. A documented rule is something it would be good to follow; a build rule is something you cannot proceed without. An agent can skim past a paragraph. It cannot skim past a failing build.
Needing emphasis means the rule gets broken often, and rules that get broken often keep getting broken no matter how much you emphasize them.
One more rule moved the same way. While building scheduled publishing we hit the problem that a link between posts can point into the future — another rule a document cannot enforce, because at the moment you write the link the target file is sitting right there in the repo and nothing looks wrong. Once the build started scraping every post link and comparing publish dates, that mistake stopped happening.
Moving rules into code taught us one more thing: don't delete the rule from the document when you do. Delete it and the agent works in ignorance until the build fails at the end — by which point it has spent half a day going the wrong way. So the document keeps a single line saying "the build enforces this" — not the rule in full, just the existence of the guard.
Not everything can move, of course. "Translations shouldn't read like machine translation" has no automated check. Leave that class of rule in the document and migrate everything that a check can express.
7. Reporting Rules — Say What Must Be Said
The last section we added, and one we're glad we did.
The real risk with agent work isn't a wrong thing reported as right — that gets caught in review. It's half the work reported as all of it, which doesn't. Deciding in advance what must always be mentioned closes a good deal of that gap.
8. Five Kinds of Sentence That Shouldn't Stay
"Would this happen anyway?" wasn't the only test for cutting. A separate class of sentence is neither wrong nor obvious — it just turns harmful with time.
The first row is a real line in this repository's file. On the day an eleventh page appears it quietly becomes false, and one false line lowers the credibility of every other line. Counts belong in a build check, or nowhere.
The third row we learned from editing posts on this site. Point at another document by section number and adding one section there silently makes your sentence wrong. The same applies inside a rules file: the moment it references itself by section number, adding a rule turns into proofreading the whole document.
The fourth is the opposite failure — a sentence that's too strong. If a real exception exists and the file says "always," an agent that meets the exception either breaks the rule or stops working. Both are bad. Whoever knows the exception should write it down.
9. When a Rule Gets Ignored — Diagnosing Why
"The agent doesn't follow the rules" turned out not to be one phenomenon. Each symptom has a different cause and a different place to fix.
The second row is the counterintuitive one: the rule gets broken, so you write more rules, and the writing is the cause. That is exactly where we were.
The fourth row happened here. "Keep the inline style" was written as a landing-page rule, but with no stated scope — so inline styles started appearing in blog posts too. The rule was followed and the result was wrong. Now every rule in the file leads with its subject: "landing and lab pages…", "blog posts…".
10. Common Questions
How long should the file be?
Section count tracks the experience better than line count. This repo has twelve, and no section runs past a screen. Past twenty or so, there are usually two things mixed together — rules and explanation. Move the explanation elsewhere and keep the rules, and the file halves.
In a monorepo, one file at the root or one per repository?
We run both: shared rules at the workspace root, repo-specific rules inside each repository. The essential part is stating which one wins on a conflict. That's why this repo's file opens with a single line: it assumes the shared rules and overrides them where they disagree. Without that line, an agent picks arbitrarily when two documents say different things.
Different tools want different filenames (CLAUDE.md, AGENTS.md). What then?
If the content is the same, make one canonical and have the other point at it. Maintain both and they will diverge, and after they diverge nobody knows which is right. This isn't a documentation problem — it's the ordinary cost of writing the same fact in two places.
Should rules include example code?
A wrong/right pair works far better than a single correct example, which leaves the boundary invisible. Just keep it short — examples inflate the file as surely as prose does. We hold each pair to about five lines.
How soon does editing the file change behavior?
On the next task. The file is read at the start of every session, so there's no training lag. That means the day you notice a broken rule is the day to fix the wording. Conversely, if it breaks again right after you fixed it, the problem isn't wording — go back to the diagnosis table above.
Can the agent write this file?
Drafting, yes; deciding, no. Rules files written by an agent tend to refill with general advice, because the evidence for what counts as an exception in this repo lives outside the file. The prompt that actually helped was "list the places you were unsure in this repository." That list was the list of rules worth writing.
11. In Summary
The file ended up less than half its original length, and compliance clearly improved. The principles:
- Don't write what would happen anyway. It buries what wouldn't.
- Keep only genuine judgment calls — against general practice, split within the repo, or invisible in the code.
- Attach a reason to every prohibition. Reasons generalize; bare rules don't.
- State how to verify, especially what the build misses.
- Move checkable rules into code. The document is the fallback, not the mechanism.
- Say what must be reported. It exposes half-finished work.
- Never write counts fixed in time or cross-references by section number. They go quietly false.
- Lead every rule with its subject. Without a scope, a rule can be followed and still produce the wrong result.
If your CLAUDE.md reads like a README, take another look at it. The reader isn't someone new to the project — it's a collaborator who already knows every general convention and none of your exceptions. The file only needs to carry the difference.