The master table
| Subsystem | Resolution model | Who wins | Deterministic? |
|---|---|---|---|
Memory files (CLAUDE.md, CLAUDE.local.md) |
Additive, all concatenated | Nobody. Later text has a mild edge | No |
Rules (.claude/rules/) |
Additive, all concatenated | Nobody. Project rules read after user rules | No |
Settings (settings.json) |
Override | Managed > CLI > local > project > user | Yes |
| Skills (name collision) | Shadowing | Enterprise > personal > project | Yes |
| Agents (name collision) | Shadowing | Managed > CLI > project > user > plugin | Yes |
| Output style | Single value | Resolved by the settings hierarchy | Yes |
| Hooks | Additive, all matching hooks run | Everyone. No shadowing | Yes |
| Permissions | Deny wins | An explicit deny beats any allow | Yes |
flowchart TD
START["Two pieces of configuration disagree"] --> T{"What kind?"}
T -->|"Prose:<br/>CLAUDE.md, rules"| PROSE["<b>Both are in context.</b><br/>Model picks — possibly arbitrarily.<br/>➜ Remove the contradiction yourself"]
T -->|"Structured value:<br/>settings.json key"| CFG["<b>Precedence order applies.</b><br/>Managed > CLI > local > project > user"]
T -->|"Same-named skill"| SKL["<b>Personal shadows project.</b><br/>➜ Rename one, or namespace via a plugin"]
T -->|"Same-named agent"| AGT["<b>Project shadows personal.</b><br/>➜ Opposite of skills. Check with /agents"]
T -->|"Permission rules"| PRM["<b>Deny always wins.</b>"]
T -->|"Multiple hooks<br/>on one event"| HK["<b>All of them run.</b><br/>Order is not guaranteed"]
Memory files: there is no precedence engine
This is the most consequential misunderstanding about Claude Code.
All discovered memory files are concatenated into the prompt. They do not
override each other. The discovery order (root → cwd, and CLAUDE.local.md after
CLAUDE.md within a directory) is a reading order, not a priority order.
If two memory files contradict each other, Claude may pick either one. Text read later tends to have a mild edge, and more specific instructions tend to beat more general ones, but neither is guaranteed, and the choice can differ between turns in the same session.
The failure case
~/.claude/CLAUDE.md
- Always write tests before implementation.
./CLAUDE.md
- This is a spike repository. Do not write tests.
What happens: both statements are in context. Claude will comply with one, usually the project file, but not reliably. You will see it write tests roughly one time in five and have no idea why.
Three correct fixes, in order of preference
1. Remove the contradiction. Rewrite the global rule so it never fires here:
- Write tests before implementation unless the project's CLAUDE.md
says otherwise.
This works because you have converted a conflict into a conditional. The model is good at conditionals and bad at silent arbitration.
2. Scope the global rule out of existence. Move it from
~/.claude/CLAUDE.md into ~/.claude/rules/testing.md with a paths: glob so it
only loads for the file types where you actually mean it.
3. Exclude the ancestor file with
claudeMdExcludes. This is the only
true override available for memory, and it is blunt: it removes the whole file,
not one line.
Design principle: keep the layers disjoint. Global memory holds preferences that are true everywhere; project memory holds facts about the project. If you find yourself relying on “the project file should win”, you have already put the wrong thing in the global file.
Rules: additive, with a soft ordering
~/.claude/rules/ loads before .claude/rules/, so project rules are read later
and carry more weight. But both load. “Higher priority” is not “replaces”.
~/.claude/rules/go.md
---
paths: ["**/*.go"]
---
- Use `github.com/pkg/errors` for wrapping.
.claude/rules/go.md
---
paths: ["**/*.go"]
---
- Use standard library `fmt.Errorf` with `%w`. Do not add `pkg/errors`.
Same filename does not cause shadowing. Both are in context, directly contradicting each other. The project rule usually wins because it is read later. Usually.
Fix: your personal rules directory should hold preferences that no project would contradict: how you like explanations, review depth, commit message style. Authoritative technical conventions belong in the project’s committed rules. If a personal rule ever conflicts with a repository standard, delete the personal rule; the conflict is a signal it should never have been global.
Settings: real precedence
Settings are the well-behaved subsystem. A given key resolves to exactly one value.
| File | model |
env.GOFLAGS |
|---|---|---|
~/.claude/settings.json |
"opus" |
"-mod=readonly" |
.claude/settings.json |
"sonnet" |
(unset) |
.claude/settings.local.json |
(unset) | "-mod=mod" |
| Effective | "sonnet", project beats user |
"-mod=mod", local beats user |
Note that resolution is per key, not per file. The user file still supplies any key the higher-priority files don’t set.
Permissions are the exception within settings: they merge rather than
override, and a deny rule beats an allow rule from any scope. An enterprise
deny cannot be overridden at all.
Skills vs agents: opposite directions
The genuinely confusing one.
graph TD
subgraph SK["SKILLS — personal wins"]
S1["Enterprise"] --> S2["<b>Personal ~/.claude/skills/</b>"]
S2 --> S3["Project .claude/skills/"]
end
subgraph AG["AGENTS — project wins"]
A1["Managed"] --> A2["--agents CLI flag"]
A2 --> A3["<b>Project .claude/agents/</b>"]
A3 --> A4["Personal ~/.claude/agents/"]
A4 --> A5["Plugin agents/"]
end
The skills trap
You wrote ~/.claude/skills/deploy/SKILL.md months ago for a side project. You
join a team whose repo ships .claude/skills/deploy/SKILL.md.
Typing /deploy runs yours. Silently. Against their infrastructure.
| Fix | How |
|---|---|
| Rename yours | ~/.claude/skills/deploy-personal/ |
| Package the team’s as a plugin | Becomes /platform:deploy, namespaced, cannot collide |
| Audit before trusting | Run /skills (or /help) in a new repo and look for names you recognise |
For agents the direction is reversed, so a project agent correctly overrides your
personal one of the same name, which is usually what you want. Verify with
/agents.
The practical rule: never give a personal skill a generic name. deploy,
review, test, commit, release and build are all names a repository is
likely to claim. Prefix yours.
Output style: last write wins, via settings
outputStyle is a single settings key, so the settings hierarchy applies. A
project-level outputStyle overrides your personal one.
Two subtleties:
- The change only takes effect after
/clearor a new session, because the system prompt is assembled at session start. Setting it mid-conversation and seeing no change is expected, not a bug. - A custom output style with
keep-coding-instructions: falseremoves the built-in engineering instructions. This is not a conflict the model arbitrates; the text is simply gone. If Claude suddenly stops verifying its work after you add a custom style, this is why.
Hooks: everybody runs
There is no precedence. All hooks matching an event execute. A PreToolUse hook
from your settings, one from the project settings, and one from a plugin will all
fire.
- Order is not guaranteed. Never write two hooks that depend on running in a particular sequence.
- Any one of them can block. A single non-zero exit is enough.
- They compose badly if they mutate the same file. Two
PostToolUseformatters on the same path will fight.
The interaction that catches everyone
Layers can conflict across subsystems, not just within one. The resolution is by mechanism strength, not by scope:
| Conflict | Winner | Why |
|---|---|---|
CLAUDE.md says “always run gofmt” vs. a PostToolUse hook that runs gofumpt |
Hook | Deterministic beats probabilistic. Claude’s own attempt is then overwritten |
CLAUDE.md says “you may edit migrations” vs. a PreToolUse hook blocking migrations/ |
Hook | The tool call never executes |
A rule says “use Bash freely” vs. permissions.deny on Bash(rm *) |
Permission | Deny is enforced outside the model |
| A subagent’s system prompt vs. your CLAUDE.md | Both apply | Custom subagents load CLAUDE.md. Explore and Plan do not |
| An output style vs. CLAUDE.md | Both apply | Different parts of the prompt; if they contradict, you are back to the additive case |
A conflict-resolution checklist
When Claude does something you didn’t expect:
/context. Was the instruction even loaded? Half of all “Claude ignored my rule” cases end here./memory. Is there a second memory file saying the opposite? Check ancestor directories, which is where the surprises live./agentsand/skills. Is a personal definition shadowing the project’s?- Check
settings.local.json. A value you set once and forgot outranks the committed project file. - Check plugin hooks. Enabled plugins contribute hooks you did not write.
- Only then conclude the model made a judgement call.