CLAUDE.md File Example: Global, Project and Local Layers
A real CLAUDE.md file example: the managed, user, project and local layers, how they load, @imports, and what belongs in a skill or a hook instead.
By Matthews WongReviewed on Checked against Claude Code v2.1.296
Key takeaway
CLAUDE.md is a Markdown file of instructions that Claude Code loads into every session. Files from four scopes, managed, user, project and local, are concatenated rather than overridden, broadest first, and files in subfolders load only when Claude works there. Keep it short, keep procedures in skills, and back every hard rule with a hook, permission or test.
You will be able to
- Put an instruction in the right CLAUDE.md layer and predict the order Claude reads them in.
- Decide whether a rule belongs in CLAUDE.md, a path-scoped rule, a skill or a hook.
- Confirm with /context what actually loaded, instead of assuming it did.
Step through the diagram
Press Play, or step with the arrows. Every step is written out below the diagram.
How CLAUDE.md files load into Claude's context
Instruction files from four scopes join the context in order after the system prompt, imports expand at launch, a subfolder's file waits for a file read, and only a check outside CLAUDE.md can enforce a rule.
Reviewed on 13 October 2026 · Claude Code v2.1.296
Keys: ← → step · Home / End · K play or pause
Claude Code reads CLAUDE.md files from four scopes: your organisation, you on every project, your team in this repo, and you alone in this repo.
At launch the four files are joined in that order, broadest first, after the system prompt. Nothing overrides anything; if two disagree, Claude may follow either.
An @path line loads another file at launch, alongside the CLAUDE.md that names it. Imports tidy a long file, but cost exactly as much context.
- git workflow @docs/git.mdPredict the next step Claude now reads src/api/app.ts. What happens to src/api/CLAUDE.md? (It joins the context now · Nothing: it loaded at launch · It replaces the root CLAUDE.md)A CLAUDE.md inside a subfolder waits. It joins the context the first time Claude reads, writes or edits a file in that folder.
The docs target under 200 lines per file. This repo's runs past 500, so its long blog procedures belong in a skill, which loads only when needed.
.claude/skills/publishing-blog-posts/SKILL.mdPredict the next step Does a rule in CLAUDE.md stop Claude from breaking it? (Yes, if it sits in the project file · No, only a check that fails does)CLAUDE.md is a request, not a guarantee. This repo pairs its hard rules with checks that fail, like the parity check that stops the build.
`assertBlogParity()` fails the build otherwise.Run /context and read the Memory files list. If a file is missing there, Claude cannot see a word of it.
/context
Where do CLAUDE.md files live, and in what order do they load?
A CLAUDE.md can live in four places. A managed file, deployed by IT, applies to everyone on the machine and cannot be excluded. Your user file at ~/.claude/CLAUDE.md applies to you in every project. The project file, ./CLAUDE.md or ./.claude/CLAUDE.md, is committed so the whole team shares it. CLAUDE.local.md holds your personal notes for one project and belongs in .gitignore.
Read more (2)Show less
Claude Code does not pick one of them. It loads every file in your working directory and the directories above it and concatenates them, broadest scope first, so a project instruction is read after a user instruction. In each directory, CLAUDE.local.md comes after CLAUDE.md. A CLAUDE.md in a subfolder below where you started loads later, the first time Claude reads, writes or edits a file in that folder.
Because nothing overrides anything, a contradiction is a bug. If your user file says npm and the project file says pnpm, the docs warn that Claude may pick one arbitrarily. This repo keeps only this site's facts in its project file; preferences that apply to every project live in the author's own user file, which is never committed.
How do @imports work in a CLAUDE.md?
Write @path/to/file anywhere in a CLAUDE.md and Claude Code loads that file into context at launch, alongside the file that references it. Relative paths resolve from the importing file, not from where you started Claude, and imports can nest up to four hops deep. A path inside backticks or a code block is left alone, so you can mention a file without importing it.
Read more (1)Show less
Imports organise; they do not save anything. An imported file loads at launch exactly like inline text, so splitting a 600-line file into five imports costs the same context. To defer instructions until they matter, use a path-scoped rule in .claude/rules/ or a skill. The first time a project imports a file from outside the working directory, Claude Code asks you to approve it.
What belongs in CLAUDE.md, and what belongs in a skill or a hook?
CLAUDE.md is for facts Claude needs in every session and cannot guess: the build and test commands, conventions that differ from the defaults, and gotchas. The docs suggest asking of every line, "Would removing this cause Claude to make mistakes?" File-by-file tours, tutorials and anything Claude can work out by reading the code do not belong there.
Read more (2)Show less
A multi-step procedure, or anything that matters for only one part of the codebase, belongs elsewhere. A skill loads on demand, when you invoke it or when Claude decides it is relevant. A rule in .claude/rules/ with paths frontmatter loads only when Claude touches a matching file. That is why this repo's blog publishing pipeline lives in its publishing-blog-posts skill.
Anything that must happen every time belongs in a hook or a permission rule. CLAUDE.md reaches Claude as a user message after the system prompt, so it shapes behaviour without enforcing it. Each of this repo's hard rules has a backstop that fails on its own: assertBlogParity() breaks the build, the merge script rejects bad blog JSON, and a test fails if a figure creeps back into a figure-free post.
How long should a CLAUDE.md file be?
The docs target under 200 lines per file. Longer files consume more context and reduce adherence, and Claude Code shows a warning at startup and in /status when a file passes the recommended length. If Claude keeps ignoring a rule you did write down, the file is probably too long and the rule is getting lost.
Read more (1)Show less
Three cheap habits help. Block-level HTML comments are stripped before the file reaches Claude, so a note explaining why a rule exists costs no context. Emphasis works only when it is rare: mark many lines IMPORTANT and none stands out. And for a checked-in file, /doctor proposes cuts for content Claude can derive from the code, while /doctor prompt-audit looks for stale or conflicting instructions.
The real config behind this lesson
Excerpts from the repository that builds and deploys this website, quoted as they are.
## Hard rules — build breaks if violated
1. **`messages/en.json` and `messages/id.json` must have the exact same key tree.** Missing key in either file → runtime error.
2. **No `{`, `}`, or `<` in blog `content.*` JSON values.** The merge script rejects them. Put markup in JSX; put ICU interpolation only in non-blog UI strings.
3. **Every slug in `BLOG_POSTS_STATIC` must have an entry in `BLOG_META` (and vice versa).** `assertBlogParity()` fails the build otherwise.
4. **Every component key read in a blog component must exist in the translation fragment.** The merge script validates this.
5. **Always import `Link`, `useRouter`, `usePathname` from `@/i18n/navigation`, not from `next/link` or `next/navigation`.** Bare Next.js navigation loses the locale prefix.Five rules, one line each, and each says what breaks. That is the docs' advice in practice: concrete enough to check, short enough to read every session. Rules 2 to 4 also name their backstop, the merge script or assertBlogParity(), so the rule holds even on a day Claude misreads it.
npm run dev # Turbopack dev server → http://localhost:3000
npm run deck # regenerate public/Matthews-Wong-Profile.pdf (the 16:9 profile deck)
cd video && npm run film:intro # re-render the home page's parallax intro film (see video/README.md)
npm run build # Production build — runs assertBlogParity(), typecheck implicit
npm run lint # ESLint
npm run posts:stale # which posts are going stale, flagship topics first
npx tsc --noEmit # Explicit typecheck without buildingThe Commands block: the first thing in the file after the stack table. It lists commands Claude cannot guess, such as this repo's own deck and film renders, and each comment says what the command is for, so Claude picks the right one without reading package.json first.
`npm run build` runs a `prebuild` step that fails if `lib/blog-sources.json` is
stale — regenerate with `npm run sources:build` after editing any sources block.A gotcha written down once. Without these two lines, Claude would see the build fail after editing a sources block and have to work out on its own that lib/blog-sources.json is generated. The line tells it the cause and the fix together.
Mistakes that cost real time
Treating CLAUDE.md as a policy engine
A line like "never edit .env" in CLAUDE.md is a request. Claude usually follows it, but nothing stops the call. Anything that must hold every time needs a permission deny rule or a PreToolUse hook; the next lesson covers the rules.
Two layers that contradict each other
Files are concatenated, not ranked, so "use npm" in your user file and "use pnpm" in the project leave Claude to choose. Remove the contradiction instead of hoping the load order settles it.
Splitting into imports to save context
Every @import loads at launch, so a long file split five ways costs exactly what it did before. Move rules for one folder into .claude/rules/ with paths frontmatter, and procedures into skills.
What I'd change here: the length
This repo's CLAUDE.md runs past 500 lines, well over the 200-line target. About 135 of them, under "Adding a blog post", repeat procedures that already live in the publishing-blog-posts and drawing-blog-diagrams skills. Moving them out would leave the facts and the hard rules in the always-loaded file.
| CLAUDE.md | Path-scoped rule | Skill | Hook | |
|---|---|---|---|---|
| When it loads | Every session, at launch | When Claude touches a matching file | When invoked, or when Claude finds it relevant | Runs on its event; adds no context unless it returns output |
| Best for | Commands, conventions, gotchas | Rules for one folder or file type | Procedures and reference material | Checks that must run every time |
| Enforced? | No: it is context | No: it is context | No: Claude applies it | Yes: it always fires |
Do it on your own machine
You need Claude Code and any git repository you can experiment in. Ten minutes, nothing to install.
Run /init in a practice repo. If a CLAUDE.md already exists, /init suggests improvements instead of overwriting it. Then delete every line Claude could work out by reading the code.
/initRewrite vague rules as checkable ones, and leave a note for humans in an HTML comment. Comments are stripped before Claude reads the file.
- Run `npm test` before committing - API handlers live in `src/api/handlers/` <!-- why: the API tests need a local Redis -->Move a rule that only matters for one folder into a path-scoped rule. It loads only when Claude reads or edits a matching file.
mkdir -p .claude/rules cat > .claude/rules/api.md <<'EOF' --- paths: - "src/api/**/*.ts" --- - All API endpoints must include input validation EOFCreate a subfolder CLAUDE.md from your shell, not through Claude, so you can watch it load later.
mkdir -p src/api && touch src/api/app.ts echo '- Use the shared error format in src/api/errors.ts' > src/api/CLAUDE.mdStart a new session and run /context. The root CLAUDE.md is under Memory files and src/api/CLAUDE.md is not. Ask Claude to read src/api/app.ts and watch a Loaded line appear.
/context
Three questions before you move on
Pick an answer to see why it is right or wrong. Nothing is saved or graded, so guess freely.
Answer in your head, then check
1.Your ~/.claude/CLAUDE.md says "use npm" and the project's CLAUDE.md says "use pnpm". Which wins?Show the answer
Answer:Neither overrides the other. Both are concatenated, with the project file read later, and the docs warn that Claude may pick either. Remove the contradiction instead of relying on order.
2.You split a 600-line CLAUDE.md into five @imports. Did you save context?Show the answer
Answer:No. Imported files load at launch, the same as inline text. To defer loading, use path-scoped rules or skills.
3.An instruction seems lost after /compact. Where did it probably live?Show the answer
Answer:It was given only in conversation, or it sits in a subfolder CLAUDE.md or a path-scoped rule that has not loaded again yet. The project-root CLAUDE.md is re-read from disk after compaction.
4.Claude must never edit .env. Is a line in CLAUDE.md enough?Show the answer
Answer:No. CLAUDE.md is context, not enforcement. Use a permission deny rule or a PreToolUse hook, which Claude Code applies whatever Claude decides.
Related deep dives on this site
Sources
Primary sources checked on the research date. Follow them for the current version.
- Claude Code docs: choose where to put CLAUDE.md files
- Claude Code docs: how CLAUDE.md files load
- Claude Code docs: import additional files
- Claude Code docs: path-specific rules
- Claude Code docs: my CLAUDE.md is too large
- Claude Code docs: write an effective CLAUDE.md
- Claude Code docs: CLAUDE.md vs skills vs hooks
- Claude Code docs in Indonesian: how Claude remembers your project