Claude Code Settings & Permissions: settings.json Explained
Every Claude Code settings file and which one wins, the permission-rule syntax with its Bash matching gotchas, permission modes, and a safe starter settings.json.
Claude Code reads settings from up to five places — managed policy, CLI flags, .claude/settings.local.json, .claude/settings.json, and ~/.claude/settings.json, in that precedence order. Permissions are deny → ask → allow rules like Bash(npm run test:*) or Edit(src/**). Check a team baseline into the project file, keep personal overrides local, and manage rules with /permissions.
Key takeaways
- Five sources, one winner: managed policy > CLI flags > .claude/settings.local.json > .claude/settings.json > ~/.claude/settings.json — and a deny rule from any scope beats an allow from any other.
- Permission rules are Tool or Tool(specifier): Bash(npm run test:*), Edit(src/**/*.ts), Read(~/.zshrc), WebFetch(domain:example.com), mcp__server__tool.
- Bash matching is prefix-based with a word boundary: Bash(ls *) matches 'ls -la' but not 'lsof'; Bash(ls*) matches both. Compound commands are checked per subcommand.
- Permission modes set the autonomy dial — default, acceptEdits, plan, bypassPermissions — cycle them with Shift+Tab or set defaultMode in settings.
- First rules to write: deny Read on your secrets (.env, key files), allow your test/lint commands, and keep bypassPermissions for isolated containers only.
Every Claude Code behavior you'd want to standardize — what it may run without asking, what it must never touch, which hooks fire, which model it uses — lives in settings.json. The trouble is that there are five of them, they merge, and the permission syntax has real gotchas. This guide is the map.
The five places settings come from
| Scope | Location | Who it affects | Precedence |
|---|---|---|---|
| Managed policy | /Library/Application Support/ClaudeCode/ (macOS), /etc/claude-code/ (Linux) | Everyone on the machine — IT-deployed | 1 (highest) |
| CLI flags | claude --permission-mode plan … | This session | 2 |
| Local project | .claude/settings.local.json (auto-gitignored) | You, this repo | 3 |
| Project | .claude/settings.json (checked in) | Whole team, this repo | 4 |
| User | ~/.claude/settings.json | You, every repo | 5 (lowest) |
Higher scopes win on conflicts, with one crucial exception: a deny permission rule from any scope blocks the action regardless of allow rules elsewhere. Security floors hold even when someone's personal settings are permissive.
The working pattern: put the team contract (allowed commands, denied paths, shared hooks) in .claude/settings.json, and personal taste (your model, your notification hook) in ~/.claude/settings.json or the local file.
The keys you'll actually set
A tour of the high-value keys — there are more, but these carry most real configs:
permissions—allow/ask/denyrule arrays plusadditionalDirectories(extra paths Claude may access beyond the working directory). The heart of the file; full syntax below.env— environment variables for every session in scope ({"NODE_ENV": "test"}).hooks— lifecycle automation; see the hooks guide.model— default model alias or full name.defaultMode— starting permission mode (see modes below).statusLine/outputStyle— UI customization, usually set via/statuslineand/output-style.includeCoAuthoredBy— whether commits get theCo-Authored-By: Claudetrailer.autoMemoryEnabled— toggle auto-memory.cleanupPeriodDays— how long session transcripts are kept.enableAllProjectMcpServers— auto-approve every MCP server a project's.mcp.jsondefines (convenient, but understand what you're trusting).enabledPlugins/extraKnownMarketplaces— plugin management, usually driven by/plugin.
Permission rules: the syntax
Rules live in three arrays — allow (run without asking), ask (always confirm), deny (never) — and each rule is Tool or Tool(specifier):
{
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test:*)",
"Bash(git diff:*)",
"Edit(src/**)",
"WebFetch(domain:docs.anthropic.com)"
],
"ask": ["Bash(git push:*)"],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
]
}
}Evaluation order is deny → ask → allow — the first match decides.
Bash rules are prefix matchers, and the details bite:
Bash(npm run test:*)— the:*suffix means "this prefix plus anything": matchesnpm run test,npm run test -- --watch, etc.Bash(ls *)matchesls -labut notlsof— the space is a word boundary.Bash(ls*)matches both. Easy to write the wrong one.- Compound commands are evaluated per subcommand:
git status && npm testneeds both halves covered (a prompt's "yes, don't ask again" records them separately). - Wildcards work mid-pattern too:
Bash(git * main)coversgit push origin mainandgit merge main.
Read and Edit rules use gitignore-style paths with four anchors: //abs/path (filesystem root), ~/path (home), /path (project root), path (relative). ** recurses, * matches one level — so Edit(src/**/*.ts) is "any TypeScript file under src".
Other tools: WebFetch(domain:example.com) scopes fetching by domain; mcp__github__create_issue targets one MCP tool (and mcp__* in deny switches off all MCP tools); Agent(Explore) controls which subagents may launch.
TIP
You rarely have to hand-write rules cold: run /permissions for an interactive editor that shows every active rule and which file it came from, or answer a permission prompt with "don't ask again" and let Claude Code write the rule. The claude-settings-auditor skill reviews the merged result for holes.
Permission modes: the autonomy dial
Modes set the default posture; rules carve out exceptions.
| Mode | Behavior |
|---|---|
default | Prompts on first use of each tool — the standard interactive loop |
acceptEdits | Auto-approves file edits and safe filesystem commands; still asks for the rest |
plan | Read-only: Claude explores and proposes a plan, edits nothing until approved |
bypassPermissions | No prompts at all — for isolated containers/VMs only |
Cycle modes with Shift+Tab mid-session, start one with claude --permission-mode plan, or pin a default with "defaultMode" in settings. (Recent versions add further opt-in modes — an auto-approval mode with safety checks among them — but these four are the durable core.)
WARNING
bypassPermissions is not a convenience setting. Everything that makes an agent safe to run on your machine routes through the permission system; bypass it only where the environment itself is the sandbox — a container or CI runner you can throw away. For day-to-day speed, acceptEdits plus a good allow-list gets you 90% of the velocity at a fraction of the risk.
A safe starter for your team
Drop this in .claude/settings.json, adjust the commands to your stack, and commit it:
{
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test:*)",
"Bash(npm run build)",
"Bash(git status)",
"Bash(git diff:*)",
"Bash(git log:*)"
],
"ask": ["Bash(git push:*)", "Bash(npm install:*)"],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
]
},
"env": { "FORCE_COLOR": "1" },
"includeCoAuthoredBy": true
}It encodes the three habits that matter: the verify loop (lint/test/build) runs friction-free, anything that leaves the machine asks first, and secrets are unreadable no matter what anyone's personal settings say. From there, tighten or loosen per project — and let hooks handle the rules that need logic instead of patterns. For the deeper question of which tools an agent should have at all, see Effective Tool Use.
Frequently asked questions
- Where is Claude Code's settings.json?
- Three places you'll actually edit: ~/.claude/settings.json (your defaults for every project), .claude/settings.json in a repo (team-shared, checked in), and .claude/settings.local.json (personal, gitignored). Enterprise machines can also have a managed settings file that overrides everything, and CLI flags override everything except managed policy.
- How do I let Claude Code run commands without being asked every time?
- Add permission rules. Either run /permissions and add allow rules interactively, or put them in settings.json — e.g. "allow": ["Bash(npm run test:*)", "Bash(git diff:*)"]. When a permission prompt appears, choosing "don't ask again" writes the rule for you. Prefer narrow prefixes over allowing all of Bash.
- What's the difference between settings.json and settings.local.json?
- .claude/settings.json is the team file — checked into the repo, applies to everyone who works in it. .claude/settings.local.json is yours alone — Claude Code gitignores it automatically, and it takes precedence over the team file. Team baseline in one, personal taste in the other.
- How do I block Claude Code from reading secrets?
- Deny rules: "deny": ["Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)"]. Deny beats allow from any scope, so a project-level deny holds even if a user-level rule allows broadly. Pair it with a PreToolUse hook if you want the same paths protected from edits with a custom message.
- What does bypassPermissions mode do?
- It skips permission prompts entirely — Claude runs tools without asking. It exists for isolated environments (containers, throwaway VMs, CI sandboxes) where the blast radius is contained. Don't run it on your laptop: the prompt you would have denied is exactly the one that matters.
Related
- Claude Code Hooks: Automate Formatting, Tests, and GuardrailsHow Claude Code hooks work — the major hook events, the settings.json configuration shape, exit codes and JSON output, plus three hooks worth copying.
- Claude Settings AuditorAudit every Claude Code settings layer — user, project, local, and managed — and report the effective merged configuration with its risks: over-broad Bash allows, missing deny rules for secrets, bypassPermissions defaults, unvetted MCP servers and hooks, and rules that never match. Use before trusting a new repo's checked-in settings, or to harden your own before handing the agent more autonomy.
- Managing Claude Code Memory & Context: CLAUDE.md, /compact, and Auto-MemoryHow Claude Code remembers — every CLAUDE.md scope and load order, path-scoped rules, the auto-memory system, and the context commands that keep sessions sharp.
- 25 Claude Code Tips, Shortcuts, and Power FeaturesThe 25 highest-leverage Claude Code tips — keyboard shortcuts, bash and memory shortcuts, session commands, model tricks, and the power features most people miss.
- Effective Tool Use: Scoping an Agent's ToolsetHow to scope tools and permissions so an agent reaches for the right one and can't do damage.
- CLAUDE.md Best PracticesHow to write a CLAUDE.md that actually helps — what to include, what to leave out, and how to keep it current.
- Claude CodeAnthropic’s official agentic coding tool that runs in the terminal, IDE, and web.
- Hook WriterTurn a plain-language automation request — 'format every file Claude edits', 'block writes to migrations', 'notify me when input is needed' — into a working Claude Code hook: the right event, a safe tested script, and the settings.json registration at the right scope. Use when you want a hook but don't want to hand-write the matcher, stdin JSON parsing, and exit-code plumbing.
- Running Claude Code in CI: Headless Mode & GitHub ActionsClaude Code without the terminal — claude -p flags, JSON and structured output, safe permission scoping, and the official GitHub Action responding to @claude.
- Claude Code vs Codex CLI: Terminal Agents Compared (2026)Claude Code vs OpenAI's Codex CLI — autonomy vs sandboxed control, extensibility vs open source, model ecosystems, and which terminal agent fits your work.
- Claude Code Plugins: Install, Use, and Build Your OwnHow Claude Code plugins work — what they can bundle, the /plugin and marketplace commands, the plugin.json manifest, and building and testing your own.
- Adding MCP Servers to Claude Code: Local, Remote, and Project-ScopedThe complete claude mcp add reference — stdio vs HTTP transports, local/project/user scopes, .mcp.json with env expansion, OAuth via /mcp, and the gotchas.
- Vibe Coding in 2026: What It Is, When It Works, When It BitesAn honest guide to vibe coding — where prompt-and-accept development genuinely pays, where it accumulates risk, and the guardrails that make it professional.
- Claude Code Troubleshooting: Fixes for the Most Common ProblemsPractical fixes for the Claude Code issues people actually hit — install and auth failures, context-limit errors, MCP servers that won't connect, permission loops, and CI quirks.
- Stripe MCPStripe's official MCP server — customers, invoices, payment links, subscriptions, refunds, and docs search for agents, hosted at mcp.stripe.com.
- Setup Claude CIWire Claude Code into this repo's CI the safe way — install the GitHub App or scaffold the workflow YAML, scope permissions to the minimum, set secrets correctly, and verify with a real trigger.
- Human-in-the-Loop (HITL)Human-in-the-loop design inserts human judgment at decisive points in an AI workflow — approving actions, resolving ambiguity, owning the irreversible steps.