Doctor .claude/settings.json
BlockedBash(git push *)
Open the doctor
Checked against Claude Code 2.1.292 docs, 7 OctChecked against 2.1.292 docs, 7 Oct 243 keys indexed Runs in your browser

Claude Code settings.json, explained and tested

Paste your settings file. The doctor flags what Claude Code ignores, shows the fix, and tells you whether a command runs, asks first or gets blocked.

settings.json doctor
Load
.claude/settings.jsonEveryone in the repo20 lines
2 fixable

Findings

1 error · 2 warnings · 1 note
  • errorComments are not allowed in settings.json. Claude Code reads strict JSON and reports this file as a Settings Error.
    Delete the comment. Use a _comment key or a nearby README if you need a note.
    Docs
  • warning"Bash(git * main)": the * stands in for the subcommand, so this allows every git subcommand that ends that way (for git that includes options that run other programs). Claude Code warns about it at startup.
    Put the * after the subcommand, for example Bash(git log *).
  • warning"Write(/src/**)": Claude Code checks file paths against Edit(...) and Read(...) rules only. A Write(path) rule is accepted but never consulted.
    Use Edit(/src/**).
    Docs
  • noteThe 5 allow rules in a committed project file apply only after each teammate accepts the workspace trust dialog. Deny and ask rules apply right away.
8 permission rules parsed$schema set.env reads denied

Test a tool call

as Project file
Blocked

A deny rule matches. Deny is checked first, so nothing else can allow it.

It also matches the allow rule Bash(git * main), but deny is checked first.

1 denymatched

Tested as if the JSON errors were fixed. Until they are, Claude Code skips this file.

Where is the Claude Code settings.json file?

Short answer

Your personal settings live in ~/.claude/settings.json (on Windows %USERPROFILE%\.claude\settings.json). Each project can have a shared .claude/settings.json, committed for the team, and a personal .claude/settings.local.json that stays out of git. Organizations deploy managed-settings.json in a system folder. Installing Claude Code creates none of them.

Claude Code writes two of these files for you. ~/.claude/settings.json appears the first time you change a /config option it stores there, such as the theme. .claude/settings.local.json appears the first time you pick "Yes, and don't ask again" on a permission prompt, and in a git repository Claude Code adds it to your global git excludes so it never lands in a commit.

It reads the shared .claude/settings.json from the folder you start in, so start Claude Code at the repository root to use a file committed there. The local file lives at the repository root even when you start in a subfolder.

Which settings file should I use?

Short answer

Use ~/.claude/settings.json for preferences you want everywhere, such as theme and model. Put team rules, hooks and plugins in .claude/settings.json and commit it. Put personal overrides for one repository in .claude/settings.local.json. Anything your organization must enforce belongs in managed settings.

Which file? Three questions
Who is the setting for?
Where should it apply?
Must nobody override it?
Put it in

~/.claude/settings.json

Your user file applies in every project on this machine. Theme, model, notifications and your own deny rules go here.

To try a value for one session without saving it, pass it at start: claude --settings '{"model": "opus"}'. It sits above every file except managed settings and is gone when the session ends.

Which Claude Code setting wins?

Short answer

Managed settings win, then command-line flags such as --settings, then .claude/settings.local.json, then .claude/settings.json, then ~/.claude/settings.json. A key set higher overrides the same key lower down, but lists such as permissions.allow merge across files instead of replacing each other.

Try it with
Environment variables are not a level. This one applies over the model key from any file.
Claude Code starts with sonnet from the project level, the highest one that sets model.

The order for a single value, from the settings docs. Lists combine from every file instead of picking one.

Lists merge, and deny beats allow across files

Each file can add permissions.allow entries without removing another file's. That merge cuts both ways: a deny rule in your user file blocks an allow rule in the project file, and the reverse. A few model keys follow their own rules: fallbackModel takes its whole value from one file, modelPicker is read only from managed, --settings and user files, and a managed availableModels list replaces the lists in other files.

Keys where the stricter value wins

For a few security keys, Claude Code honors a restrictive value from a lower file even over managed settings:

KeyStricter value honored
disableClaudeAiConnectorstrue from any file
isolatePeerMachinestrue from any file
enableArtifactfalse from any file
disableArtifacttrue from any file
maxEffortLevelThe lowest cap from any file, including --settings
remoteControlAtStartupfalse from the project or local file
syncClaudeAiSkills, syncClaudeAiPlugins, useAutoModeDuringPlanfalse from any file except the shared .claude/settings.json

How do Claude Code permission rules work?

Short answer

Rules look like Tool or Tool(specifier) and sit in permissions.allow, ask or deny. Claude Code checks deny first, then ask, then allow, and the first match decides, so a broad deny beats a narrow allow. In Bash rules, * matches any text, and each part of a compound command must match on its own.

01 · order

Deny, then ask, then allow. Specificity does not matter: Bash(aws *) in deny blocks aws s3 ls even with Bash(aws s3 ls) in allow.

02 · one file at a time

The doctor tests the file in the editor. Claude Code merges every file, so a deny elsewhere still wins.

03 · tested

The matcher passes 92 checks, most taken from the example tables on the official permissions page.

Does it match? The documented wildcard examples

Type a command and every rule from the docs' wildcard table says whether it matches. Click an example to load it.

1 of 8 rules match
You writeYour commandDocs: matchesDocs: does not match
Bash(npm run build)no match
Bash(npm run *)no match
Bash(git log * main)no match
Bash(git * main)matches
Bash(* --version)no match
Bash(ls *)no match
Bash(ls*)no match
Bash(* --help *)no match
The space before a trailing * counts: Bash(ls *) skips lsof, Bash(ls*) does not. Bash(ls:*) equals Bash(ls *), but :* only works at the end.

Compound commands and wrappers

Claude Code splits commands on &&, ||, ;, |, |&, & and newlines. An allow rule must match every part; a deny or ask rule fires on any part, including commands inside $( ). Before matching it strips timeout, time, nice, nohup, stdbuf, command, builtin, noglob and bare xargs, so Bash(npm test *) also covers timeout 30 npm test. Runners such as npx, devbox run and docker exec are not stripped, so Bash(devbox run *) also matches devbox run rm -rf ..

This allowlisting approach is often defeated by the model's own proclivity to get fancy with inline scripting.
dgunay · Hacker News · Aug 2026

What a Bash rule does not stop

A Bash rule matches the command text Claude writes. The same program called another way slips past it:

Rule in denyStopsDoes not stop
Bash(curl *)curl https://example.com/usr/bin/curl https://example.com, sh -c 'curl https://example.com'
Bash(rm *)rm -rf build//bin/rm -rf build/, bash -c 'rm -rf build/'
Bash(git push *)git push origin maingit -C . push origin main, git 'push' origin main
For a boundary that does not depend on command text, turn on the sandbox. For your own logic, use a PreToolUse hook.
I had to write my own auto approval system and plug it in as a hook.
oefrha · Hacker News · May 2026

Where a path rule points

Read and Edit rules use gitignore patterns with four anchors. A single leading slash is the trap: it anchors at the project root in a project file and at ~/.claude in your user file, never at the filesystem root.

Path anchor resolver
Session: home /Users/you, started in ~/code/app
Defined in
pattern typeAnchored at the project root where the session starts (/)resolves to/Users/you/code/app/docs/**your path/Users/you/code/app/docs/guide.mdmatch?yes
permission enforcement that lives inside the tool it's supposed to police will always be one bug away from failing open
zahraarman · Hacker News · Jul 2026

What should a starter settings.json contain?

Short answer

Start small: the $schema line for autocomplete, deny rules for .env files and secrets, allow rules for the lint and test commands you run all day, and a rule that stops git push. Keep the default mode, notifications and model in your user file, not the one your team shares.

Starter builder
File
System
settings.json
{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": [
      "Bash(npm run lint)",
      "Bash(npm run test *)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)"
    ],
    "defaultMode": "acceptEdits"
  },
  "preferredNotifChannel": "terminal_bell",
  "cleanupPeriodDays": 90,
  "statusLine": {
    "type": "command",
    "command": "jq -r '\"[\\(.model.display_name)] \\(.context_window.used_percentage // 0)% context\"'"
  }
}

Save to ~/.claude/settings.json

Applies in every project. model is read at start, so restart after saving.

Which Claude Code settings are worth changing first?

Short answer

Ten keys do most of the work: cleanupPeriodDays to keep transcripts past 30 days, autoMemoryEnabled, preferredNotifChannel for a bell when a task ends, attribution, statusLine, model, spinnerTipsEnabled, env, enabledPlugins with extraKnownMarketplaces, and sandbox.enabled.

cleanupPeriodDays01

"cleanupPeriodDays": 90

Claude Code deletes transcripts older than this, silently, so old sessions vanish from /resume. The default is 30 days; 0 fails validation.

"cleanupPeriodDays": 99999 SyneRyder · Hacker News · Jun 2026

autoMemoryEnabled02

"autoMemoryEnabled": false

Auto memory is on by default. Turn it off if you would rather keep project notes in CLAUDE.md yourself.

I have this in ~/.claude/settings.json "autoMemoryEnabled": false fluidcruft · Hacker News · Aug 2026

preferredNotifChannel03

"preferredNotifChannel": "terminal_bell"

A bell or desktop notification when a task finishes. Values: auto, terminal_bell, iterm2, iterm2_with_bell, kitty, ghostty, notifications_disabled.

In claude code it's `"preferredNotifChannel": "terminal_bell"` in the settings.json zavec · Hacker News · Jun 2026

attribution04

"attribution": false

Drops the attribution Claude Code adds to commits and pull requests. false works from 2.1.281; earlier versions reject it and skip the file. An object with commit and pr strings customizes it instead.

statusLine05

"statusLine": {
  "type": "command",
  "command": "jq -r '...'"
}

Runs your command and prints its output below the prompt. The docs example shows the model name and how full the context window is; it needs jq.

model06

"model": "opus"

The model Claude Code starts with, read only at start: use /model mid-session. Aliases such as opus, sonnet and haiku follow the newest version. For effort, use /effort: it saves a level per model, and Opus 5.5 and newer ignore effortLevel in the user file.

spinnerTipsEnabled07

"spinnerTipsEnabled": false

Hides the tips shown in the spinner while Claude works. On by default.

env08

"env": {
  "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
}

Sets environment variables for every session and its subprocesses, so you stop exporting them in your shell profile.

I added: "env": { "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1" }, to my .claude/settings.json file, and the /rc in the corner went away. ebcode · Hacker News · Sep 2026

enabledPlugins + extraKnownMarketplaces09

"enabledPlugins": {
  "code-formatter@team-tools": true
}

Commit both in the project file and everyone who opens the repo gets the marketplace and the plugin. Marketplaces wait for workspace trust.

i just define the marketplaces and plugins in my .claude/settings.json for the project. pdantix · Hacker News · Sep 2026

sandbox.enabled10

"sandbox": {
  "enabled": true
}

OS-level limits on what Bash can touch, on macOS, Linux and WSL2. Linux and WSL2 need bubblewrap and socat. Sandboxed commands run without prompts by default.

Which copied settings do nothing?

Short answer

Seven show up again and again: bash.deniedCommands and an autoCompactThreshold key do not exist, .claudeignore has no effect, a // comment breaks the whole file, Write(path) rules are never consulted, bypassPermissions in a committed project file is ignored, and mcp__server__tool(arg) rules are skipped.

01

bash.deniedCommands does not exist

People write
"bash": {
  "deniedCommands": ["rm"]
}
Use this instead
"permissions": {
  "deny": ["Bash(rm *)"]
}

There is no bash key. Claude Code ignores it, and every rm still runs or prompts as before. Blocked commands are Bash rules in permissions.deny.

02

There is no auto-compact threshold key

People write
"autoCompactThreshold": 50
Use this instead
"env": {
  "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "50"
}

The variable takes 1 to 100 and can only make compaction happen earlier: values above the default are ignored. autoCompactEnabled turns it off.

03

.claudeignore has no effect

People write
# .claudeignore
.env
node_modules/
Use this instead
"permissions": {
  "deny": ["Read(./.env)"]
}

Claude Code does not read a .claudeignore file. Read deny rules keep files out, and a Read deny also blocks Edit on the same path.

04

A // comment breaks the whole file

People write
{
  // my rules
  "model": "opus"
}
Use this instead
{
  "model": "opus"
}

Settings files are strict JSON. One comment or trailing comma is a Settings Error, and Claude Code skips the entire file, not just that line.

05

Write(path) rules are never consulted

People write
"allow": ["Write(/src/**)"]
Use this instead
"allow": ["Edit(/src/**)"]

Edit rules cover every built-in tool that writes files. Path rules for Write, NotebookEdit, MultiEdit and Glob are never checked.

06

bypassPermissions in a committed project file

People write
"defaultMode": "bypassPermissions"
(in .claude/settings.json)
Use this instead
"defaultMode": "acceptEdits"
or bypassPermissions in your
user file, in a container

auto and bypassPermissions do not take effect from project or local files (bypassPermissions since 2.1.257), so a cloned repo cannot switch off your prompts.

07

mcp__server__tool(arg) rules are skipped

People write
"deny": ["mcp__github__create_issue(repo:prod)"]
Use this instead
"deny": ["mcp__github__create_issue"]

MCP rules with parentheses are skipped when settings load. Deny the whole tool, or pass the pattern on the command line with --disallowedTools.

How do I stop Claude Code asking for permission, safely?

Short answer

Add allow rules for the commands you approve every day, use acceptEdits mode for file edits, and turn on the sandbox so sandboxed Bash commands run without a prompt. Auto mode hands routine approvals to a classifier. Keep bypassPermissions for containers and VMs, and set disableBypassPermissionsMode to "disable" to lock it out.

I setup an alias in my shell for --dangerously-skip-permissions after about a week of the constant y, y, y
hkchad · Hacker News · Aug 2026
ModeWhat it doesSet it from
defaultAsks the first time each tool is used. Shown as Manual; manual is an alias.Any file
acceptEditsAccepts file edits and mkdir, touch, mv, cp, rm, rmdir and sed inside your working directories.Any file
planReads and runs read-only commands; no edits to your source files.Any file
autoNo routine prompts; a background classifier checks shell commands and network requests.User or managed file, --settings or --permission-mode
dontAskDenies anything that would prompt. Allowed tools and reads still run: good for CI.Any file
bypassPermissionsSkips prompts, including writes to .git and .claude. Ask rules still ask. Containers and VMs only.User or managed file, or --dangerously-skip-permissions
  1. Allow what you approve every day. Bash(npm run test *) and Bash(npm run lint) remove most prompts on their own.
  2. Never allow an interpreter or an encoder. Bash(python *) runs any script, and Bash(base64 *) prints any file.
  3. Turn on the sandbox. With sandbox.enabled and the default autoAllowBashIfSandboxed, sandboxed Bash runs without asking, inside OS-level limits. Deny rules still apply.
  4. Audit the local file. Every "Yes, and don't ask again" adds an allow rule to .claude/settings.local.json.
give Claude Code permission to run base64 without review without realizing this lets it read any file
arcfour · Hacker News · Apr 2026
any time it found it was blocked from using a tool, e.g. git, it would write a powershell script that did the same thing
eterm · Hacker News · Apr 2026
I've been running Claude Code with --dangerously-skip-permissions in a Docker container
steve_taylor · Hacker News · Aug 2026

What settings does Claude Code have?

Short answer

The settings reference lists 243 keys. 156 work in any settings file, 45 only in managed settings, 26 only in user or managed settings, 4 in user, local or managed settings, and 12 global config keys live in ~/.claude.json. Filter by file and topic below, or download the whole list.

243 of 243 keys
KeyWhat it doesWorks in
advisorModelPick which model answers when Claude asks the advisor toolAny file
agentStart every session as a named subagent with its prompt, tools, and modelAny file
agentPushNotifEnabledLet Claude send a push notification to your phone when it decides toAny file
allowAllClaudeAiMcpsLoad the claude.ai connectors Claude Code fetches itself alongside a deployed managed-mcp.jsonManaged
allowClaudeInChromeWithManagedMcpLet the built-in Claude in Chrome server run alongside a deployed managed-mcp.jsonManaged
allowedChannelPluginsReplace the default allowlist of channel plugins that can push messagesManaged
allowedHttpHookUrlsLimit which URLs HTTP hooks can targetAny file
allowedMcpServersAllowlist which MCP servers users can addAny file
allowedProvidersLimit which API providers a machine may useManaged
allowManagedHooksOnlyRun only the hooks your organization deploysManaged
allowManagedMcpServersOnlyMake the managed MCP allowlist the only one that appliesManaged
allowManagedPermissionRulesOnlyMake managed settings the only settings source of permission rulesManaged
alwaysThinkingEnabledTurn extended thinking off for every sessionAny file
apiKeyHelperGenerate the API credential with your own commandAny file
askUserQuestionTimeoutLet an unanswered question auto-continue after idle timeUser or managed
Descriptions condensed from Anthropic's settings referenceCSVJSON

Why is my Claude Code setting ignored?

Short answer

Usually one of five things: a higher level sets the same key, the file cannot set that key, broken JSON makes Claude Code skip the file, project allow rules are waiting for workspace trust, or the key is read only at start, like model. Run /status to see which files loaded, then claude doctor.

Work down the list0 of 9 checked
  • Run /status. The Setting sources line lists every file Claude Code loaded. A file missing from it was not read.
  • Run claude doctor. It lists entries Claude Code rejected and why.
  • Check the higher levels. A key in managed, --settings, local or project settings beats the same key in your user file.
  • Check the file can set that key. Managed-only keys do nothing elsewhere, and global config keys live in ~/.claude.json. The doctor flags both.
  • Accept workspace trust. Project allow rules, additionalDirectories, marketplaces and most env values wait for it. claude -p shows no dialog, so in a folder you never trusted it skips project allow rules.
  • Fix the JSON. A Settings Error means the whole file was skipped. A Settings Warning means only some entries were.
  • Restart for start-only keys. model is read at start. Use /model mid-session.
  • Look for ANTHROPIC_MODEL. An exported ANTHROPIC_MODEL beats the model key in every file, managed included.
  • Audit settings.local.json. Every "Yes, and don't ask again" adds an allow rule there, and old ones can outlive the reason you added them.
these permissions strings can contain substantive risks: API keys once pasted into a command, unrestricted git push
hermanerr, on auditing the allowlist · Hacker News · Jul 2026

settings.json vs ~/.claude.json vs CLAUDE.md vs .mcp.json: what goes where?

Short answer

settings.json holds rules and preferences that Claude Code enforces. ~/.claude.json is Claude Code's own state: your sign-in, MCP servers at user and local scope, and trust decisions. CLAUDE.md holds instructions Claude reads but nothing enforces. .mcp.json lists the project MCP servers you commit for the team.

FileHoldsWho writes itCommit it?
settings.jsonPermissions, hooks, env, model, plugins. Enforced by Claude Code.You, or /config and permission promptsThe project file, yes
~/.claude.jsonSign-in, user and local MCP servers, per-project trust, global config keysClaude Code; you rarely edit itNever
CLAUDE.mdStanding instructions. Shapes what Claude tries; enforces nothingYouThe project one, yes
.mcp.jsonProject-scope MCP servers; asks before first useYou, or claude mcp add --scope projectYes
Which MCP servers belong in .mcp.json: see MCP servers worth adding.

One more place: the env block in settings points Claude Code at a different endpoint with ANTHROPIC_BASE_URL. If you plan to run a model on your own machine, check what your hardware can run first.

Questions people ask

How do I access Claude Code settings?

Run /config in a session and open the Config tab for personal options such as theme and editor mode. For everything else, edit the settings file in your editor. /status shows which files loaded.

Where is settings.json on Windows and macOS?

macOS and Linux: ~/.claude/settings.json. Windows: %USERPROFILE%\.claude\settings.json. Managed settings sit in /Library/Application Support/ClaudeCode/ on macOS and C:\Program Files\ClaudeCode\ on Windows.

Does settings.json allow comments?

No. Settings files are strict JSON. A // comment or a trailing comma is a syntax error, and Claude Code shows a Settings Error at the next start and skips the file.

What is settings.local.json for?

Your own overrides for one repository. Claude Code saves "Yes, and don't ask again" approvals there and keeps the file out of git through your global excludes.

How do I make Claude Code stop asking for permission?

Allow the commands you trust, use acceptEdits for file edits, or turn on the sandbox. See the safe options above.

How do I allow all Bash commands?

Add "Bash" to permissions.allow. Deny and ask rules still apply, and a PreToolUse hook can reject the commands you never want.

Can I prevent Claude Code from running dangerous commands?

Deny rules such as Bash(rm *) stop the usual form, not /bin/rm or sh -c. For a real boundary, enable the sandbox.

How do I change the default model?

Set "model" in ~/.claude/settings.json, or pick one with /model. --model changes one session, and an exported ANTHROPIC_MODEL overrides the key in every file.

Is there a JSON schema for settings.json?

Yes. Add "$schema": "https://json.schemastore.org/claude-code-settings.json" for autocomplete in VS Code and Cursor. It can lag behind the newest releases.

Why is my setting ignored?

A higher level sets it, the file cannot set it, the JSON is broken, or it waits for trust. Work through the checklist.

Sources

  1. Settings files and precedence, Claude Code docs
  2. Configure permissions and permission modes, Claude Code docs
  3. Settings reference: the 243-key index
  4. Deploy managed settings, environment variables and sandboxing, Claude Code docs
  5. Hacker News threads, credited beside each quote

Changelog

  • 7 Oct: checked against the Claude Code 2.1.292 docs; key index rebuilt with 243 keys.
  • 7 Oct: the rule tester passes 92 checks.
  • First published with the settings.json doctor.