.claude/settings.json is the configuration file that controls how Claude Code behaves in a workspace. It governs permissions, hooks, environment variables, the default model, sandbox boundaries, and a long tail of operational toggles. This article is the full reference: every top-level key, what it accepts, the precedence order between user / workspace / managed scopes, and worked examples for the patterns you will actually use.
If you have never opened settings.json before, start with Your First Claude Code Workspace for the basics. This article assumes you know what the file is and want to know what every field does.
Where settings.json lives — three scopes
Claude Code reads settings from several locations and merges them, with later sources overriding earlier ones. The full precedence order, lowest to highest:
- User settings —
~/.claude/settings.json— applies to every workspace on this machine - Shared workspace settings —
.claude/settings.json— committed to the repo, applies to anyone using this workspace - Local workspace settings —
.claude/settings.local.json— gitignored by convention, your personal overrides for this workspace - Command-line arguments —
--model,--permission-mode— override everything for that one session - Managed settings — pushed by IT in enterprise deployments — cannot be overridden
Practical implication: put team conventions in the shared settings.json (committed), put your personal preferences in settings.local.json (gitignored), and let your global ~/.claude/settings.json hold defaults that apply everywhere.
Top-level keys
| Key | Type | Purpose |
|---|---|---|
permissions | object | allow / deny / ask rules and the default permission mode |
hooks | object | event-driven shell scripts (PreToolUse, PostToolUse, etc.) |
env | object | environment variables exposed to Bash and shell tools during the session |
model | string | default model alias or full model ID |
sandbox | object | filesystem and network isolation rules |
statusLine | string / object | custom status bar format |
enabledPlugins | array | which Claude Code plugins to load |
extraKnownMarketplaces | array | additional plugin sources beyond defaults |
contextCompactionThreshold | number | % of context window before auto-compaction triggers |
effortLevel | string | adaptive reasoning budget (e.g. low / medium / high) |
cleanupPeriodDays | number | how long session history is retained locally (default 30) |
apiKeyHelper | string | command that returns an API key (for non-OAuth auth) |
enabledMcpjsonServers / disabledMcpjsonServers | array | selectively enable / disable MCP servers from .mcp.json |
remoteControlAtStartup | boolean | auto-enable Remote Control on session start |
voiceEnabled | boolean | enable voice input |
agentPushNotifEnabled | boolean | push notifications when sub-agents complete |
disableAllHooks | boolean | kill switch for all hooks (debug or trust scenarios) |
skipDangerousModePermissionPrompt | boolean | suppress the bypassPermissions warning (containers only) |
Several keys are managed-only — they only take effect when set in a managed (enterprise-pushed) settings file: disableBypassPermissionsMode, disableAutoMode, allowManagedHooksOnly, allowManagedPermissionRulesOnly, allowManagedMcpServersOnly, availableModels, modelOverrides. Setting them in user or workspace settings has no effect.
permissions — the rule set
The permissions object is where you pre-approve, pre-deny, or pre-flag specific tool calls. It contains four fields:
{
"permissions": {
"defaultMode": "default",
"allow": [],
"deny": [],
"ask": []
}
}
defaultMode sets the starting permission mode for new sessions. Valid values: default, acceptEdits, plan, auto, dontAsk, bypassPermissions. See Permission Modes Deep Dive for what each does.
allow, deny, and ask take arrays of permission rule strings. Format: ToolName(matcher). Examples:
{
"permissions": {
"defaultMode": "acceptEdits",
"allow": [
"Bash(git status:*)",
"Bash(npm test:*)",
"Bash(npm run build:*)",
"Read(~/Documents/**)",
"WebFetch(domain:github.com)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(curl:*)",
"Edit(/etc/**)",
"WebFetch(domain:*.suspicious-site.com)"
],
"ask": [
"Bash(git push:*)",
"Bash(npm publish:*)"
]
}
}
Evaluation order: deny rules win first (a denied call is blocked even if also allowed), then ask rules (force a prompt even in non-prompting modes), then allow rules. Anything matching no rule falls through to the current permission mode's default behaviour.
Matcher patterns:
:*— wildcard suffix (matches any continuation of the command)**— recursive directory globdomain:example.com— domain match for WebFetchmcp__servername__*— pattern match for MCP tools (servername is the MCP key)
hooks — event-driven scripts
The hooks object maps event names to arrays of hook definitions. Each event can have multiple hook entries; each entry can have one or more matchers and one or more commands to run.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/bash-audit.sh",
"timeout": 30
}
]
}
],
"PreCompact": [
{
"hooks": [
{
"type": "command",
"command": ".claude/hooks/save-checkpoint.sh"
}
]
}
]
}
}
For the full event list, payload schemas, and return contracts, see Hooks — Complete Event Reference.
env — session environment variables
Variables in env are exposed to the Bash tool and any shell command Claude runs during the session. They do not leak into your shell after the session ends.
{
"env": {
"NODE_ENV": "development",
"DEBUG": "true",
"ANTHROPIC_BASE_URL": "https://api.anthropic.com"
}
}
Do not put secrets here
settings.json is often committed to git. Anything you put in env is committed with it. Use apiKeyHelper or a gitignored .env file (loaded via a hook) for actual credentials. settings.json is for non-secret defaults only.
model — default model selection
Set the default model for new sessions in this workspace. Use an alias (recommended) or a full model ID:
{
"model": "sonnet"
}
// or pin a specific version
{
"model": "claude-sonnet-4-6"
}
// or use the 1M-context variant
{
"model": "sonnet[1m]"
}
Override per-session with --model on the command line.
sandbox — filesystem and network isolation
Sandbox rules constrain which paths and network destinations Claude Code can touch, regardless of permission rules. Use to enforce a hard boundary even in auto or bypassPermissions mode.
{
"sandbox": {
"filesystem": {
"readPaths": ["~/projects/myapp/**"],
"writePaths": ["~/projects/myapp/**"],
"denyPaths": ["~/projects/myapp/secrets/**"]
},
"network": {
"allowedDomains": ["github.com", "registry.npmjs.org"]
}
}
}
statusLine — custom status bar
Override the status bar shown at the bottom of the Claude Code panel. Useful when you want to surface workspace identity, current git branch, or context usage.
{
"statusLine": {
"type": "command",
"command": ".claude/scripts/status-line.sh"
}
}
The command's stdout becomes the status line. Refreshes periodically.
contextCompactionThreshold
The percentage of the context window at which auto-compaction kicks in. Default is around 80%. Lower it if you have a PreCompact hook that needs more headroom; raise it if you want to push compaction later.
{
"contextCompactionThreshold": 75
}
See Context Window Management for the full picture.
cleanupPeriodDays — local history retention
Claude Code stores conversation history locally as .jsonl files. After this many days, old session files are cleaned up. Default is 30; raise it if you use PRIMA Memory or another tool that depends on long history.
{
"cleanupPeriodDays": 90
}
apiKeyHelper — non-OAuth authentication
Path to an executable that prints an API key on stdout. Used when Claude Code should authenticate with a key from your password manager, secret store, or vault rather than OAuth.
{
"apiKeyHelper": "/usr/local/bin/get-anthropic-key"
}
The command runs each time Claude Code needs to authenticate. Useful for shared machines, CI environments, and key-rotation workflows.
enabledMcpjsonServers / disabledMcpjsonServers
By default Claude Code loads every server defined in .mcp.json in the workspace. These two arrays let you selectively enable or disable specific servers without editing .mcp.json itself — handy when one workspace's MCP config is shared across people who want different active servers.
{
"enabledMcpjsonServers": ["filesystem", "github"],
"disabledMcpjsonServers": ["expensive-api-server"]
}
Worked example — a typical workspace settings.json
{
"permissions": {
"defaultMode": "acceptEdits",
"allow": [
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(npm test:*)",
"Bash(npm run build:*)",
"Bash(npm run lint:*)",
"Read(./**)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(git push --force:*)",
"Edit(.env)",
"Edit(.env.local)"
],
"ask": [
"Bash(git push:*)",
"Bash(npm publish:*)"
]
},
"hooks": {
"PreCompact": [
{
"hooks": [
{ "type": "command", "command": ".claude/hooks/save-checkpoint.sh" }
]
}
]
},
"env": {
"NODE_ENV": "development"
},
"model": "sonnet",
"contextCompactionThreshold": 75
}
Validation and debugging
If Claude Code starts behaving unexpectedly after a settings change, validate the JSON syntax first — a missing comma silently breaks the entire file. Paste contents into jsonlint.com, or use cat .claude/settings.json | jq . in a terminal. Either tells you the exact line of any error.
To see what settings are actually in effect (the merged result of all scopes), run /config in a session. This shows the resolved values rather than what's in any single file.
What lives outside settings.json
Two things you might expect to be in settings.json but are not:
- MCP server definitions — these go in
.mcp.jsonat the workspace root, or~/.claude.jsonglobally. settings.json only enables / disables them. - CLAUDE.md and rules files — these are loaded as instruction context, not configuration. They live in
.claude/CLAUDE.mdand.claude/rules/*.md.
settings.json is for behavioural and operational configuration. Instructions to Claude itself go in CLAUDE.md.
