.claude/settings.json
Claude CodeDefinition
The Claude Code settings file that configures tool permissions, hook scripts, environment variables, and behavioral settings. Project-scoped (.claude/settings.json) checked into version control, or user-scoped (~/.claude/settings.json) for personal preferences. Hooks are defined here.
Example Usage
Define PreToolUse hooks in .claude/settings.json to enforce code quality gates before Claude writes any files.
Why It Matters for the Claude Certification Exams
CCA-F and CCDV-F both test where a control belongs: CLAUDE.md (instructions) versus settings.json (enforced config), and which settings file (user, project, local) a team should commit. A team-wide tool deny list belongs in committed .claude/settings.json, not in CLAUDE.md and not only in ~/.claude/settings.json.
In Depth
.claude/settings.json is Claude Code's machine-readable settings file. CLAUDE.md is natural-language memory the model reads; settings.json is what the harness executes: permissions, hooks, environment variables, and other structured keys. Putting a hook command in CLAUDE.md is a common miss — Claude can read it, the harness will not run it.
File locations and who they affect
Claude Code reads settings from four files on your machine (and an organisation can add managed settings):
| Scope | File | Who it affects |
|---|---|---|
| User | ~/.claude/settings.json | You, in every project on this machine |
| Shared project | .claude/settings.json | Everyone working in that folder; commit it so teammates get it |
| Project local | .claude/settings.local.json | You, in this one project. Claude Code keeps it out of git when it creates the file |
| Managed | managed-settings.json and other managed sources | Everyone your organisation deploys it to |
On Windows, ~/.claude means %USERPROFILE%\.claude. Official reference: Claude Code settings files and precedence.
User file is for personal defaults: theme, editor mode, your own permission extras. Do not put team deny-lists here — new hires will never see them.
Shared project file is the team contract. Commit .claude/settings.json so every clone gets the same allow/deny rules, hooks, plugins, and project env. Treat a change to it like a code change: review it.
Project local file is the personal override for one repo. Use it to test a permission before you share it, or to set a model you prefer without changing teammates' sessions. If you create .claude/settings.local.json by hand, add it to .gitignore yourself; when Claude Code creates it, it writes a global git exclude.
Managed settings are organisation policy. Nothing in your own files overrides a managed key.
Precedence (highest first)
When the same key appears in more than one place, Claude Code uses the highest level that sets it:
- Managed settings
- Command-line
--settingsJSON for that session - Project local (
.claude/settings.local.json) - Shared project (
.claude/settings.json) - User (
~/.claude/settings.json)
So a teammate's committed project file overrides your user defaults in that repo, and your local file overrides the committed project file for you only. List keys such as permissions.allow merge across files instead of replacing each other, so each scope can add entries.
The `permissions`, `hooks`, and `env` keys
permissions:allow,ask, anddenyrules for tools (Read, Write, Bash, and others). Team-wide deny rules belong in the committed project file. Standing "don't ask again" approvals that Claude Code writes for you land in the local file.hooks: lifecycle scripts —PreToolUse,PostToolUse,Stop,SubagentStop. Always registered here, never in CLAUDE.md. See Hooks (Claude Code).env: environment variables injected into the session (non-secret project config). Anenvblock inside a settings file is an ordinary key and follows the precedence stack above.
Settings files are strict JSON: comments and trailing commas are syntax errors.
See also: CLAUDE.md. Related: CLAUDE.md Configuration Hierarchy.
Example
Minimal project .claude/settings.json: shared permissions, a PostToolUse hook, and a non-secret env value.
{
"permissions": {
"allow": ["Read", "Write", "Bash"],
"deny": ["Bash(rm -rf *)"]
},
"hooks": {
"PostToolUse": ["npm test -- --passWithNoTests --silent"]
},
"env": {
"NODE_ENV": "development"
}
}How It's Tested & Common Confusions
Where does this control live? Scenarios ask you to pick CLAUDE.md, project settings.json, user settings.json, or settings.local.json.
- "Every developer must be blocked from
rm -rf" → committed.claude/settings.json(shared deny list) - "I want Opus in this repo without changing the team default" →
.claude/settings.local.json - "Set my editor theme on every project on this laptop" →
~/.claude/settings.json - "Explain the service map to Claude" → CLAUDE.md, not settings.json
Hook placement is another tested distinction: hooks are defined in settings.json even when the script itself lives elsewhere.
Frequently Asked Questions
Can I put hooks in CLAUDE.md instead of settings.json?
No. Hooks are executable commands and must be configured in settings.json where the harness can read and execute them. CLAUDE.md is read by the model for natural-language context; it cannot register lifecycle callbacks.
Which settings file wins when the same key is set in more than one place?
Highest first: managed organisation settings, then --settings on the CLI, then .claude/settings.local.json, then committed .claude/settings.json, then ~/.claude/settings.json. Your local file overrides the shared project file for you only; the shared project file overrides your user defaults in that repo. List keys such as permissions.allow merge across files.
What is .claude/settings.local.json for?
Personal overrides for one project: a model you prefer, a permission you are testing, or a standing approval Claude Code saved when you chose "don't ask again". It should stay out of git. Team permissions and hooks belong in committed .claude/settings.json.