
A CLAUDE.md that changes decisions, not one that describes the project
Most are a README with a different filename. The test for every line is whether an agent could act differently because of it, and two sections justify the file on their own.
CLAUDE.md sits at the root of the project and Claude Code reads it at the start of every session. Most of the ones we see are a README with a different filename: a paragraph about what the company does, a list of commands, and nothing that changes a single decision. A useful one is closer to a set of standing corrections, written so that the mistake you fixed in week one does not come back in week four.
Write the decisions, not the description
The test for every line is whether an agent could act differently because of it. A sentence explaining that the company builds websites for healthcare clients changes nothing. A sentence saying that no page may carry a client statistic unless it appears in a named source file changes what gets written on every page. The first is context, the second is a constraint, and only the second earns its place.
What belongs in it on a website project
| Section | Why it earns its place |
|---|---|
| Stack and versions | Framework with its major version, styling approach, and anything the agent must not install. Without the version it writes the API it was trained on. |
| Content model | Where copy lives and which files are data rather than code. This is what stops the agent hard-coding a heading into a component. |
| Claims policy | What may be asserted on a page and what needs a source. The single highest-value section, because invented specifics are expensive to find later. |
| House style | Punctuation, tone, words you do not use. Cheap to state and otherwise re-corrected forever. |
| Verification | Which command proves a change worked. Without it the agent will claim success from a clean build, which proves nothing about the page. |
| Known traps | The bugs this repository has already produced twice. This is the section that grows and the one that pays. |
Keep it short enough to be read
It loads at the start of every session, so every line is paid for on every turn. A file that has grown to a thousand lines of accumulated advice dilutes the twenty lines that matter. Prune it the way you would prune a test suite: when a rule has not prevented anything in three months, it was documentation rather than a constraint. Claude Code also builds auto memory as it works, so some of what people write by hand accumulates on its own.
Scope rules to where they apply
A monorepo with a marketing site, an app and a component library does not have one set of conventions. Nested files are read for sessions in or below their directory, so the rules for the marketing site can sit with the marketing site instead of being qualified with an exception in a single root file. If the repository already has an AGENTS.md for other coding agents, Claude Code can read that instead, which saves maintaining two.
What does not belong
- Anything secret. It is a file in the repository and it is read into context on every session.
- A changelog. It grows without bound and none of it changes a decision.
- Anything enforceable by a tool. A formatting rule belongs in the formatter and a lint rule in the linter, where they apply whether or not anybody read the file.
- Instructions that only apply sometimes. Those are a skill, invoked when relevant, not a standing cost on every session.
The surrounding workflow is in building a website with Claude Code, and the traps worth writing into the known-traps section on a web project are collected in what to check before you believe the agent built it.
A worked example, shortened
What follows is the shape of a real one, with the project specifics removed. The point is the ratio: almost every line is a rule with a consequence, and the only description present is the one sentence needed to make the rules make sense.
- Stack: the framework and its major version, the styling approach, and a named list of what not to install.
- Content: every string lives in the data layer. A heading hard-coded in a component is a defect, not a shortcut.
- Claims: no statistic, client name or testimonial may appear unless it exists in a named source file. If a number is needed and absent, leave the sentence out.
- Style: the punctuation and words the house does not use, stated once so they are not re-corrected weekly.
- Verification: the exact command that proves a change worked, and the explicit note that a clean build does not.
- Traps: the bugs this repository has produced before, each with the check that catches it.
Write rules that fail loudly
A rule phrased as a preference gets weighed against other considerations and sometimes loses. A rule phrased as a condition does not. Prefer we never ship a page without a canonical to try to remember canonicals, and where a rule can be made mechanical, move it out of the file entirely and into a check that fails the build. The file is for the things a tool cannot decide.
Settings are a separate lever
Instructions are not permissions. Which commands can run without asking, which directories are reachable and which tools are available belong in settings, not in prose that asks nicely. Teams that try to enforce a boundary by writing it into CLAUDE.md have written a request. Teams that put it in settings have written a rule. Both have their place, and confusing them is how a project ends up with a long file nobody follows.
Two places this file reaches that are easy to miss. A subagent starts with your instructions loaded unless you deliberately omit them, so a rule written here governs delegated work too, which matters more than it sounds once you are splitting a large build: what to delegate to subagents covers where that line falls. And a rule that must hold rather than merely be read does not belong in prose at all, which is the argument in the hooks that gate a website repository.

