A Claude Code config is project-specific by design. Seven anchor points bind it to your tree.
Most guides treat CLAUDE.md as a portable artifact: paste a template, share it across projects, done. That framing misses the load-bearing detail. A real CLAUDE.md is a contract with the project tree it sits in. It names paths, scripts, hooks, MCP servers, slash commands, and past incidents that only exist inside one specific repo. Copy it to another repo and the agent dutifully reads seven kinds of lines that resolve to nothing, and then improvises around them. Below: what those seven anchor types are, what breaks on copy, and where each rule actually belongs.
1. Seven anchor types that bind a config to its tree
Every concrete rule in a real CLAUDE.md ends up looking like one of these eight rows. The first column is the shape of rule. The second is what happens when you copy the file to a different project. The third is where the rule actually belongs.
| Feature | Where the rule actually belongs | What happens when you copy this rule to a new repo |
|---|---|---|
| Karpathy-style rubric rules (plan first, ask if unclear, tests as truth) | Mostly portable. They are about how to think, not what to touch. | Move to ~/.claude/CLAUDE.md once; let every project inherit them. |
| Stack names (Next.js, Postgres, Django, Rust) | Project-specific by definition. Wrong stack = wrong agent behavior. | Belongs in ./CLAUDE.md of this repo only. |
| File path references (scripts/release.sh, ./api/, ./packages/web) | Breaks on copy. The new tree may not have the path at all. | Belongs in ./CLAUDE.md or a nested subdir CLAUDE.md. |
| MCP allowlist references ('use the Stripe MCP', 'pglocal MCP only') | Breaks on copy. .claude/settings.json in the new repo does not list those servers. | Lives in .claude/settings.json, referenced from project CLAUDE.md. |
| Hook commands ('pre-commit-lint', 'run npm test before commit') | Breaks on copy. Hook binaries may not exist in the new tree. | Configure in .claude/settings.json hooks block. Do not duplicate in CLAUDE.md. |
| @import targets (@./.claude/style.md, @./docs/conventions.md) | Breaks on copy. Anthropic memory docs: 'imports expand inline at launch.' Missing target = silent skip. | Either commit the imported file too, or inline the rules. |
| Past-incident references ('we got burned on the staging migration in Q3') | Breaks on copy. Different repo, different incidents. | Either rewrite for this project or move to a personal CLAUDE.local.md. |
| Slash-command references ('/release', '/ship-pr') | Breaks on copy. .claude/commands/ directory not duplicated. | Copy the .claude/commands/ files too, or remove the slash command references. |
One pattern from the table: only the top row (the framework-agnostic rules) actually transfers. Every other row is a project anchor. A guide that tells you to "share your CLAUDE.md template across repos" is true for the first row and wrong for the rest. The fix is not to make your file more abstract, it is to stop treating one file as the home for two different kinds of rules.
2. The clearest evidence: ccmd's cache_bust detector
The reason ccmd's analyzer flags timestamps and session strings is the same reason a config does not transfer cleanly. Open src/lib/analyzer.ts and read lines 193 to 203:
The detector hits on ISO dates, "today", "this session", and "right now" in the first 20 lines. Severity is high because prompt caches need byte-identical prefixes; a timestamp at the top guarantees a cache miss on every new session. The deeper reason the detector exists is that those strings are the purest marker of project coupling. A line that says "today is 2026-05-17 and we are mid-sprint on the subscriptions rewrite" is bound to one repo on one date. It cannot survive a copy. Neither can the rules it sits above, because the agent has just been told the context is wrong.
3. A worked example: copying CLAUDE.md from one repo to another
A realistic ./CLAUDE.md from a Next.js + Stripe payments repo, dropped wholesale into a fresh Python analytics worker. Run the analyzer against the new copy and this is what comes back:
Seven of fifty-eight lines silently break. The agent reads them anyway; nothing throws an error. The remediation is not a smarter template. The remediation is to recognize that CLAUDE.md is a per-repo contract, write it for this repo, and reach for the user file or a skill when you need to share something across repos.
4. Where each rule actually belongs: a seven-step placement audit
Run this on a current project and on any CLAUDE.md you are tempted to copy. The goal is one rule, one file, one fire rate that matches the rule's scope.
1. Open ~/.claude/CLAUDE.md and ask: 'Would this rule fire on every repo on this machine?'
If yes, it belongs here. Karpathy's 12 rules, your personal preferences ('terse responses', 'no em dashes'), output style, language. If the rule names a framework, a script path, or a teammate, it does not belong here.
2. Open ./CLAUDE.md (project root) and ask: 'Would this rule fire on every session in this repo?'
Stack names, the database, the deployment target, the company-wide forbidden patterns. The rule that says 'we use Stripe + Postgres, not Lemonsqueezy + Mongo' lives here. Not in the user file. Not in a subdir file.
3. Create subdir CLAUDE.md only for rules that fire conditionally
./api/CLAUDE.md only loads after Claude first reads a file inside ./api/. Migration rules, request-shape rules, error-mapping rules belong here. Anthropic memory docs: subdirectory CLAUDE.md is hierarchical and loads on demand.
4. Move executable contracts (hooks, MCP allowlist) to .claude/settings.json
A rule that says 'always run npm test before commit' is a hook. Write the hook in settings.json so the harness enforces it; do not write a rule in CLAUDE.md that asks the agent to remember to do it. CLAUDE.md is for instructions the harness cannot enforce.
5. Move repeatable workflows to .claude/commands/ or skills
A 600-token release runbook in ./CLAUDE.md fires every turn of every session. Move it to .claude/commands/release.md (slash command) or a skill. It loads only when invoked. Same content, fraction of the per-turn cost.
6. Use ./CLAUDE.local.md for personal overrides you do not commit
Your machine paths, your personal style, your unfinished refactor notes. Anthropic memory docs flag it as 'machine-only, not shared with the repo.' Add it to .gitignore. Do not let your incident notes leak into the team config.
7. Re-paste each file into the analyzer and check the cache_bust line
Any ISO date or 'today is...' in the first 20 lines of ANY file resets prompt cache on every new session. analyzer.ts:194 catches it; the fix is to move volatile text to the bottom of the file or remove it. This is the single most common project-coupling mistake we see.
After this exercise most teams end up with a much smaller ./CLAUDE.md (a few stack lines, the company-wide forbidden patterns, a pointer to the slash commands) and a much larger .claude/commands/ and .claude/settings.json. That redistribution is the actual portable shape: framework-agnostic discipline lives in your user file, executable contracts live in settings, project-specific facts live in the project files. Nothing tries to be two things at once.
5. So what is actually portable across projects?
The rules that survive a copy are the ones that say something true regardless of stack or tree. Karpathy's 12 rules. Your own output-style preferences. The forbidden-pattern list a senior engineer would write for any junior engineer (don't commit secrets, don't guess at unfamiliar APIs, ask before destructive operations). The ccmd analyzer's Karpathy-12 check at src/lib/analyzer.ts lines 49 to 122 enumerates them; nine of those twelve are pure discipline rules and transfer cleanly between projects.
That portable layer lives in ~/.claude/CLAUDE.md. Write it once, audit it against the 12-rule rubric, and let every project on your machine inherit it. The portable part is small; that is correct. The project-specific part is large; that is also correct. The mistake we see most often is teams trying to make the project-specific file portable by stripping out the path and stack references that made it useful in the first place. What is left is a file that fires on every turn and says nothing the user file did not already say.
Want a second pair of eyes on what should move where?
15 minutes, we open your user file, your project files, and your .claude/settings.json together, and rehome the rules whose anchor type does not match where they live. Free.
Frequently asked questions
How do I make a Claude Code config project-specific?
Put project rules in ./CLAUDE.md (committed, shared with the team), ./CLAUDE.local.md (your machine, gitignored), .claude/settings.json (hooks and MCP allowlist), .claude/commands/ (slash commands), and any subdirectory CLAUDE.md for narrower scope. Anthropic's hierarchical memory lookup loads each of these on every turn that touches the tree. The user-level ~/.claude/CLAUDE.md is global to your machine, not project-specific; rules that name a stack, a script, or a path do not belong in it.
Can I just copy CLAUDE.md from one project to another?
You can, and the agent will not complain. But the file is silently broken. Anthropic memory docs are explicit that @import targets expand inline at launch; a missing target is a silent skip. The same is true for path references, hook commands, MCP server names, and incident anecdotes. The rules that survive a copy are the framework-agnostic ones (plan first, ask if unclear). The rest of the file is dead weight in the new tree until you rewrite it.
What is the difference between ./CLAUDE.md and ./CLAUDE.local.md?
./CLAUDE.md is shared with the repo. Every collaborator who clones gets it, and it ships through to CI Claude runs too. ./CLAUDE.local.md is gitignored by convention; it loads on your machine only. Use ./CLAUDE.local.md for unfinished refactor notes, personal style ('I prefer terse responses'), or machine paths that are not portable. Both files load on every turn in this repo; the only difference is whether the team sees them.
Does ~/.claude/CLAUDE.md count as project-specific?
No. It is machine-wide. It fires on every repo on your machine, on every turn. Rules that belong there are about you (your name, your editor preferences, your global style) or about how you think (Karpathy rubric, plan-before-coding). A rule that says 'we use Postgres on Neon' in your user file fires in every repo you open, including the ones where you use Postgres on Supabase. ccmd's analyzer catches misplaced rules with the Karpathy-9 stack-awareness check at analyzer.ts:99.
Where do MCP server allowlists and hooks live?
.claude/settings.json (in the project root) is where MCP allowlists, hook commands, and harness-enforced settings live. CLAUDE.md is prose the agent reads; .claude/settings.json is a contract the harness enforces. A rule in CLAUDE.md that says 'always use the Stripe MCP' only works if Stripe is in the .claude/settings.json allowlist of this project. Copying CLAUDE.md does not copy the allowlist. The agent will read the instruction, fail to find the tool, and improvise. That improvisation is the source of the most expensive surprises we have audited.
Why does Claude ignore some rules in a copied CLAUDE.md?
Three common reasons specific to a copy. First, an @import line whose target does not exist in the new repo is silently dropped, so any rules in the imported file are simply absent. Second, the stack-aware Karpathy rule 9 check fails: the file says 'we use Next.js' but the new repo is a Python worker, and the agent now has a self-contradictory context, so it tends to follow the more recent message instead. Third, project-specific commands referenced in CLAUDE.md (like '/release' or '/ship-pr') resolve to nothing, and the agent invents a workflow on the fly. We wrote a more detailed analysis at /t/why-claude-skips-claudemd-rules.
What is the cache_bust anchor and why does it matter for project-specific configs?
ccmd's analyzer flags any ISO date or 'today is' or 'this session' string in the first 20 lines of a config file (see src/lib/analyzer.ts line 194). The detector exists because prompt caches only hit on byte-identical prefixes. A timestamp in the first 20 lines means every new session rewrites the prefix, every turn re-bills the full file at full input cost, and that the rule body itself is bound to a specific date in a specific project. It is the most common project-coupling mistake. Move volatile text to the bottom of the file, or remove it.
Related: the multi-file token budget, why Claude skips some rules, the 12-rule audit your file gets graded on, or paste a file on the analyzer.
Comments (••)
Leave a comment to see what others are saying.Public and anonymous. No signup.