CLAUDE.md: How to Write It for Claude Code, With a Template
What is CLAUDE.md?
CLAUDE.md is a markdown file of persistent instructions that Claude Code loads into context at the start of every session: build and test commands, team conventions, project constraints that aren't obvious from the code. It's context for the model, not enforced configuration. Claude reads the file and tries to follow it, but only hooks and settings rules guarantee that something happens.
TL;DR
- -CLAUDE.md exists at four levels: the organization's managed policy, ~/.claude/CLAUDE.md, the project's ./CLAUDE.md or ./.claude/CLAUDE.md, and a personal ./CLAUDE.local.md. The files don't override each other. Claude Code concatenates them into one context.
- -The Claude Code docs recommend keeping each CLAUDE.md under 200 lines. It's a guideline with no hard cutoff: a long file takes more context and gets followed less reliably, and @ imports don't reduce that cost.
- -Only write down what Claude can't work out from the code: the exact verification commands, places where the code is misleading, team decisions, mistakes that have already happened twice. The model reads the folder structure and the stack on its own.
- -A rule with zero exceptions ("never touch migrations/") moves out of CLAUDE.md into a hook, a deny rule, or managed settings. Multi-step procedures go into skills, and rules for one part of the code go into .claude/rules/ with a paths field.
- -Since v2.1.277, Claude Code reads AGENTS.md directly, but by default only when there's no CLAUDE.md or CLAUDE.local.md in the working directory or above it. The author's test on version 2.1.318 confirmed this in all four configurations.
CLAUDE.md is a markdown file of persistent instructions that Claude Code loads into context at the start of every session. The docs are explicit about its status: Claude treats these files “as context, not enforced configuration.” The model reads the file and usually follows it, with no guarantee. If an action has to be blocked no matter what the model decides, you need a hook.
A lot of CLAUDE.md problems come from that gap. The file grows, CRITICAL and IMPORTANT multiply, and the model still skips rules. The official guide recommends keeping each CLAUDE.md under 200 lines. Researchers from ETH Zurich and LogicStar.ai reached a similar conclusion from the other side: context files raise an agent’s cost by more than 20% on average and, overall, don’t increase the share of solved tasks.
This article covers how CLAUDE.md works in current versions of Claude Code: where the files live, what order they load in, how imports and .claude/rules/ work, what to put in the file, and what to move into hooks and skills. At the end there’s a template and an audit checklist. AGENTS.md, the format shared across different agents, has its own AGENTS.md guide. The examples come from real files in the author’s workspace (about 15 projects), anonymized, and the AGENTS.md behavior was tested on Claude Code 2.1.318.
What CLAUDE.md is and how it differs from auto memory
Context, not configuration
Claude Code has two mechanisms that carry knowledge between sessions. You write CLAUDE.md. Claude maintains auto memory on its own, based on your corrections. Both load at the start of every session.
| CLAUDE.md | Auto memory | |
|---|---|---|
| Who writes it | You | Claude |
| What’s inside | Instructions and rules | Learnings and patterns from corrections |
| Scope | Project, user, organization | Repository, shared across worktrees |
| What loads | The whole file and its imports | First 200 lines or 25 KB |
| Used for | Commands, conventions, constraints | Your preferences and corrections |
Technically, CLAUDE.md arrives as a user message right after the system prompt. It isn’t part of the system prompt itself. Claude reads the file and tries to follow it, but the docs don’t promise strict compliance, especially for vague or conflicting instructions.
The best practices page splits instructions into two kinds. Non-deterministic ones (the prompt, CLAUDE.md, skills) are read by the model, and the model decides whether to apply them. Deterministic ones (hooks, deny rules, managed settings) are executed by Claude Code, and the model’s decision doesn’t affect them. CLAUDE.md always stays in the first group.
Where CLAUDE.md lives and how it loads
Four levels
| Level | Path | Who sees it |
|---|---|---|
| Managed policy | macOS: /Library/Application Support/ClaudeCode/CLAUDE.md; Linux and WSL: /etc/claude-code/CLAUDE.md; Windows: C:\Program Files\ClaudeCode\CLAUDE.md | All users on the machine |
| User | ~/.claude/CLAUDE.md | Only you, in every project |
| Project | ./CLAUDE.md or ./.claude/CLAUDE.md | The team, through git |
| Local | ./CLAUDE.local.md (add to .gitignore) | Only you, in this project |
The table is in load order, from the broadest level to the narrowest: a project instruction lands in context after a user instruction. The managed file is rolled out through MDM, Group Policy, or Ansible. Instead of a separate file, its text can go in the claudeMd key in managed-settings.json. The docs suggest keeping behavioral rules in the managed CLAUDE.md and expressing tool and path restrictions through permissions.deny in managed settings.
Parent and nested directories
Claude Code reads CLAUDE.md and CLAUDE.local.md from the working directory and from every directory above it. If you launch it in foo/bar/, it loads foo/bar/CLAUDE.md, foo/CLAUDE.md, and the CLAUDE.local.md files next to them.
Three details people often get wrong:
- Files are concatenated. None of them overrides another. The order runs from the filesystem root to the working directory, so the model reads instructions closer to the launch point last. Within one directory,
CLAUDE.local.mdcomes afterCLAUDE.md. If two files contradict each other, the docs say Claude may pick one arbitrarily. - Subdirectories load on demand. A
CLAUDE.mdin a subdirectory below the working directory doesn’t load at startup. Claude Code pulls it in when Claude reads, writes, or edits a file in that subdirectory, including reads throughcatorheadin Bash. - Files that load on demand have a character limit. With a 200K context window, it’s 40,000 characters per file. If a nested CLAUDE.md or a path-scoped rule is longer, Claude gets only the beginning plus a note to read the rest with Read. Check the size with
wc -m. The limit applies from v2.1.309.
There’s a free option for maintainer notes: block-level HTML comments <!-- ... --> are stripped before the file goes into context and cost no tokens. Comments inside code blocks are kept.
Monorepos: claudeMdExcludes and --add-dir
In a large monorepo, other teams’ CLAUDE.md files from parent directories get loaded too. You can turn them off with the claudeMdExcludes setting, whose glob patterns are matched against absolute paths:
{
"claudeMdExcludes": [
"**/monorepo/CLAUDE.md",
"/home/user/monorepo/other-team/.claude/rules/**"
]
}
The docs suggest putting this setting in .claude/settings.local.json so the exclusion stays on your machine. It works at any settings level, and arrays from different levels are merged. The managed CLAUDE.md can’t be excluded.
--add-dir works the other way around: by default, CLAUDE.md files from additional directories don’t load. An environment variable turns them on:
CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 claude --add-dir ../shared-config
For more on laying out files in big repositories, see Monorepos and large repos.
@path imports in CLAUDE.md
Syntax and limits
An @path/to/file line anywhere in CLAUDE.md pulls that file’s contents into context:
See @README for project overview and @package.json for available npm commands for this project.
# Additional Instructions
- git workflow @docs/git-instructions.md
Parsing rules:
- a relative path resolves from the file that contains the import, not from the working directory;
- imported files can import other files, up to a depth of four hops;
- imports don’t fire inside code spans and code blocks, so to mention a path without loading it, wrap it in backticks (
`@README`); - escape a space in a path with a backslash (
@Design\ Docs/api.md); a path in quotes isn’t imported at all; - an import in a project file that points outside the working directory triggers an approval dialog the first time it appears. If you decline, imports stay off. User-level files (
~/.claude/CLAUDE.md,~/.claude/rules/) import without the dialog, except in Cowork sessions.
The main limitation: an import doesn’t save context. The imported file loads together with its parent. Splitting into files makes maintenance easier, but 300 lines across three imports cost the same as 300 lines in one file.
Pattern: a thin global file
In the author’s workspace, the global ~/.claude/CLAUDE.md is a single line:
@shared-rules.md
The personal rules live in a separate 225-line file. It’s versioned on its own and imported into every project. This is import as organization: the file is easy to edit and to carry between machines. Context still pays for all 225 lines, and the file itself is over the 200-line recommendation.
The same trick helps with worktrees. A CLAUDE.local.md ignored by git exists only in the worktree where it was created. To get personal instructions into every copy of the repository, the docs suggest importing a file from your home directory: @~/.claude/my-project-instructions.md.
What to put in CLAUDE.md and what to leave out
What to write
Best practices keep in the file what Claude can’t work out from the code:
- how to verify work: the exact commands for tests, typecheck, the linter, and running a single test file. According to the docs, the verification command is the single most useful line in the whole file;
- places where the code misleads: an old pattern that shows up everywhere but shouldn’t be copied, or a directory that looks dead but is in use;
- decisions that aren’t in the repository: which error helper the team picked, how deployment works, which migrations need review;
- anything you’ve had to correct twice.
The “When to add to CLAUDE.md” section lists four signals that it’s time to add an entry. Claude made the same mistake a second time. A code review caught something Claude should have known about the codebase. You type the same correction into chat that you typed last session. A new teammate would need the same context.
Write instructions you can verify. “Use 2-space indentation” beats “format code properly.” “Run npm test before committing” beats “test your changes.” “API handlers live in src/api/handlers/” beats “keep files organized.”
What not to write
- Architecture and file layout that are visible from the code. The best practices table of outdated advice has a row for exactly this: Claude reads the repo itself.
- General wishes with no way to check them. “No hacks” and “write exemplary code” are things the model can’t verify, so it can’t reliably follow them either.
- Multi-step procedures. A release, an incident runbook, a data migration sequence belong in a skill. If Claude can invoke the skill on its own, each session sees only its name and description, and the full text loads when a task needs it.
- Rules for one part of the code. They belong in
.claude/rules/with apathsfield. - Secrets. You can describe how they’re handled (where they come from, which script syncs them), but not the values.
This approach has empirical backing. In “Evaluating AGENTS.md: Are Repository-Level Context Files Helpful for Coding Agents?” (Gloaguen et al., ETH Zurich and LogicStar.ai, arXiv 2602.11988), agents ran SWE-bench tasks with LLM-generated context files, plus a new set of issues from repositories where developers had written those files themselves. The abstract’s conclusions: context files don’t generally improve the share of solved tasks, and they raise inference cost by more than 20% on average. Agents follow the instructions well, repository overviews don’t help them, and the files pay off where they describe non-standard practices. The paper is about AGENTS.md, but it’s the same kind of file, and the finding matches the docs’ advice: write only what isn’t obvious.
Rule, reason, verification
The rules that hold up best in the author’s files share one shape: a prohibition, the reason for it, and a pointer to whatever checks the result instead of a human. An anonymized example:
## Deploy
- Don't deploy functions with the bare CLI command: it resets the
JWT verification flag, and sign-up breaks after that.
Deploy only through `scripts/deploy.sh`: it checks the flags after rollout.
An entry like this has three useful properties. The reason shows the model where the rule’s boundaries are, so it doesn’t stretch the rule to cases where it isn’t needed. The steps aren’t retold: the rule points to the script as the source of truth. And the script checks the result even if the model forgot the rule.
Git rules work the same way. In one project, the ban on git stash -u comes with a description of a real incident: published material ended up in the untracked part of a stash and vanished from the working tree. Next to it, the file describes an installed git hook that blocks dropping such a stash. The text explains the reason, and the hook enforces it.
Two more patterns that have worked well:
- A pair of lists: “ask before changing” and “free to change.” The risk zone gets an explicit boundary, so there’s no need to forbid everything.
- One main rule at the very top of the file. In the author’s files, the rule about atomic commits comes first: that item has to be seen before everything else.
CLAUDE.md size and its cost in context
The 200-line recommendation
The docs put it this way: “target under 200 lines per CLAUDE.md file. Longer files consume more context and reduce adherence.” It’s a guideline. Nobody cuts off text after line 200. Here’s what actually happens:
- if a file is longer than recommended, Claude Code shows a warning at startup and in
/status; - a separate warning appears when files that are each within the norm together exceed the total startup limit (every CLAUDE.md, rules file, and
@import counts as a separate file); - Claude Code skips a file over 4 MiB entirely;
- files that load on demand have a character limit (40,000 with a 200K window), past which the model sees only the beginning.
Numbers from the author’s workspace (wc, November 2026):
| File | Lines | Words | Assessment |
|---|---|---|---|
| Small project (bot) | 43 | ~190 | Structure, stack, launch, ADR link; that’s enough |
| Blog | 116 | ~670 | Commands, architecture, git rules |
| Workspace root file | 174 | ~1280 | Project map, secrets scheme, rules |
| Global rules (via import) | 225 | ~1870 | Over the recommendation |
| Product monorepo | 708 | ~3860 (41 KB) | 3.5 times the recommendation |
~/.claude/CLAUDE.md | 1 | - | Only @shared-rules.md |
The author didn’t measure how many tokens the largest file takes, so there’s no estimate here. For your own file, /context shows that number.
How to measure: /context and /memory
/context all prints a Memory files section: which CLAUDE.md, CLAUDE.local.md, and AGENTS.md files loaded at startup and how many tokens each one takes. If a file isn’t on the list, the model can’t see it. In fullscreen mode, /context with no argument collapses that list.
/memory lists memory files at the user and project level, opens them in an editor, and turns auto memory on or off.
There are two built-in checks for cleanup:
/doctorsuggests cuts to the project CLAUDE.md. It removes what Claude can work out from the code (directory layout, dependency lists, architecture overviews) and keeps gotchas, rationale, and conventions that differ from the defaults;/doctor prompt-audit(since v2.1.283) looks for instructions written for older models, references to files and commands that no longer exist, and contradictions between files. It checks CLAUDE.md, CLAUDE.local.md, AGENTS.md, plus rules, skills, commands, subagents, and output styles in.claude/and~/.claude/. The report changes nothing until you ask it to apply the fixes.
Why compact, relevant context beats a big one is covered in detail in the context engineering guide.
.claude/rules/ and path-scoped rules
If a rule only matters in part of the codebase, it goes into .claude/rules/. Each .md file in that folder covers one topic, and subdirectories are searched recursively.
Rules without a paths field load at startup with the same priority as .claude/CLAUDE.md. Rules with a paths field load when Claude reads, writes, or edits a matching file:
---
paths:
- "src/api/**/*.ts"
---
- Validate request bodies with the zod schemas from src/api/schemas/
- Every new endpoint needs an entry in openapi.yaml, or CI fails
From a rules file’s frontmatter, Claude Code reads only paths and silently ignores every other field. If the YAML doesn’t parse, the frontmatter is dropped and the rule loads unconditionally. claude --debug shows the parse error.
Two more mechanisms exist. Personal rules for all projects go in ~/.claude/rules/, and they load before project rules. A shared rule set can be linked into .claude/rules/ with a symlink, but a symlink outside the working directory counts as an external import and needs approval.
Good candidates for moving into rules are CLAUDE.md sections that start with “when working with…”: when working with migrations, when editing the mobile client, when changing edge functions.
CLAUDE.md, hook, or skill: what goes where
| What you need | Mechanism | Why |
|---|---|---|
| Facts for every session: commands, conventions | CLAUDE.md | Always loaded |
| Rules for one part of the code | .claude/rules/ with paths | Loads only when working with matching files |
| A multi-step procedure | Skill | Full text loads when needed |
| A rule with no exceptions | Hook, deny rule, managed settings | Claude Code executes it, the model’s decision isn’t involved |
| Personal settings in a project | CLAUDE.local.md | Stays out of git |
| A check before work is finished | Stop hook or CI | Sends Claude back to work until the check passes or the block limit is reached |
Exceptions decide whether a rule stays in CLAUDE.md or becomes a hook. Best practices walk through three rules: “don’t read .env,” “run the formatter after edits,” “don’t touch the migrations folder.” The model follows them almost always. If “almost” isn’t good enough, the rule moves into configuration: the formatter into a PostToolUse hook, the migrations ban into a PreToolUse hook that exits with code 2. “Prefer named exports,” on the other hand, stays in CLAUDE.md, because a rule like that has plenty of legitimate exceptions.
According to the docs, the sign that a line should become a hook is this: you keep adding emphasis to it, and Claude keeps skipping it anyway. The reverse holds too: hooks for what is really just a preference are better deleted, leaving the call to the model. Events, exit codes, and examples are covered in the Claude Code hooks guide, and moving research into a separate context is described in the article on subagents.
CLAUDE.md template
The template below follows the “only what isn’t obvious” principle. Its values are an example for a TypeScript project, so replace them with your own. HTML comments don’t reach the context, so hints for humans can stay right in the file.
# CLAUDE.md
<!-- Only what Claude can't work out from the code. Target: under 200 lines. -->
## Commands
- Install: `pnpm install --frozen-lockfile`
- Single test: `pnpm vitest run path/to/file.test.ts`
- Typecheck: `pnpm tsc --noEmit`
- Full check before a PR: `pnpm lint && pnpm test && pnpm build`
## Constraints
- Don't edit the generated client in `src/gen/`: `pnpm codegen` overwrites it.
- Change the DB schema only with a new migration in `db/migrations/`.
## Conventions
- Throw errors through the helpers in `src/lib/errors.ts`, not as strings.
- `src/legacy/` is live, but don't carry its patterns into new code.
## Gotchas
- Integration tests need `DATABASE_URL`, see `.env.example`.
## Ask before changing
- `infra/`, `.github/workflows/`, existing files in `db/migrations/`
## Learned rules
<!-- Format: rule / why (what broke) / date. Review once a quarter. -->
- Deploy only through `scripts/deploy.sh`: the bare CLI command resets
the function's security flags. (YYYY-MM)
## References
- Architecture decisions: @docs/decisions/README.md
A CLAUDE.local.md template for personal settings in the same project (add the file to .gitignore):
# CLAUDE.local.md: just for me, not committed
- Test environment: http://localhost:3000, test user from `seed/users.ts`
- Reply in Russian, keep terms and code in English
- Show a plan before large edits
You don’t have to write the file from scratch. /init generates a first version from the codebase, and if a CLAUDE.md already exists, it suggests improvements instead of overwriting it. With the CLAUDE_CODE_NEW_INIT=1 variable, the command runs interactively: it asks what to set up (CLAUDE.md, skills, hooks), explores the code with a subagent, and shows a proposal before writing any files. As best practices put it, from there the work is mostly removing lines.
A short starter version with verified commands and constraints is in the complete Claude Code guide.
How to maintain CLAUDE.md
Learned Rules and audits
In the author’s files, the “Learned Rules” section only grows after a real mistake, with a date and a short “why.” An anonymized example from practice: a four-check definition of “done” for a security fix (repeat the attack from outside, check the CVEs of the running version, cover every entry path, run a detector with a backtest). The rule appeared after a case where a “fix” was verified only against the configuration.
Left alone, a section like this grows fast. A working routine:
- After a mistake, add a rule in the “what to do, why, date” format.
- Once a quarter, run
/doctor prompt-auditand delete rules that a hook or linter now covers, or that went stale along with the model. - Move a rule the model keeps breaking into a hook.
- Keep notes for humans in HTML comments, which cost no tokens.
Common mistakes
Every example below came from the author’s own files:
| Mistake | Why it hurts | What to do |
|---|---|---|
| A 708-line file: behavior, architecture, testing philosophy, agent orchestration | Extra context on every task, rules get lost | Split into .claude/rules/ with paths and skills, keep commands and constraints in CLAUDE.md |
| Two independent copies: CLAUDE.md and AGENTS.md | The copies diverge, and drift is already visible in some projects | One source: @AGENTS.md in CLAUDE.md, or a symlink |
| CRITICAL and IMPORTANT in more than nine places in one file | Emphasis loses its value; per the docs, current models respond to it by applying the rule more broadly than needed | Shorten the file, move no-exception rules into hooks |
| General principles with no criterion (“no hacks”) | Nothing to check | Rewrite in a verifiable form or delete |
| A description of the folder structure and stack | Claude will read this itself | Delete or replace with a link to the ADRs |
| Paths and commands that no longer exist | The model follows instructions that point nowhere | /doctor prompt-audit |
The advice to mark important rules as CRITICAL shows up in many guides, including earlier versions of posts on this blog. The docs’ current table of outdated advice gives it its own row: older models benefited from emphasis, and current ones follow a plainly worded line.
CLAUDE.md and AGENTS.md
Some guides still say Claude Code reads only CLAUDE.md. That’s wrong for v2.1.277 and later: a built-in plugin reads AGENTS.md directly. The default behavior:
| In the repository | Claude reads |
|---|---|
| AGENTS.md, no CLAUDE.md or CLAUDE.local.md in the working directory or above | AGENTS.md |
| AGENTS.md and CLAUDE.md (or CLAUDE.local.md) | Only CLAUDE.md |
CLAUDE.md with an @AGENTS.md import | CLAUDE.md, and AGENTS.md through the import |
The author tested four configurations on Claude Code 2.1.318 (claude -p, isolated folders, a unique marker in each file) and compared the model’s answer with the /context all output. The result matched the docs. One trap is easy to miss: a personal CLAUDE.local.md in an AGENTS.md project turns off reading AGENTS.md, and the model sees only the local file. The @AGENTS.md import doesn’t create a duplicate: Memory files lists each file once.
To have Claude read both files, set Project instructions = claude-md-and-agents-md in /config. In the settings file, that’s the key pluginConfigs["cc-plugin-agents-md@builtin"].options.instructionFiles. It’s read only from ~/.claude/settings.json, a --settings file, or managed settings, and project settings ignore it. The format, compatibility with Codex, Cursor, and Copilot, and ways to keep one file for every agent are covered in the AGENTS.md guide. If a separate tool syncs your rules, the AgentSync write-up is useful: once AGENTS.md could be read directly, some of those scenarios got simpler.
Limitations and what wasn’t tested
- The Claude Code docs change often. The version numbers (v2.1.277, v2.1.283, v2.1.285, v2.1.309) and the plugin ID
cc-plugin-agents-md@builtinare current as of November 2026. Before v2.1.285, the plugin was calledagents-md@builtin. - Behavior after
/compactis described from the docs. After compaction, the root CLAUDE.md is re-read from disk and injected into the session again, while nested CLAUDE.md files and rules withpathsreload on demand. Instructions that only came up in conversation are lost, so they’re worth moving into the file. This wasn’t tested with a live/compact. - The AGENTS.md test ran in non-interactive
claude -pmode. Interactive/config,--add-dir, aCLAUDE.mdsymlink pointing toAGENTS.md, and nested AGENTS.md files weren’t tested. - The ETH Zurich data comes from the paper’s abstract. Percentages for individual agents and models aren’t given here.
- How shortening the 708-line file changes the quality of work wasn’t measured. The size table shows volume, not effect.
Where to start
- Run
/context alland see which files actually loaded and what they cost. - If there’s no CLAUDE.md, generate one with
/initand immediately delete everything Claude would read from the code on its own. - Put the exact verification commands at the top of the file: tests, typecheck, linter, running a single test.
- Run
/doctor prompt-auditand work through the contradictions and dead references. - Find the rules marked CRITICAL and IMPORTANT: either reword each one calmly or move it into a hook.
- Move “when working with…” sections into
.claude/rules/withpaths, and turn procedures into skills.
If a project has both CLAUDE.md and AGENTS.md, continue with the AGENTS.md guide: it covers how to keep a single source of rules. A broader look at skills, subagents, and hooks is in Claude Code Skills and Agents.