You, everywhere
Preferences that follow you across every project on your machine. Your theme, your personal shortcuts.
You added a permission rule. Nothing changed. You added it again, in a different file. Still nothing. You reinstall, and now you have two problems.
Here is the thing nobody says out loud: your edit probably worked perfectly, and is being overridden by a file you forgot you had. Claude Code reads settings from several places and merges them in a fixed order. Editing the wrong one produces the exact symptom of editing nothing at all.
The multiple files are not an accident, they are the point. Three different people want to configure the same tool and they must not overwrite each other:
You, everywhere
Preferences that follow you across every project on your machine. Your theme, your personal shortcuts.
The team, in this repo
Rules that belong to the project and should be identical for everyone who clones it. Committed to git.
You, in this repo only
Your local overrides for one project — a path that only exists on your machine, a credential you are testing. Never committed.
Your organisation
Managed policy on a company machine. Deliberately unbeatable by the three above.
Once you see it as four audiences rather than four files, the precedence order stops being arbitrary. The more specific the audience, the more it wins — except policy, which wins over everything by design.
From strongest to weakest. The first one that defines a setting is the one that takes effect.
| # | Source | Where it lives | Committed? |
|---|---|---|---|
| 1 | Enterprise managed policy | System-wide managed settings path | Managed by IT |
| 2 | Command line arguments | The flags on the command you just ran | — |
| 3 | Project local | .claude/settings.local.json |
No — gitignored |
| 4 | Project shared | .claude/settings.json |
Yes |
| 5 | User | ~/.claude/settings.json |
No |
Read that table twice, because two rows account for most of the confusion.
Row 3 beats row 4. Your settings.local.json overrides the team file. If a teammate’s
setup works and yours doesn’t, this is the first place to look — you probably created it
weeks ago and forgot.
Row 5 loses to everything. Editing ~/.claude/settings.json to fix a project-specific
problem is the single most common wasted afternoon. It is the weakest file in the chain.
Here is the same thing as a tree, which is how it actually looks on disk:
Ask the session what it loaded.
Do not reason about it. Look at it.
/statusThis is the ground truth. If what you see here differs from the file you edited, you have your answer already and everything below is confirmation.
List every settings file that could apply.
Run this from your project root. It finds all four candidates in one shot.
ls -la .claude/settings.json .claude/settings.local.json ~/.claude/settings.json 2>/dev/nullEvery file that prints is competing for your setting. The ones you did not know about are the interesting ones.
Prove which file defines your key.
Search all of them for the setting you are fighting with. Replace permissions with
whatever you actually changed.
rg -n "permissions" .claude/settings.json .claude/settings.local.json ~/.claude/settings.json 2>/dev/nullIf the key appears in more than one file, the highest one in the precedence table wins — and it is not necessarily the one you edited.
Validate the JSON before you believe the contents.
A malformed settings file can be skipped without a loud complaint, which looks exactly like a file that is being overridden.
for f in .claude/settings.json .claude/settings.local.json ~/.claude/settings.json; do [ -f "$f" ] && { python3 -m json.tool "$f" > /dev/null 2>&1 \ && echo "ok $f" || echo "INVALID $f"; }doneRestart the session.
Some settings are read once, when the session starts. Editing them mid-session and concluding they do not work is a self-inflicted wound. Change the file, start fresh, then judge.
Editing the user file to fix a project problem. The weakest file in the chain. If the project defines the same key, you will never see your change.
Forgetting settings.local.json exists. It is gitignored, so it is invisible in every
diff and every code review. It is also the second-strongest file. That combination is why it
causes so much confusion — it beats the team’s config and leaves no trace in git.
Assuming the whole file is replaced. Settings merge per key, not per file. A key you did not define is inherited from a weaker source, which means the effective config is a blend of several files and matches none of them exactly.
Trusting the file over the session. The file is what you wrote. /status is what was
loaded. When they disagree, the session is right and you are debugging the wrong thing.
Editing on a managed machine. If your organisation ships a managed policy, it wins on purpose. No amount of local editing will beat it, and that is the intended behaviour — not a bug to work around.
/status shows the effective settings, and you compared them to your edit.claude/settings.local.json was checked — it is gitignored and it beats the team file