Vault / wiki/201/claude-code-settings.md
updated 2026-05-28Claude Code Settings & Permissions
settings.json controls permissions, env vars, hooks, MCP servers, output format, and model selection.
File locations (precedence: top wins)
- Command-line flags
<repo>/.claude/settings.local.json— local-only, gitignored<repo>/.claude/settings.json— project-shared, committed~/.claude/settings.json— user-global- Enterprise managed settings
Shape
{
"model": "claude-opus-4-7",
"permissions": {
"allow": [
"Read(./**)",
"Bash(npm test:*)",
"Bash(git status)",
"Bash(git diff:*)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(git push --force:*)"
]
},
"env": {
"ANTHROPIC_API_KEY": "${env:ANTHROPIC_API_KEY}"
},
"hooks": {
"PreToolUse": [...],
"PostToolUse": [...]
}
}
Permission match rules
- Permission strings:
Tool(arg-pattern). - Arg pattern: glob-like (
Bash(npm test:*)matches anynpm test ...invocation). denyis evaluated first. A denied call never proceeds.allowskips the user-confirmation prompt.- Anything not allowed nor denied → user is prompted.
Useful patterns
CI / non-interactive:
{"permissions": {"allow": ["*"], "deny": ["Bash(rm:*)", "Bash(git push:*)"]}}
Combine with claude --print so unattended runs don't block on prompts.
Read-only review:
{"permissions": {"allow": ["Read(./**)", "Grep(*)", "Glob(*)"], "deny": ["Edit(*)", "Write(*)", "Bash(*)"]}}
Per-project tools:
{"permissions": {"allow": ["Bash(./scripts/deploy.sh:*)", "Bash(make:*)"]}}
Output format (for scripting)
claude -p "task" --output-format json returns a JSON envelope you can pipe. --output-format stream-json for streaming events.
CCA-F angle
The exam tests where to put a permission so it applies in CI but not locally (or vice versa), and how to safely auto-approve a narrow set of tools without opening the floodgates. Memorize the precedence order and that deny always wins.