Your Claude Code settings.json, explained
Most of what makes Claude Code feel yours lives in a settings.json: what it is allowed to do without asking, and what runs when it acts. This guide covers where those files live, how they layer, and the two keys you will touch most: permissions and hooks.
Where settings come from
Claude Code layers settings from a few places, most specific winning:
- User settings:
~/.claude/settings.json, applied to every project on your machine. - Project settings:
.claude/settings.jsonin a repository, shared with your team through version control. - Local project settings:
.claude/settings.local.json, for personal overrides you keep out of git. Claude Code adds it to your.gitignorefor you. - Managed settings, deployed by an administrator, which win over everything else.
Because they layer, put team-wide rules in the project file and personal tweaks in your user or local file. When two files set the same key, the more specific one replaces it rather than merging deeply, so keep each file focused on what belongs there.
permissions: what the agent may do on its own
The permissions key controls which actions Claude can take without stopping to ask. It holds lists of rules, typically allow, ask and deny:
{
"permissions": {
"allow": [
"Bash(npm run test:*)",
"Bash(git status)",
"Read(./src/**)"
],
"ask": [
"Bash(git push:*)"
],
"deny": [
"Read(./.env)",
"Read(./secrets/**)",
"Bash(rm:*)"
]
}
}
Each rule names a tool and, in parentheses, a pattern for what it may touch. allow lets matching actions run unattended; ask forces a prompt even in a permissive mode; deny blocks them outright. Anything not covered falls back to asking you, which is where the Notification hook comes in (below).
A few details worth knowing:
- For
Bash, the pattern matches the start of the command, and:*is the wildcard:Bash(npm run test:*)coversnpm run test -- --watch. - For file tools, the pattern is a path glob relative to the project, so
Edit(./src/**)scopes edits to your source tree. denyalways wins overallow, which makes it the right place for secrets.additionalDirectorieslets a session read outside the project root, anddefaultModesets the starting permission mode (default,acceptEdits,plan).
Tighten deny around secrets and destructive commands, and widen allow for the safe, repetitive things (running your test script, reading source) so the agent stops interrupting you for them. That single change is the biggest day-to-day speed-up available.
hooks: run a command on each event
The hooks key runs your own command at each point in a session: start, tool use, needing you, finishing. It is a topic of its own; start with the complete guide to Claude Code hooks and the reference of every hook event. A minimal example:
{
"hooks": {
"Stop": [
{ "hooks": [{ "type": "command", "command": "notify-send 'Claude Code' 'Run finished'" }] }
]
}
}
One gotcha: hooks are snapshotted when a session starts. Edit the file mid-session and the change will not apply until you restart Claude Code or review it from the /hooks menu.
The other keys worth knowing
Beyond those two, a handful of keys earn their place in a real config:
| Key | Does |
|---|---|
model | Pins the model for this project or user. |
env | Environment variables injected into every session. |
statusLine | A command whose output becomes your status line. |
includeCoAuthoredBy | Set to false to drop the co-author trailer from commits. |
cleanupPeriodDays | How long transcripts are kept locally. |
apiKeyHelper | A script that prints the credential to use. |
A realistic file
Putting it together, a project .claude/settings.json that a team can actually share:
{
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test:*)",
"Read(./**)",
"Edit(./src/**)"
],
"deny": [
"Read(./.env*)",
"Bash(rm:*)",
"Bash(git push:*)"
]
},
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "npx prettier --write \"$CLAUDE_PROJECT_DIR\"" }]
}
],
"Stop": [
{ "hooks": [{ "type": "command", "command": "notify-send 'Claude Code' 'Run finished'" }] }
]
},
"includeCoAuthoredBy": false
}
Everyone on the team gets the same guardrails and the same auto-formatting, and each developer can still layer a personal settings.local.json on top for their own notifications.
Editing it without the JSON
You do not have to hand-write any of this. Inside a session, /permissions opens the allow and deny lists, /hooks walks you through adding a hook, and /config covers the rest. They write the same files, so you can start in the menus and tidy the JSON later.
Keep it readable and reviewed
A settings.json grants real power: permissions decide what runs unattended, and hooks run commands automatically. Treat the project file like code: review changes in pull requests, keep secrets in deny, and never paste a settings file you have not read. A malicious allow rule or hook command is indistinguishable from a helpful one until it runs.
Let the awareness part configure itself
Getting the hooks block right so you can see your sessions is fiddly to maintain by hand, especially once several people share the project file. Blooby handles exactly that slice: it merges its own hooks into your settings.json for you (without touching your permissions or overwriting anything) and turns them into a live mascot per Claude Code session. You keep full control of the file; Blooby just adds the part that watches.
See it for yourself
download Get Blooby free