Most of Claude Code's behavior is controlled by a few JSON files: which commands it can run without asking, which files it must never read, which hooks fire, and which model it uses. Here's where they live and what to put in them.
| File | Scope | Commit it? |
|---|---|---|
~/.claude/settings.json | You, in every project | No, it's personal |
.claude/settings.json | This repository, for everyone | Yes, it's shared team config |
.claude/settings.local.json | This repository, only you | No, add it to .gitignore |
When the same setting appears in more than one place, the more specific file wins: local project settings override shared project settings, which override your user settings. Organizations can also deploy managed policy settings that override everything. Command-line flags apply to the current session only.
Run /config or /permissions inside Claude Code to view and edit these interactively.
{
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test:*)",
"Bash(git status)",
"Bash(git diff:*)"
],
"ask": [
"Bash(git push:*)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(curl:*)"
]
},
"env": {
"NODE_ENV": "development"
},
"hooks": {
"PreToolUse": [
{ "matcher": "Bash",
"hooks": [ { "type": "command", "command": "python3 \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/guard-bash.py" } ] }
]
}
}
allow: tool uses that run without a prompt.ask: always prompt, even if a broader allow rule matches.deny: never allowed. Deny rules win over allow rules.Rules look like Tool or Tool(specifier):
Bash(npm run lint) matches that exact command.Bash(npm run test:*) matches any command that starts with npm run test. The :* suffix is a prefix match.Read(./.env) and Edit(./src/**) take gitignore-style path patterns.WebFetch(domain:docs.example.com) limits fetches to a domain.Prefix rules for Bash are convenient but coarse. Be careful allowing things like Bash(git:*), which also covers git push --force. See the permissions guide for a sensible starting allowlist.
Environment variables set for every session, and inherited by commands Claude runs. Good for non-secret switches like NODE_ENV or a feature flag for local development. Don't put API keys in a committed .claude/settings.json. Keep them in your shell environment or a secrets manager.
Commands that run on events such as PreToolUse, PostToolUse, Notification and Stop. A hook that exits with code 2 before a tool runs blocks it. See 6 practical hook examples.
Sets the default model for sessions, for example "model": "sonnet". You can switch any time with /model. It's usually better set per person in ~/.claude/settings.json than forced on the whole team.
.claude/settings.json: deny rules for secrets, allow rules for the project's own lint and test commands, and safety hooks. Everyone benefits, and changes are reviewed in pull requests.~/.claude/settings.json: your model preference, notification hooks, and read-only commands you're comfortable auto-approving everywhere..claude/settings.local.json: one-off experiments you don't want to commit. Claude Code writes here when you choose "don't ask again" for a command in a project.:* prefix form for commands with arguments./hooks to see what's registered, and test the script by piping JSON into it.Keelwork bundles 10 workflow skills, 5 tested safety hooks (including a full guard-bash and a secret scanner), 3 subagents and 5 CLAUDE.md templates, with a one-command installer that safely merges into your settings.
Get Keelwork — $24 →