CLAUDE.md Workshop

How to write a CLAUDE.md file.

Most CLAUDE.md files are too long, half true, and owned by nobody. Here is what the file does, where it goes, what belongs in it, and what stops working once a whole engineering organization is writing them.

On this page

What the file actually is

A CLAUDE.md is a markdown file that Claude Code loads into context at the start of every session. That is the entire mechanism. There is no parser, no schema and no validation: whatever is in the file becomes part of the prompt, in the order it is found.

Two consequences follow from that, and almost every mistake people make with these files comes from missing one of them. The first is that it is context rather than configuration. Instructions shape what Claude does; they do not enforce it. If something must never happen, a PreToolUse hook is the enforcement layer and CLAUDE.md is not. The second is that everything in the file costs context and competes for attention with everything else in it, which is why a short accurate file beats a thorough one.

Where it goes, and which one wins

There are four places the file can live, and they are cumulative rather than exclusive:

ScopeLocationWho gets it
Managed policy/Library/Application Support/ClaudeCode/CLAUDE.mdYour organization, deployed by IT. Individual settings cannot exclude it. That path is macOS; Linux uses /etc/claude-code/CLAUDE.md.
User~/.claude/CLAUDE.mdYou, in every project on your machine. Never committed anywhere.
Project./CLAUDE.md or ./.claude/CLAUDE.mdYour team, through source control. This is the one people mean.
Local./CLAUDE.local.mdYou, in this project only. Gitignore it.

“Which one wins” is the wrong question, and it is the most common misunderstanding about these files. They do not override each other. Every discovered file is concatenated into context, ordered from the filesystem root down to your working directory, so the file closest to where you launched Claude is read last rather than exclusively.

So a rule in a parent directory is not replaced by the one below it. Both are present, and if they disagree you have written a contradiction rather than an override. In a monorepo that is a real and recurring problem, which is what claudeMdExcludes exists for.

Files in directories above your working directory load at launch. Files in subdirectories below it do not: they load on demand, when Claude reads a file in that directory. That is worth knowing before you go hunting for why a rule did not apply, because a rule sitting in packages/api/CLAUDE.md is genuinely absent until Claude opens something in packages/api/.

A file can also pull in others with @path/to/file, recursing up to four hops. Import parsing skips code spans, so writing a path inside backticks mentions it without importing it.

A complete CLAUDE.md, annotated

This is the shape that survives contact with a real repository. It is short on purpose. Every line is here because leaving it out produced something wrong.

# Payments API

## What this is
Go service behind /v1/payments. Talks to Stripe and to ledger-svc.
NOT the billing UI (that is web/billing) and NOT invoicing (invoice-svc).
# Orientation first: what the thing is, and what it is
# not. The negative half does more work than the positive
# half, because wrong-service edits are the expensive error.
## Commands
- Test: `make test` (NOT `go test ./...`, which skips the
  testcontainers setup and passes when it should not)
- Lint: `make lint`
- One test: `make test ARGS='-run TestAuthorize'`
# The parenthetical is the whole value of this block. The
# command is discoverable; the trap is not.
## Conventions
- Money is `int64` minor units. Never float. Never `decimal`.
- Every exported func returns `(T, error)`; no naked returns.
- New endpoints need a row in `docs/endpoints.md` or CI fails.
# Things a reader cannot infer from the surrounding code
# fast enough, plus one rule whose violation is caught late
# and confusingly.
## Boundaries
- Do not edit `internal/ledger/generated/`. It is codegen;
  change `ledger.proto` and run `make proto`.
- Do not add dependencies without asking.
# Where autonomy stops. Short, absolute, and each one maps
# to something that has actually gone wrong.
## Gotchas
- Local Stripe keys are in 1Password, not `.env.example`.
- `make test` needs Docker running.

Note what is absent. No description of what Go is. No restatement of the directory tree, which Claude can read faster than you can maintain a copy of it. No style rules already enforced by the linter, because a rule the tooling enforces does not need a second home where it can go stale. And no Always write clean, maintainable code, which is the single most common line in these files and has never once changed an output.

What breaks at 500 engineers

Everything above is the solo version of the problem, and it is the version the internet has covered. The part that is harder to find written down is what happens when an organization adopts this at once.

Before going independent I was on the AI Champions team that rolled Claude Code out across engineering at The New York Times, a bit over 500 engineers, and gave three rollout presentations including a CLAUDE.md talk at the internal EngX conference. The failure mode at that scale is not that people write bad files. It is that they write good ones, independently, and the good ones disagree.

Three things that only show up above a certain headcount:

  • Nested files compound instead of resolving. A platform team writes a root CLAUDE.md. Four service teams write their own below it. Every session in those services now carries both, concatenated, and nobody reviewed the combination because nobody owns the combination. The first sign is a rule being obeyed inconsistently, which reads like a model problem and is not one.
  • The things that should be organization-wide are not in CLAUDE.md at all. Security and compliance instructions copy-pasted into forty repositories are forty things to update and thirty-nine that will not be. A managed policy file, deployed by MDM, applies to every session on the machine and cannot be excluded by individual settings. That is where they belong. Anything genuinely mandatory belongs in managed settings instead, since settings are enforced by the client and CLAUDE.md is not.
  • The file rots faster than anyone expects, and rot is contagious. The first time an engineer watches an agent follow an instruction that stopped being true six weeks ago, they stop trusting the file. They do not fix it. They start working around it, and so does everyone they tell. Recovering trust costs far more than maintenance would have.

None of these are solved by writing a better file. They are solved by deciding who owns which layer before the files multiply, which is a fifteen minute conversation if you have it early and a migration if you have it late.

Six checks before you commit it

This is the pass I run on a CLAUDE.md, in order. Most files fail the first two.

  1. Every line survives the question “what does this stop?”If you cannot name the specific wrong output a line prevents, it is decoration and it is diluting the lines that matter. “Write clean code” stops nothing. “Never use git add -A; scope every add to named files” stops something you can point at.
  2. It is under about 200 linesThat is the target in Anthropic’s own guidance, and the reason is adherence rather than cost: longer files reduce how consistently instructions get followed. If yours is past that, the content is not wrong, it is in the wrong container. Move it into .claude/rules/ with a paths field so it loads only when Claude touches matching files.
  3. Nothing in it contradicts anything else in itContradictory rules do not average out. Claude may pick one arbitrarily, and you will not be able to tell which. This gets worse as files stack, because nested files in subdirectories are appended to the ones above them rather than replacing them.
  4. It says what is true today, not what you intendA CLAUDE.md describing the architecture you are migrating toward is worse than no file, because it will be followed. Aspirations belong in a design doc.
  5. The paths in it are realStale paths are the most common decay in a file that was accurate when written. They are also the cheapest thing to check, and the check can be automated.
  6. Somebody owns itNot a team, a person. A file everyone can edit and nobody maintains drifts into a graveyard of rules that used to be true, and the first time an agent follows a dead rule, people stop trusting the file rather than fixing it.

When you do not need one

A CLAUDE.md earns its place when a project has conventions that are real, specific and not visible from the code in the first few minutes. Plenty of projects do not. A small repository with an obvious layout, standard tooling and one contributor is usually better served by a good README that Claude reads anyway.

The honest failure case is the file written because it seemed like good practice. It fills with plausible sentences nobody disagrees with, none of which change any output, and it costs context on every single session forever. If you cannot fill a page with things that are specifically true about your repository, do not pad it. Write six lines and stop.

Questions people ask

Should CLAUDE.md be committed?

Yes, if it describes the project. That is the whole point of the project-level file: your team gets the same standards through source control instead of each person rediscovering them. Keep anything personal, like your sandbox URLs or preferred test data, in a gitignored CLAUDE.local.md beside it.

Where do I find my CLAUDE.md file?

In the project, it is ./CLAUDE.md or ./.claude/CLAUDE.md at the repository root. Your personal one is ~/.claude/CLAUDE.md. If instructions are being applied that you cannot find the source of, check the directories above where you launched Claude Code, because every one of them contributes, and then check whether your organization deployed a managed policy file.

How do I create one?

Run /init in your project. It reads the codebase and writes a starting file with the build commands, test instructions and conventions it can discover, and if a CLAUDE.md already exists it proposes improvements rather than overwriting it. Then delete most of what it gives you and add the things it could not have known.

What makes a CLAUDE.md good rather than just present?

Specificity, and being current. The six checks above are the version I use. The shortest honest test is to open the file and count how many lines would change the output of a real task. On most files the answer is a handful, and the rest is there because it felt like the sort of thing that should be in a standards document.

Does Claude Code read AGENTS.md?

Yes, on recent versions, but only when you have no CLAUDE.md, .claude/CLAUDE.md or CLAUDE.local.md in your working directory or above it. The trap is that a CLAUDE.local.md counts. Adding a personal file to a repository that relies on AGENTS.md quietly stops AGENTS.md being read for you, and for you only, which is a difficult thing to notice from the inside.

Write them on your own repositories.

The CLAUDE.md Workshop is one live 90 minute session with your engineering team, worked against your actual codebase rather than generic examples. Your team writes the context files for your real services in the room and leaves with standards wired to how you already ship.