Guide8 min read

How to write a CLAUDE.md that Claude Code actually follows

A CLAUDE.md is a Markdown file Claude Code loads at the start of every session, from your working directory and every directory above it. All of them are concatenated rather than overriding each other, ordered from the filesystem root down, so the file closest to where you launched Claude is read last. The practical rules are: keep it short, because everything in it competes for context; write what an agent could not infer, not general best practice; and split anything long into .claude/rules/ so it loads only when relevant. It is context, not enforcement — if a rule must never be broken, back it with a hook or a test.

By Lazy Flow

Where it goes, and what actually loads

Claude Code loads CLAUDE.md and CLAUDE.local.md from your current working directory and every directory above it. Launch in foo/bar/ and it loads foo/bar/CLAUDE.md, foo/CLAUDE.md, and any CLAUDE.local.md alongside them.

They are concatenated, not overridden — which surprises people who expect the nearest file to win. Content is ordered from the filesystem root down to your working directory, so foo/CLAUDE.md appears before foo/bar/CLAUDE.md, and within a directory CLAUDE.local.md is appended after CLAUDE.md. Your personal notes are the last thing Claude reads at that level.

Files in subdirectories below your working directory behave differently: they are not loaded at launch, only when Claude reads a file in that subdirectory. That is what makes per-package instructions in a monorepo affordable — you are not paying for every package's rules on every session.

A typical layout
your-project/
├── .claude/
│   ├── CLAUDE.md          main project instructions
│   └── rules/
│       ├── testing.md     loaded every session
│       ├── api-design.md  loaded every session
│       └── frontend.md    path-scoped: only when touched
├── CLAUDE.local.md        yours, gitignored
└── AGENTS.md              the portable baseline

Keep it short — and the comment trick

Everything in a CLAUDE.md is in context for the whole session, competing with your actual code for the model's attention. A page that is entirely load-bearing beats ten pages where the agent has to work out which parts still apply.

The test: if you have explained something to the agent more than twice, write it down. If you have never needed to explain it, leave it out. "Write clean, readable code" costs tokens and changes nothing.

Split it with .claude/rules/

Once a CLAUDE.md is long enough to scroll, move topics into .claude/rules/ as separate Markdown files — one topic per file, with descriptive names like testing.md or security.md. All .md files are discovered recursively, so subdirectories like frontend/ and backend/ work.

Rules without frontmatter load at launch with the same priority as .claude/CLAUDE.md. The gain is organisational, not yet a context saving.

The context saving comes from path scoping. A rule with a paths field in its YAML frontmatter only loads when Claude is working with matching files:

.claude/rules/api-design.md
---
paths:
  - "src/api/**/*.ts"
---

Every route returns AppError with a machine code, never a bare string.
Validate at the boundary with the shared zod schemas, not inline.

That rule costs nothing on a session spent in the frontend. On a large codebase this is the difference between instructions that stay sharp and a preamble so long the model skims it.

Imports, and their limits

A CLAUDE.md can pull in other files with @path syntax. Imported files are expanded and loaded at launch alongside the file that references them. Relative paths resolve against the file containing the import, not your working directory — the usual cause of an import that works from the repo root and breaks from a subdirectory.

Importing
See @README for the project overview and @package.json for the
available npm commands.

@AGENTS.md

# Claude-specific notes

Only guidance that is meaningless in another tool belongs below here.

Two limits worth knowing before you build a structure on this. Imports recurse to a maximum depth of four hops, so a chain of files each importing the next stops being loaded at the fifth. And import parsing skips Markdown code spans and fenced blocks — so to mention a path without importing it, wrap it in backticks. Outside backticks, @README imports the file.

Monorepos and extra directories

In a large monorepo, other teams' CLAUDE.md files on the path above you get picked up along with your own. claudeMdExcludes takes paths or globs and skips them, which is the difference between useful shared context and four teams' conventions arguing in one window.

Worth knowing about --add-dir: by default, CLAUDE.md files in additional directories are NOT loaded. If you want them, set CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1, which pulls in that directory's CLAUDE.md, .claude/CLAUDE.md, .claude/rules/*.md and CLAUDE.local.md.

Loading instructions from a shared directory
CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 claude --add-dir ../shared-config

The limit nobody mentions

Anthropic's documentation is unusually direct about this, and it is the most important sentence on the subject: Claude treats these files as context, not enforced configuration. The agent weighs your instructions against everything else in the session and can decide otherwise.

So a CLAUDE.md is the right place for conventions, architecture, reasoning and preferences — things where judgement is wanted. It is the wrong place for anything that must hold every time.

For those, use something mechanical. A PreToolUse hook blocks an action regardless of what the model decides. A test fails. A lint rule fails. CI refuses the merge. "Never edit the generated schema file" in prose is a strong hint; the same rule as a hook is a guarantee.

TRY THIS PROMPT
List the instruction files you loaded this session with their full paths, then tell me the three rules you consider binding and where each came from. Don't summarise — quote them.

Run that in a fresh session after any change to the setup. If the paths are not what you expected, or a rule you care about is missing, you have found the problem in one message rather than after an afternoon of odd behaviour.

Common questions

Does a nested CLAUDE.md override the one above it?

No. All discovered files are concatenated rather than overriding each other, ordered from the filesystem root down to your working directory. The nearer file is read last, which gives it recency but not authority — if two files genuinely contradict, the agent may pick either. Remove the contradiction rather than relying on position.

CLAUDE.md or .claude/rules/ — which should I use?

Start with CLAUDE.md. Move to .claude/rules/ when it is long enough that you scroll to find things, or when a set of conventions only matters for part of the codebase. Rules without paths frontmatter load every session at the same priority as .claude/CLAUDE.md; rules with it load only when Claude touches matching files, which is where the context saving actually comes from.

Should CLAUDE.md be committed?

Yes — it is project documentation and the value is that everyone's agent follows the same conventions. Keep personal preferences in CLAUDE.local.md, which is meant to be gitignored. One caution: CLAUDE.local.md suppresses a shared AGENTS.md for you alone, so if your project relies on one, set Project instructions to claude-md-and-agents-md.

How long should it be?

Shorter than feels right. Every line competes for attention with your code, and stale lines actively mislead. Put rationale and maintainer notes in HTML comments, which are stripped before the file reaches the model and therefore cost nothing.

READ NEXT