CLAUDE.md Best Practices

How to write a CLAUDE.md that agents follow: keep it short, make every rule checkable, give the reason, cut what the code already says, and move the rest into rules and skills.

Most CLAUDE.md files fail the same way. They start useful, grow past what an agent will reliably act on, collect a few instructions that contradict each other, and end up as a file everybody edits and nobody trusts.

The fix is not more detail. It is knowing what belongs in the file, what belongs somewhere else, and what to cut. This page covers how to write one well. For what a CLAUDE.md is and where it goes, start with the CLAUDE.md file guide.

Almost none of this is specific to Claude Code. AGENTS.md, .cursor/rules/, and .github/copilot-instructions.md are the same idea with different filenames, and the practices carry across all of them.

Understand what the file can and cannot do

This is the one that explains most disappointment with CLAUDE.md.

Instructions in a CLAUDE.md are delivered as context, not as enforcement. In Claude Code they arrive as a user message after the system prompt. The agent reads them and tries to comply. There is no mechanism that makes it comply.

So a CLAUDE.md is the right place for standards, conventions, and background. It is the wrong place for anything that must happen every single time. If a step has to run before every commit, write a hook, which executes as a shell command at a fixed point regardless of what the agent decides. If a path must never be touched, use a permission deny rule rather than a sentence asking nicely.

Write the file for guidance. Use the enforcement layer for enforcement.

Keep it short

Every CLAUDE.md loads at the start of every session, so its whole length is subtracted from the context available for actual work. Worse, adherence drops as the file grows. A 600-line file is not three times as effective as a 200-line one. It is less effective.

Anthropic’s own guidance is to target under 200 lines per file. Treat that as a real ceiling.

This matters more the more agents you run. One agent reading a bloated file wastes some context. Six agents across three projects each reading their own bloated file wastes it six times over, and the cost of a sloppy file scales with your parallelism.

A note on a common workaround: splitting a long file into @ imports does not help. Imported files load at launch alongside the file that references them. Imports are for organizing, not for shrinking.

Cut everything the code already says

The single largest source of bloat is content an agent could derive by reading the repository: directory trees, dependency lists, architecture overviews, descriptions of what a framework is.

This is well enough established that Claude Code’s own /doctor checkup will propose trims along exactly these lines. It cuts what is derivable from the codebase and keeps the pitfalls, the rationale, and the conventions that differ from tool defaults.

Use that as your filter. Keep the things an agent would get wrong by making a reasonable assumption. Cut the things it would get right by looking.

Make every rule checkable

A rule you could not verify is a rule nobody can follow.

VagueCheckable
Format code properlyUse 2-space indentation
Write good testsEvery route handler needs a test for the 4xx path
Keep files organizedAPI handlers live in src/api/handlers/
Be careful with the databaseMigrations are forward-only. To undo one, write a new migration.

The left column reads like instruction and communicates nothing. Everyone already believes they format code properly.

Give the reason with the rule

A rule with its reason attached survives contact with situations you did not anticipate.

Compare “do not edit src/generated/” against “do not edit src/generated/, it is rewritten by npm run codegen”. The first is a boundary. The second lets an agent work out what to do instead, and generalize correctly to a file you forgot to mention.

Reasons cost a clause. They are among the cheapest words in the file.

Hunt for contradictions

When two instructions conflict, an agent may follow either one, and which one can vary between sessions. That produces the worst failure mode: intermittent, unreproducible, and easy to blame on the model.

Contradictions accumulate quietly, because they usually arrive months apart from different people. They also hide across files. A user-level file, a project file, a nested file in a subdirectory, and a path-scoped rule are all in context at once, and nothing warns you when they disagree.

Re-read the whole set periodically, not just the file you are editing.

Add to it when you correct something twice

The best signal for what belongs in a CLAUDE.md is your own repetition. If you have typed the same correction into a session twice, that is the file telling you what is missing.

The reverse is also a signal. An instruction nobody has needed in six months is a candidate for deletion, not preservation.

Move the rest into rules and skills

Much of what people cram into CLAUDE.md belongs elsewhere, and moving it makes the remaining file stronger.

Path-scoped rules are for instructions that only apply to part of the codebase. A rule in .claude/rules/ with a paths value loads only when the agent touches matching files:

---
paths:
  - "src/api/**/*.ts"
---

- Every endpoint validates its input
- Use the standard error envelope

Your API conventions stop costing context on the days you work on the frontend.

Skills are for procedures rather than standing facts. A release checklist, a migration runbook, a review process: these load when invoked or when the agent judges them relevant, so they cost nothing the rest of the time.

The split is roughly: standing facts in CLAUDE.md, file-specific rules in .claude/rules/, procedures in skills.

Write it once for every agent you run

If you use more than one agent, and most people now do, resist keeping a separate instruction file per tool. They drift, and a stale file is worse than no file because it is confidently wrong.

Keep one source of truth and point the others at it. AGENTS.md is the closest thing to a common format, read by more than 25 tools. Claude Code does not read it directly, but a one-line import bridges that:

@AGENTS.md

## Claude Code
Use plan mode for changes under `src/billing/`.

Now the shared instructions live in one file, and each tool’s file holds only what is genuinely specific to it. That is usually very little.

Leave notes for humans without spending context

Block-level HTML comments are stripped from a CLAUDE.md before it reaches the agent. They cost nothing at runtime and stay visible to anyone opening the file:

<!-- Added after the March incident. Do not remove without asking the platform team. -->
- Migrations are forward-only.

Useful for recording why a rule exists when the reason is too long to sit in the rule itself.

Check that it loaded

An instruction that never reached the agent looks exactly like an instruction it ignored, and the two get confused constantly.

In Claude Code, /context lists what actually loaded under Memory files. If your file is not there, nothing you write in it will change anything, and the problem is location rather than wording.

Check this first, before rewriting a rule that was never read.

Review it like code

A CLAUDE.md is the highest-leverage file in the repository. Every agent session begins by reading it, so an error in it is an error repeated across every piece of work anyone does.

Treat changes to it the way you treat changes to a shared config: reviewed, with a reason in the commit message, and pruned when they stop earning their place.

The short version

  • Guidance goes in the file. Enforcement goes in hooks and permissions.
  • Under 200 lines.
  • Cut anything the agent could learn by reading the code.
  • Every rule specific enough to check.
  • Every rule carries its reason.
  • No two rules that disagree.
  • Add what you have corrected twice, delete what nobody has needed.
  • File-specific rules become path-scoped rules; procedures become skills.
  • One source of truth, imported by whichever agents you run.
  • Confirm it loaded before assuming it was ignored.

Keeping this true across projects

Following all of this in one repository is manageable. The problem is the tenth repository, where the files quietly diverge and nobody notices until an agent does something strange.

Starter files let crystl seed the same CLAUDE.md and AGENTS.md into every new project, so they begin identical instead of copied from whichever repo was open last. The agent file editor puts the config files for every project in one panel, which is the only practical way to spot drift between them. The project optimizer scans a project for gaps, including a file that has gone missing or thin, and fixes each one in a click.