A CLAUDE.md is the file Claude Code reads at the start of every session: standing instructions for your project, in plain markdown, usually at the repo root. AGENTS.md is the same idea for agents that are not Claude Code, and Claude Code reads it through a one-line import rather than natively. This page covers the eight sections most files carry, where the file goes, a full template you can paste, and the guardrail rules almost nobody writes.

A line earns its place in a CLAUDE.md by being checkable. Sounding wise doesn’t count. “Write clean code” fails that test: nothing afterward proves the assistant did it or skipped it. “Never edit supabase/migrations/* without a test that logs in as a second account and tries to read the first account’s row” passes: either that test exists and ran green, or it doesn’t and the change shouldn’t have shipped.

That’s the whole standard, and it fits in one line:

Never touch src/lib/payments/webhook.ts without pnpm test webhook passing.

One sentence, one file, one command that either runs green or doesn’t. Compare that to the line most starter templates open with, “keep the code clean and well-documented,” and the gap between those two sentences is what the rest of this post is about.

Most of what currently ranks for CLAUDE.md best practices covers the same ground, and covers it well: keep the file short, list the build and test commands, describe the folder structure so the assistant stops guessing where things live, then hand you the /init-generated starting point to trim by hand. Anthropic’s current best-practices guide also separates advisory instructions from deterministic hooks and recommends giving Claude a check it can run. The practical gap is connecting those ideas to a real app: naming the paths where a plausible change costs money or data, pairing each path with the exact check that protects it, and stating which secrets must never appear in a response, log, or commit.

What goes in a CLAUDE.md file

Eight sections cover the baseline that every guide on this topic lists. Each one earns its place the same way: keep it if the agent has guessed wrong about this at least once.

  • Project overview: one or two lines on what the app does and who uses it. Keep it if the agent has misread the product.
  • Tech stack and versions: framework, runtime, package manager, database, with versions. Keep it if the agent has written code for the wrong major version.
  • Build, test and deploy commands: the exact strings, not descriptions of them. Keep it if the agent has invented a script name.
  • Project structure: three or four lines on where things live. Keep it if the agent has put a file in the wrong directory.
  • Coding conventions: the ones a formatter can’t enforce, like naming, error handling, or named-versus-default exports. Keep it only if a linter or formatter doesn’t already catch it.
  • Workflows: the sequence for a common job, like adding a migration or an endpoint. Keep it if you’ve typed the same sequence into chat twice.
  • Domain jargon: the words your team uses that mean something specific here. Keep it if a new hire would need it explained.
  • MCP server notes: which servers are connected and what each is for. Keep it if the agent has reached for the wrong one.

That’s the part /init will draft for you from the codebase, and the part every ranking guide already covers well. What none of them cover is the next layer: the files where a plausible-looking change costs money or leaks data, and the check that proves the change was safe. Those are the guardrail sections below.

How long should the file be

Anthropic’s memory documentation gives one number: target under 200 lines per CLAUDE.md file, because longer files consume more context and reduce how consistently Claude follows them. There’s no separate smaller target and no rule about how many sections you need. Two things help when the file starts growing: /doctor proposes trims for a checked-in CLAUDE.md, cutting content Claude can derive from the codebase and keeping the pitfalls and conventions it can’t; and anything that only matters for one part of the codebase moves into a path-scoped rule under .claude/rules/, which loads only when Claude reads a matching file.

Splitting into @path imports is worth doing for organization, but it doesn’t shrink anything. Imported files still load at launch and still enter the context window.

How to phrase a rule so it gets followed

One rule per line. Imperative mood. A file path or a command in every line. Emphasis markers like IMPORTANT reserved for the two or three rules that actually matter, because a file where everything is important reads like a file where nothing is. No prose paragraphs: the assistant scans structure the way a reader does.

# Before
We care a lot about test coverage on this project and it's important that
any changes to authentication are properly tested before they go out.

# After
- `src/lib/auth/*`: don't change without `pnpm test auth` passing first.

Where the CLAUDE.md file goes

The project file lives at ./CLAUDE.md or ./.claude/CLAUDE.md and gets committed. Four other locations exist, each with a different scope:

LocationScopeLoads
./CLAUDE.md or ./.claude/CLAUDE.mdThe project, shared with the team through version controlIn full, at launch
~/.claude/CLAUDE.mdJust you, across every project on your machineIn full, at launch
CLAUDE.md in a subdirectoryThat part of the codebaseOn demand, when Claude reads a file in that directory
./CLAUDE.local.mdJust you, this project only. Add it to .gitignoreIn full, at launch
Managed policy path (/Library/Application Support/ClaudeCode/CLAUDE.md on macOS, /etc/claude-code/CLAUDE.md on Linux, C:\Program Files\ClaudeCode\CLAUDE.md on Windows)Everyone in the organization, deployed by ITIn full, at launch

Claude Code walks up the directory tree from where you launched it and concatenates every file it finds, ordered from the filesystem root down to your working directory. The file closest to where you started is read last. Nothing overrides anything; it all stacks.

The subdirectory row is the one that matters for a security-minded file, because it puts the rule next to the thing it protects:

your-project/
├── CLAUDE.md                    # loaded at launch, committed
├── CLAUDE.local.md              # personal, gitignored
├── .claude/
│   └── rules/
│       └── testing.md           # path-scoped, loads on a matching file
├── src/
└── supabase/
    └── migrations/
        └── CLAUDE.md            # loads when Claude reads a migration

A CLAUDE.md next to supabase/migrations/ is the natural home for the row-level-security rule, and it costs nothing in the sessions that never touch a migration.

To split a long file, use @path/to/file imports. Relative paths resolve against the file doing the importing, not your working directory; imports can nest up to four hops; and wrapping a path in backticks keeps it literal instead of importing it. One caveat on CLAUDE.local.md: it’s gitignored, so it only exists in the worktree where you created it. If you work across git worktrees, import a file from your home directory instead (@~/.claude/my-project-instructions.md) and it follows you.

Two commands are worth knowing. /memory lists your CLAUDE.md and CLAUDE.local.md locations across user and project scope and opens any of them in your editor. /context shows which files actually loaded into the session you’re in, which is the first thing to check when a rule seems to be ignored.

The guardrail sections nobody writes

A security-minded CLAUDE.md earns its keep on three sections most starter templates skip entirely: a fragile-areas list naming the files where a wrong change costs money or data, a matching test command for each of those files, and a secrets rule stating what never gets echoed into a chat, log, or commit.

  • Fragile areas: the files or directories where a plausible-looking change costs money or leaks data (auth middleware, RLS policies, the payment webhook), named specifically enough that “fragile” means a file path, not a feeling.
  • Never-touch-without-a-test: for each fragile area, the exact test command that has to pass before that file changes, so the rule can be checked instead of trusted.
  • Secrets rules: what never gets echoed back into a chat response, a log line, or a commit, stated as specifically as the fragile-areas list.

All three matter for the same reason: a wrong-but-confident answer in one of these spots does damage that nothing in the demo will show you. Why AI coding tools ship security holes by default covers the same ground from the model’s side: auth, payment verification, and tenant isolation are exactly the classes that pass a demo and fail a second account.

Line up a vague version of the same three rules against a checkable one and the gap is immediate:

Sounds like a guardrail Is one
Auth code is sensitive, be careful with itsrc/lib/auth/*: don’t change without pnpm test auth passing first
Never leak secretsNever echo an API key, signing secret, or service-role token into a chat response, log line, or commit
Payments need extra caresrc/lib/payments/webhook.ts: don’t restructure without pnpm test webhook passing against a replayed, unsigned payload
Sounds like a guardrail
Auth code is sensitive, be careful with it
Never leak secrets
Payments need extra care
Is one
Auth code is sensitive, be careful with it
src/lib/auth/*: don’t change without pnpm test auth passing first
Never leak secrets
Never echo an API key, signing secret, or service-role token into a chat response, log line, or commit
Payments need extra care
src/lib/payments/webhook.ts: don’t restructure without pnpm test webhook passing against a replayed, unsigned payload

Why Claude ignores your CLAUDE.md

Three things explain almost every case, and only one of them is about the writing.

It isn’t the system prompt. CLAUDE.md content is delivered as a user message after the system prompt, not as part of it. Anthropic’s documentation is plain about the consequence: Claude reads it and tries to follow it, but there’s no guarantee of strict compliance, and vague instructions get the loosest treatment of all. That’s the mechanism behind the checkable-line standard at the top of this post.

The file is too long. The documented target is under 200 lines, because longer files consume more context and reduce adherence. A file that grew to 400 lines of preferences is followed less carefully than a 60-line file, because the lines that mattered are competing with the ones that didn’t.

The rule contradicts another rule, or never loaded at all. If two files give different guidance for the same behavior, Claude may pick one arbitrarily, and a project file plus a user file plus a nested file plus .claude/rules/ is four places for that to happen. Before rewriting anything, run /context and check the list under Memory files: if your file isn’t there, it is being missed rather than ignored. One related gotcha: the project-root file survives /compact and gets re-injected, but nested CLAUDE.md files in subdirectories do not. They reload the next time Claude reads a file in that directory.

Fix the first two with shorter, more specific lines. The third is a plumbing problem. And when a rule absolutely has to hold, none of the three is the real answer. The same three failures show up in a builder’s own instruction fields, and Lovable documents both what it reads on every message and where those instructions stop holding.

A rules file only works if something enforces it

A CLAUDE.md rule enforces nothing by itself. Anthropic’s documentation says Claude treats the file as context, not enforced configuration, and a written rule only becomes a guardrail once something outside the conversation, a test that fails the build, checks whether it held.

I’ve seen what an unenforced rules file looks like when it’s dressed up as the safety layer of an entire product. In the AxonBuild audit corpus, Repo 04 was an AI orchestrator for a health-data platform, marketed on the promise that a human approves every clinical action before it happens. Its written guardrail was a 462-line policy file spelling out exactly what the AI could and couldn’t do without sign-off. I checked whether the running server actually loaded that file anywhere. It didn’t, and that’s the finding that’s stuck with me: the approval logic that existed lived elsewhere in the code, hand-rolled, and had already drifted from what the policy document claimed. The same audit found a second, separate way the same product’s approval step could be walked around: the orchestrator handed the model its own step-up token and stamped every action as human-confirmed, so a steered model could sign off on itself. Two different failures, one root cause: nothing was checking whether the written rule held.

That’s an extreme version of a mistake a CLAUDE.md makes on a smaller scale. Anthropic’s own documentation is direct about the mechanism: “Claude treats them as context, not enforced configuration. To block an action regardless of what Claude decides, use a PreToolUse hook instead.” A CLAUDE.md is a briefing, read at the start of every session and taken seriously. A briefing is not a lock, and the locks live elsewhere: what Claude Code can actually touch is decided by the permission tiers and hooks, not by anything you wrote in this file. Reach works the same way: what connecting an MCP server to Claude Code actually grants is settled in MCP configuration, and a line in this one asking the assistant to be careful with a server changes none of it. The fragile-areas list above only becomes a guardrail once something outside the conversation, a test that fails the build, checks whether the rule held. Write the rule and stop there, and you’ve built Repo 04’s policy document at a smaller scale: something a founder could point to, resting on nothing that runs.

A CLAUDE.md the assistant reads and a rule the build enforces are two different things, and only one of them survives an agent that’s confident and wrong.

A full CLAUDE.md template, annotated

Paste this, delete what you don’t need, and replace the paths with yours. The top four sections are the baseline every guide covers; the bottom three are the guardrail sections almost nobody writes. The file is annotated with HTML comments, and Claude strips block-level <!-- --> comments before the file enters its context, so a note for the next human costs zero tokens.

# Project

Multi-tenant scheduling app for independent clinics. Every row is scoped to a
clinic; a leak across clinics is the worst thing that can happen here.

# Stack

- Astro 6 · Node 22 · pnpm · Supabase (Postgres + row-level security)
- Payments via a webhook handler, not a hosted checkout.

# Commands

- `pnpm dev` (one server on :4321) · `pnpm build` · `pnpm test` · `pnpm lint`
- Never start a second dev server on another port to work around a stale one.

# Structure

<!-- Three or four lines. If this is drifting into a full folder map,
     delete it: the agent can read the tree faster than you can maintain it. -->

- `src/lib/` shared logic · `src/pages/api/` endpoints · `supabase/migrations/` schema

# Fragile areas

<!-- Every line below names a file and a command. If a line doesn't have
     both, it's a preference, not a guardrail: move it out of this section. -->

- `src/lib/auth/*`, `middleware/session.ts`: don't change without `pnpm test auth` passing first.
- `supabase/migrations/*.sql` (RLS policies): any edit needs a passing test that logs in as a second account and tries to read the first account's row.
- `src/lib/payments/webhook.ts`: signature verification runs on the raw request body. Don't restructure this file without `pnpm test webhook` passing against a replayed, unsigned payload.

# Secrets

<!-- This section exists because assistants debug by printing things. -->

- Never echo an API key, a signing secret, or a service-role token into a chat response, a log line, or a commit message, even while debugging. Mask it first.

# Before you touch a fragile area

- If the matching test doesn't exist yet, write it before you change the file it protects, not after.
- Don't disable a type check, lint rule, or test to make a build pass. Ask first.

Trim the top half hard. Anything in the baseline sections that your agent has never guessed wrong about costs you context and returns nothing, and /init will regenerate most of it whenever you actually need it. What no /init pass produces is the bottom half, because it depends on knowing which of your files can cost money.

One thing is deliberately missing from both halves: any statement of what to build. That belongs one step upstream in a spec written before the agent starts; this file only names what not to break once it has. In the guardrail sections, every line is a file path plus a command, because that’s the only shape of instruction a build can actually check.

Keep the file short by pointing at other files

When the file outgrows a screen, don’t compress the prose. Move the detail out and leave one line per topic naming the doc to read:

# Where to look

- Test commands and fixtures: @docs/testing.md
- Schema and RLS policies: @docs/schema.md
- Deploy and rollback steps: @docs/deploy.md

Imports keep the file readable, but they don’t buy context back: imported files are expanded and loaded at launch alongside the file that references them. The thing that actually stays out of context until it’s relevant is a path-scoped rule. Put a markdown file in .claude/rules/, give it a paths front matter list of globs like supabase/**/*.sql, and it loads only when Claude reads a file that matches. That’s the mechanism to reach for when a fragile-areas entry only concerns one corner of the repo.

The pruning test, and keeping the file honest

A CLAUDE.md earns its length back the same way it earned its first line: something checkable justifies keeping it. Once a quarter, or whenever a new fragile-areas entry gets added, read the file from the top and ask, for every line, whether it’s ever caught anything. A rule nobody remembers writing, backed by no test, and never once fired, is the file turning back into the style guide it was trying not to be. Delete it, or write the test that would let it earn its place back. How long that prune takes depends entirely on how many fragile areas got named honestly in the first place, and if the count is zero, the file was never actually guarding anything to begin with.

Commit the file, and review it in pull requests the same way you review code. A guardrail nobody on the team agreed to is a guardrail nobody follows, and a fragile-areas line added in a cleanup pass three weeks later is three weeks of changes that went out unprotected: add the line the same day you add the fragile area. Personal notes that shouldn’t be in the repo have their own homes, CLAUDE.local.md for this project or ~/.claude/CLAUDE.md for habits that follow you everywhere, so there’s no reason for them to end up in the shared file.

The file stays useful only as long as it stays true, which makes it read work as much as write work. The maintainability case for a rules file covers the other half of this, the churn and the god files a rules file also helps contain. This post is the narrower slice: the sections that exist because something real, a login, a payment, another customer’s row, is now on the other side of the change. Whether that’s actually the state your app is in yet deserves a straight answer before you write the file at all, and whether an AI-built app is ready to launch is where that answer starts.

More on working with Claude Code

A rules file is one part of a working setup. The remaining maintenance and buying decisions have their own pages: the technical debt AI-generated code leaves behind once a few months of it accumulate, what Claude Code costs per month and what the free plan leaves out, and the Claude Code alternatives worth comparing before you switch, and what a 500 from Claude Code means for the work already on disk when the tool stops mid-edit.

File locations, load order, import syntax, and the 200-line guidance on this page were checked against the current Claude Code memory and best-practices documentation, August 2026.

Common questions about CLAUDE.md files

What is a CLAUDE.md file?

A CLAUDE.md file is a plain markdown file of standing instructions that Claude Code reads at the start of every session. You write it yourself, usually at the repo root as ./CLAUDE.md or ./.claude/CLAUDE.md, and commit it so the team shares it. What goes in it is whatever the assistant would otherwise get wrong every session: the build and test commands, the stack and its versions, where things live, the conventions a formatter can’t catch, and the files that must not change without a named check passing. Anthropic’s memory documentation gives one size target, under 200 lines per file, because longer files consume more context and reduce how consistently Claude follows them.

What it is not is configuration. Anthropic’s documentation says Claude treats the file as context rather than enforced settings, so a line in it shapes behavior without guaranteeing it, and blocking an action regardless of what Claude decides is a PreToolUse hook’s job. The eight baseline sections, the three guardrail sections, and a full annotated template are all above.

Where should the CLAUDE.md file go?

The project file goes at ./CLAUDE.md or ./.claude/CLAUDE.md in the repo root, committed so the team shares it. Personal preferences that apply to every project go in ~/.claude/CLAUDE.md, and personal notes for one project go in a gitignored ./CLAUDE.local.md. You can also put a CLAUDE.md inside a subdirectory: it loads only when Claude reads a file in that directory, which makes it the right home for a rule about migrations or payments.

Files above your working directory load in full at launch and stack rather than override, ordered from the filesystem root down. The “Where the CLAUDE.md file goes” section above has the full table, including the managed policy path an IT team can deploy.

How long should a CLAUDE.md be?

Anthropic’s guidance is to target under 200 lines, because longer files consume more context and reduce how consistently Claude follows them. There’s no smaller target and no rule about how many fragile areas to name. Let the guardrail section grow only when another specific path can cause real harm and has a matching check.

If the file is approaching 200 lines, move anything that only matters for one part of the codebase into a path-scoped rule under .claude/rules/ rather than trimming prose in the top-level file. @path imports help you organize the content but don’t reduce it, because imported files still load at launch.

Why does Claude ignore my CLAUDE.md?

Usually because the rule is vague, the file is long, or it never loaded. CLAUDE.md content arrives as a user message after the system prompt, so it shapes behavior without guaranteeing compliance, and specific lines like “run pnpm test auth before changing src/lib/auth/*” survive that far better than “be careful with auth”. Run /context and check the list under Memory files first: a file that isn’t there isn’t being ignored, it’s being missed.

The other common cause is two files disagreeing. A project file, a user file, a nested file, and .claude/rules/ all stack, and when two of them contradict each other Claude may pick either one.

Should I commit CLAUDE.md to git?

Yes. The project CLAUDE.md is meant to be shared with the team through version control, and reviewing changes to it in pull requests is what keeps the fragile-areas list honest. Keep personal material out of it: CLAUDE.local.md (gitignored) holds per-project preferences, and ~/.claude/CLAUDE.md holds the ones that follow you across every project.

What goes in CLAUDE.md when the repo already has an AGENTS.md?

Claude Code does not read AGENTS.md natively, so if your repo already has one, add a CLAUDE.md whose first line is @AGENTS.md and put any Claude-specific rules underneath it. A symlink works too when you have nothing Claude-specific to add. AGENTS.md as the cross-tool rules file standard covers the format itself, and AGENTS.md vs CLAUDE.md settles which file a repo actually needs.

Can Claude Code read Cursor rules?

Claude Code doesn’t read .cursorrules on its own as a persistent instruction file or re-read it from session to session. It loads the CLAUDE.md family and .claude/rules/ instead. There is a one-time migration path: Anthropic’s current memory documentation says /init reads .cursor/rules/ or .cursorrules, plus .github/copilot-instructions.md, and incorporates relevant parts into the CLAUDE.md it generates. With CLAUDE_CODE_NEW_INIT=1, the initializer also reads AGENTS.md, .devin/rules/, .windsurf/rules/ or .windsurfrules, and Cline rules from .clinerules. After that import, the original Cursor rules still do nothing on their own in later Claude Code sessions. If you run more than one tool and want one file all of them read, AGENTS.md is the cross-tool rules file standard, and Claude Code picks it up through a symlink or a one-line import rather than natively.

Does a CLAUDE.md file replace tests?

No, and the two aren’t interchangeable. A CLAUDE.md tells the assistant what not to break. A test is what turns “don’t break this” from a request into a fact the build can verify. Write the fragile-areas list without the matching test commands, and the result is a document an assistant reads and a founder can point to, rather than a control anything actually enforces.