Back to blog
Engineering15 min read

CLAUDE.md Best Practices (What Belongs in It)

CLAUDE.md best practices verified against Anthropic's Claude Code docs: where the file loads from, what earns its place in context, what to delete, plus a worked example and audit checklist.

NH
Nafiul Hasan
Founder, Prompt Architects

TL;DR: CLAUDE.md is loaded into Claude Code's context window at the start of every session, so every line in it competes with your actual task for attention. The best practices that matter are subtractive: keep the commands that work, the constraints that break production, and the conventions the code cannot reveal. Delete everything Claude can read for itself.

Most CLAUDE.md advice is a list of things you could write. That is the wrong frame. The file is not a wiki and it is not free. Anthropic's own Claude Code documentation describes CLAUDE.md files as "loaded into the context window at the start of every session, consuming tokens alongside your conversation." So the only useful question about CLAUDE.md best practices is not what could go in it but what earns its place against everything else the model needs to hold at once.

That reframing does the work. Once a line has to justify its cost, the directory listing goes, the dependency inventory goes, and what remains is short, specific, and actually read.

Everything below was verified against Anthropic's Claude Code memory documentation at code.claude.com/docs/en/memory, accessed 28 August 2026. Where Anthropic documents something, it is quoted. Where Anthropic does not, this post says so rather than filling the gap.

Where does Claude Code actually read CLAUDE.md from?

Four scopes, and they stack rather than compete. Anthropic's documentation lists them in load order, broadest first:

ScopeLocationShared with
Managed policymacOS: /Library/Application Support/ClaudeCode/CLAUDE.md · Linux and WSL: /etc/claude-code/CLAUDE.md · Windows: C:\Program Files\ClaudeCode\CLAUDE.mdEveryone in the organization
User instructions~/.claude/CLAUDE.mdJust you, across all projects
Project instructions./CLAUDE.md or ./.claude/CLAUDE.mdYour team, via source control
Local instructions./CLAUDE.local.mdJust you, in this project

The precedence rule is the part people get wrong. These files do not override one another. Anthropic's documentation states that "All discovered files are concatenated into context rather than overriding each other", ordered "from the filesystem root down to your working directory", so instructions closer to where you launched Claude are read last. Within a single directory, CLAUDE.local.md is appended after CLAUDE.md.

Two consequences follow. First, your personal ~/.claude/CLAUDE.md does not get replaced by a project file; it gets added to, and both are paying rent in the same context window. Second, because there is no override, a contradiction between your user file and the project file is not resolved by precedence. It is just a contradiction, and the documentation is blunt about the outcome: "if two rules contradict each other, Claude may pick one arbitrarily."

Files above your working directory load at launch. Files below it behave differently, which matters for monorepo layout.

Are nested CLAUDE.md files in subdirectories picked up?

Yes, and lazily, which makes them one of the few genuinely free things in this system. Anthropic's documentation says Claude Code also discovers CLAUDE.md and CLAUDE.local.md in subdirectories under your working directory, and that "Instead of loading them at launch, they are included when Claude reads files in those subdirectories."

That is a real design lever. Instructions that only matter inside packages/billing/ cost nothing in a session that never touches billing. Pushing area-specific rules down out of a bloated root file is not just tidier, it is cheaper.

The same logic drives .claude/rules/, which Anthropic documents as a directory of topic-scoped markdown files. Rules with a paths: frontmatter field load only when Claude works with matching files; rules without it load at launch with the same priority as .claude/CLAUDE.md. For a big repo, path-scoped rules are the documented answer to a CLAUDE.md that has outgrown itself.

Do imports let you split a big CLAUDE.md without paying for it?

No, and this is the misconception worth killing outright.

Imports exist. CLAUDE.md files can pull in other files with @path/to/import syntax, relative or absolute, "with a maximum depth of four hops." Relative paths resolve against the file containing the import, not your working directory. Import parsing skips code spans and fenced code blocks, so a path wrapped in backticks stays literal instead of importing something.

But splitting a file into imports does not buy you context back. Anthropic's own troubleshooting section, under the heading for a CLAUDE.md that is too large, says splitting into imports "helps organization but doesn't reduce context, since imported files load at launch." Imported files are expanded and loaded at launch alongside the CLAUDE.md that references them.

What actually belongs in a CLAUDE.md?

The test is a single question: is this true, stable, and not derivable from the repo itself? Three yeses and it earns a line.

Anthropic's documentation converges on the same standard from a different direction. The /doctor checkup, which proposes trims for a checked-in CLAUDE.md, is described as cutting "content Claude can derive from the codebase, such as directory layouts, dependency lists, and architecture overviews," and keeping "pitfalls, rationale, and conventions that differ from tool defaults." That is Anthropic's own tooling encoding the subtraction principle.

So, concretely:

The commands that actually work. Not the ones in the README that broke six months ago. The real build, the real test command, the incantation for running a single test file, the typecheck. This is the single highest-value block in most files, because getting it wrong costs a full round trip every time.

Hard constraints and the things that break production. "Never run migrations against the production database." "Pushing to main deploys." These are the entries that pay for themselves the first time they fire.

Conventions a reader cannot infer from the code. If your codebase has both an old pattern and a new one and only the new one is correct, the code cannot tell Claude that. Write down the decision, not the taxonomy.

Where things live when the layout is surprising. Not the whole tree. The one directory nobody would guess.

Known traps, with the reason attached. A trap without a reason gets rationalized away. "Do not bump sharp past v0.33 — the Linux build in CI has no prebuilt binary for it" survives; "don't touch sharp" does not.

Notice what all five have in common: a competent developer reading the repo for an hour would not learn any of them.

What does not belong in a CLAUDE.md?

Everything on this list is something Claude gets for free by reading the repo, or something that will quietly stop being true.

A restated directory listing. Claude can run ls. A tree diagram is paid context duplicating a free tool call, and the first thing to drift when someone adds a folder.

A dependency inventory. package.json exists, it is authoritative, and it updates itself. A hand-maintained list of what you use is wrong the moment anyone installs anything.

A paraphrase of the framework's own documentation. A section explaining how React hooks work, or what the App Router does, buys nothing. The model already knows, and if it did not, your two-paragraph summary would not fix that.

Aspirational values. "Write clean code." "Prefer readable solutions." "Follow best practices." These cannot be acted on or verified. Anthropic's guidance on specificity makes the same point with examples: write "Use 2-space indentation" instead of "Format code properly", and "Run npm test before committing" instead of "Test your changes".

Anything that will silently rot. Version numbers you will not update. Team members' names. A roadmap. Current sprint priorities. The problem is not that these are useless today; it is that nothing tells you when they went stale, and stale content in a file the model trusts is worse than a blank page.

What are the failure modes that actually kill a CLAUDE.md?

Five, and every one of them is a slow failure rather than a loud one.

The file that grows until nobody reads it. It starts at forty useful lines. Someone appends a section after a bad session; someone else appends another. At six hundred lines nobody reviews it and nobody deletes from it, and it has become a place things go rather than a document. Anthropic's size guidance exists precisely for this: "target under 200 lines per CLAUDE.md file", with the note that longer files consume more context and reduce adherence.

Instructions that contradict each other. Usually not within one file, but between the user file, the project file, and a nested one. Nothing errors. The model picks one arbitrarily, you see inconsistent behavior across sessions, and you conclude that CLAUDE.md "doesn't work."

Stale content that is confidently wrong. The expensive one, because it is worse than nothing. A blank file makes the model ask or infer. A file naming a test command that was renamed in March makes the model run something that fails, then reason about why. You have paid context to make the outcome worse.

Vague aspirations that cannot be acted on. As a failure mode rather than merely bad content: they train you to believe the file is working when it is doing nothing.

A file describing the project you wish you had. The most human failure. The CLAUDE.md says tests are required for every change; in reality half the modules have none. It says the API layer is fully typed; three files use any liberally. The model now believes a codebase that does not exist, and its output is calibrated to that fiction.

A worked example: CLAUDE.md for a small web app

Deliberately short, with every line justified below it. Not a template to paste, a demonstration of the standard.

# CLAUDE.md

Next.js 15 App Router app. Postgres via Prisma. Deployed on Fly.io.

## Commands

- Dev: `pnpm dev` (port 3000)
- Test: `pnpm test` — Vitest. One file: `pnpm test src/lib/cart.test.ts`
- Typecheck: `pnpm typecheck` — run before saying a change is done
- Lint: `pnpm lint`

Do not use `npm`. The lockfile is pnpm and mixing them corrupts it.

## Constraints

- `main` auto-deploys to production on push. Work on a branch.
- Never run `prisma migrate` against `DATABASE_URL` from `.env.production`.
- Money is stored as integer cents in `Order.totalCents`. Never introduce a float.

## Conventions the code will not tell you

- Two data-fetch patterns exist. Server Components + `db.ts` is correct.
  Anything calling `/api/internal/*` from the client is legacy — do not copy it.
- New env vars must be added to `env.schema.ts` or the app throws at boot.
- Dates are stored UTC and formatted in the user's zone at render only.

## Traps

- `next/image` is disabled for user uploads. The loader has no allowlist for
  our CDN and it 500s in prod, not in dev.
- `pnpm test` needs Postgres running. Start it with `docker compose up -d db`,
  or 11 tests fail with ECONNREFUSED and everything else passes.

<!-- Maintainer note: reviewed 2026-08-14. Drop the legacy API line once
     /api/internal is deleted. -->

Why each block earns its place:

  • The three-line header. Framework, database, host. Not derivable at a glance, and it stops the model guessing at deployment shape.
  • Commands. The highest-value block. Note "One file" — that is the command people actually need and the one most often missing. Note also the npm warning: a constraint with a stated consequence, not a preference.
  • Constraints. Each one names the thing that breaks. "Work on a branch" without "main auto-deploys" is a style note; with it, it is a rule.
  • Conventions. The legacy-pattern line is the single most valuable entry in the file, and it is exactly what the repo cannot say. Both patterns are present in the code and look equally valid.
  • Traps. Both carry the reason. The next/image one includes "not in dev," which is why nobody caught it.
  • The HTML comment. Anthropic documents that "Block-level HTML comments (<!-- maintainer notes -->) in CLAUDE.md files are stripped before the content is injected into Claude's context." So a review date and a cleanup reminder cost you nothing at all. Use them.

What is absent is the point: no directory tree, no dependency list, no explanation of the App Router, no "write clean, maintainable code". Under fifty lines, well inside the documented 200-line target, and every entry is a fact the code does not carry.

For a wider set of starting points, see CLAUDE.md templates for Claude Code; for the equivalent problem in the chat product rather than the CLI, Claude Project instructions covers the same discipline in a different container.

How do you audit an existing CLAUDE.md?

Nine checks. Run them against your current file and delete on a "no."

  1. Line count. Over 200? Anthropic's guidance says trim, or move content to path-scoped rules. Start with the longest section.
  2. Command truth. Run every command in the file, right now, in a clean checkout. Delete or fix any that fail. This check alone usually justifies the audit.
  3. The derivability test. For each line, ask whether one ls, one cat package.json, or one grep would produce it. If yes, cut it.
  4. The action test. Could two developers disagree about whether an instruction was followed? If yes, it is an aspiration. Make it verifiable or delete it.
  5. Contradiction sweep. Read your ~/.claude/CLAUDE.md, the project file, and any nested ones together, in load order. Look for two rules covering the same behavior.
  6. The reason test. Every prohibition should say what breaks. A rule without a consequence gets overridden the first time it is inconvenient.
  7. The fiction test. Does the file describe the codebase as it is, or as you intended it? Read it next to the actual repo.
  8. Load verification. Run /context and check the list under Memory files. Anthropic's troubleshooting guidance is explicit: if a file is missing there, Claude cannot see it.
  9. Date it. Put a review date in an HTML comment, since those are stripped before injection. Re-audit when the build system, the deploy target, or the test runner changes.

What can CLAUDE.md not do?

This is where most guides overpromise. The documented position:

CLAUDE.md is guidance, not enforcement. Anthropic's documentation states it directly: Claude "treats them as context, not enforced configuration", and the troubleshooting section explains that "CLAUDE.md content is delivered as a user message after the system prompt, not as part of the system prompt itself", with "no guarantee of strict compliance, especially for vague or conflicting instructions." The managed-settings comparison puts the same point in one line: "CLAUDE.md instructions shape Claude's behavior but are not a hard enforcement layer."

If something must happen at a specific moment, the documented answer is a hook: a shell command at a fixed lifecycle event, run regardless of what the model decides. "Always run the linter before committing" in CLAUDE.md is a request. A hook is a guarantee.

There is no published token budget. Anthropic publishes a line target (under 200) and a hard skip threshold (a file over 4 MiB is skipped). It does not publish a token allowance for CLAUDE.md, and any specific token number you see quoted for it is not from Anthropic's documentation. Optimize against the line guidance and observed adherence, not a number nobody published.

Claude Code does not read AGENTS.md. Anthropic's memory page states it plainly: "Claude Code reads CLAUDE.md, not AGENTS.md." If your repo already has one for other tools, the documented pattern is a CLAUDE.md containing an @AGENTS.md import, with any Claude-specific instructions below it, or a symlink if you do not need to add anything. Verified 28 August 2026; that is the kind of fact worth re-checking before you rely on it.

It does not survive everything. Project-root CLAUDE.md is re-injected from disk after compaction, so it persists. Nested CLAUDE.md files and rules with paths: frontmatter reload only as Claude reads files they apply to. An instruction that seems to vanish mid-session was probably given in conversation, or lives in a nested file that has not reloaded.

None of this makes the file weak. It makes it a prompt, subject to the same economics as any other prompt: specific beats vague, short beats long, and a contradiction anywhere degrades everything. The reason AI rewrites code you did not ask it to touch is usually an instruction problem, and the reason a good CLAUDE.md fixes it is that it removes the ambiguity the model was resolving on its own.

Where does this fit alongside your other prompts?

A CLAUDE.md is standing context for one repository. It is not where your reusable prompts live, and making it serve both jobs is how it grows past the point of being read. Prompts you run across projects belong somewhere versioned and searchable, the argument in prompt versioning for developers; the ones you want inside the editor belong on a server the editor can reach, which is what MCP inside Claude Code is for.

Prompt Architects sits on that side of the line. We generate prompts, not repository configuration, and our only Claude Code touchpoint is our MCP server at mcp.prompt-architects.com/mcp (/integrations/mcp), which exposes improve, refine, shorten and enhance as tools. It will not write your CLAUDE.md, and it should not. That file describes your codebase, and only you have that.

The best CLAUDE.md you will ever write is the one you shorten twice. Write down what breaks, what runs, and what the code cannot say. Delete the rest, put a review date in an HTML comment where it costs nothing, and check /context once to confirm the thing is loading at all.

Free Chrome Extension

Stop rewriting prompts. Start shipping.

Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 5.0★ on the Chrome Web Store.

Create An Account

Frequently asked questions

Free Chrome Extension

Stop rewriting prompts. Start shipping.

Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 5.0★ on the Chrome Web Store.

Create An Account