Claude Code · September 2026

Claude Code settings, file by file

Where each settings.json lives, which one wins, the keys worth knowing, and examples you can copy — checked against the current settings reference.

The files and who they affect.

Claude Code reads settings from JSON files at four scopes, plus a managed source an organization can deploy. Precedence, highest first: managed, then --settings on the command line, then project local, then shared project, then user.

ScopePathApplies to
Managed/Library/Application Support/ClaudeCode/managed-settings.json on macOS, /etc/claude-code/managed-settings.json on Linux and WSL, C:\Program Files\ClaudeCode\managed-settings.json on Windows — or an MDM profile, or server-managed settings from the claude.ai consoleEveryone the organization deploys it to; nothing below overrides it
Command lineclaude --settings <file-or-json>That session only; overrides the files below, never managed
Project local.claude/settings.local.jsonYou, in this project; kept out of version control
Shared project.claude/settings.jsonEveryone working in the repository, once you commit it
User~/.claude/settings.jsonYou, in every project on this machine

Claude Code also keeps ~/.claude.json for itself: sign-in state, MCP server configuration, and per-project trust decisions. You do not edit it. Full detail on the official settings page.

How precedence really works.

A key set at a higher level replaces the same key set lower down, with two exceptions worth knowing. Lists merge rather than override: permissions.allow from your user file and your team’s project file are combined, and a deny rule wins over an allow rule wherever either comes from. And environment variables are not a level in the stack; each variable-and-key pair has its own rule, so ANTHROPIC_MODEL exported in your shell beats the model key from any file, while an env block inside a settings file is an ordinary key that follows the levels above.

Two values are scope-limited: permissions.defaultMode of auto or bypassPermissions only takes effect from user settings, managed settings, or --settings, never from the project files a repository could commit. Files are strict JSON — a comment or a trailing comma is reported as a settings error at the next start. Claude Code watches the files and applies most edits, including permissions and hooks, to a running session. /status lists which files loaded; claude doctor lists entries it rejected.

The keys worth knowing.

The settings reference lists every key with its type, default, and scope. These are the ones people actually set.

KeyWhat it doesExample
permissions.allowTool uses that run without a prompt["Bash(npm run *)", "Read(~/.zshrc)"]
permissions.askAlways prompt before these["Bash(git push *)"]
permissions.denyBlock these, including reads of files that hold secrets; beats allow["Read(./.env)", "Read(./secrets/**)"]
permissions.defaultModeMode new sessions start in: default (Manual), acceptEdits, plan, auto, dontAsk, bypassPermissions"plan"
permissions.additionalDirectoriesDirectories outside the working one that Claude may read and edit["~/projects/shared"]
permissions.disableBypassPermissionsModeRemove bypass mode from every session; usually managed"disable"
envEnvironment variables for every session and its subprocesses — provider routing, proxies, telemetry{"CLAUDE_CODE_USE_BEDROCK": "1"}
hooksYour own commands at lifecycle events: PreToolUse, PostToolUse, SessionStart, Stop, and othersSee the team example below
modelModel new sessions start on; --model and ANTHROPIC_MODEL override it"claude-sonnet-5"
availableModelsRestrict what /model and --model may pick["opus", "sonnet"]
effortLevelDefault reasoning effort for models without a saved level of their own"xhigh"
apiKeyHelperA script that returns the API credential, re-run every five minutes by default"~/.config/claude/get-key.sh"
cleanupPeriodDaysDays to keep session transcripts before deleting them; 30 by default20
attributionChange or hide the attribution added to commits and PRs; replaces the deprecated includeCoAuthoredBy{"commit": "Claude Code"}
enableAllProjectMcpServersApprove every server in a project’s .mcp.json without promptingtrue
forceLoginMethod, forceLoginOrgUUIDPin the login method and organization; enforced from managed settings"claudeai"
statusLineA command whose output renders below the prompt{"type": "command", "command": "..."}
outputStyle, languageChange Claude’s role and tone, or have it answer in another language"Spanish"
autoUpdatesChannellatest (the default) or stable, about a week behind"stable"
sandboxIsolate Bash commands from the filesystem and network on macOS, Linux, and WSL2{"enabled": true}
autoMemoryEnabledTurn Claude’s own cross-session notes offfalse
claudeMdExcludesSkip ancestor CLAUDE.md files by glob; useful in monorepos["**/monorepo/CLAUDE.md"]

Permission rules, the syntax.

A rule is a tool name, optionally with a pattern in parentheses. Bash(npm run *) matches any npm script; Bash(git push *) matches pushes; Read(./.env) names one file relative to the project; Edit(docs/**) matches a tree; WebFetch(domain:example.com) scopes a domain; mcp__server__tool names one MCP tool. A bare tool name such as Read matches every use. Rules from every scope are merged, deny beats allow, and an ask rule from a project or managed file outranks an allow you saved locally with “don’t ask again” — which is the usual reason a prompt keeps coming back. The syntax in full is under permission rule syntax.

A personal file is small. The $schema line gives you autocomplete and validation in any editor that understands JSON schema; the rest is preference. This one starts every session on Sonnet in plan mode, follows the stable release channel, keeps transcripts for twenty days, and lets Claude Code run git diff and read your shell config without asking.

{ "$schema": "https://json.schemastore.org/claude-code-settings.json", "model": "claude-sonnet-5", "editorMode": "vim", "autoUpdatesChannel": "stable", "cleanupPeriodDays": 20, "permissions": { "defaultMode": "plan", "allow": ["Bash(git diff *)", "Read(~/.zshrc)"] } }
~/.claude/settings.json

A team file, with a hook.

The shared project file is the one to commit. It carries the permissions everyone should share, the environment the project needs, and hooks — shell commands Claude Code runs at fixed points, which, unlike CLAUDE.md instructions, are enforced regardless of what the model decides. The example below approves npm scripts, always confirms pushes, refuses to read secrets, and runs a script from the repository before every Bash command. Hooks nest three deep: the event, a matcher, and the handlers. Allow rules in a committed file take effect only after each person trusts the folder; deny and ask rules apply regardless.

{ "permissions": { "allow": ["Bash(npm run *)"], "ask": ["Bash(git push *)"], "deny": ["Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)"] }, "env": { "CLAUDE_CODE_ENABLE_TELEMETRY": "1" }, "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.sh" } ] } ] } }
.claude/settings.json — committed with the repository

Settings, CLAUDE.md, and flags.

Three things shape a session and they are easy to conflate. Settings are enforced configuration: permission rules, hooks, and the sandbox apply whatever the model intends. CLAUDE.md is instruction: loaded as context at the start of every session, followed well when it is specific, but not a hard boundary — the docs say so plainly and point you to a PreToolUse hook when something must never happen. Flags are one session’s overrides: --permission-mode beats defaultMode, --model beats model, --allowedTools and --disallowedTools add rules for the run, --add-dir grants directories without persisting them, and --settings layers a file or a JSON string above your files for the session. /config writes a few personal options to the user file, /permissions edits rules, and /hooks shows what is configured.

One practical consequence: all of this lives on the host. The user file, the project files, the transcripts, the remembered approvals — they are on the machine where claude runs, not on the device you are looking at it from. Set a machine up once and every device that reaches it gets the same sessions, the same rules, the same history. That is the shape spawnd is built around: the host does the work and keeps the state, and a browser or a phone is only ever the console.

Start

Set up the host once; every console inherits it.

$curl -fsSL https://spawnd.dev/install.sh | sh
Sign up free
Install the daemon

Questions

Where is the Claude Code settings file?
Personal settings are in ~/.claude/settings.json. Project settings are .claude/settings.json (shared, commit it) and .claude/settings.local.json (yours). Organizations deploy managed-settings.json in a system directory or push settings from the claude.ai console.
Why isn’t my setting taking effect?
Usually a higher scope sets the same key, or the key cannot apply from that file: auto and bypassPermissions in defaultMode only work from user or managed settings. Run /status to see which files loaded and claude doctor to see rejected entries.
Do settings sync between machines?
No. Settings and transcripts are files on each host. Committing .claude/settings.json shares project rules through git; personal settings stay per machine unless you copy them. Reaching one configured host from several devices is what spawnd is for.