All posts
5 min read

Claude Code Settings Explained: settings.json Scopes, Precedence, and a Team Setup

Claude Code reads settings from managed, command-line, local, project, and user files. Where each lives, which wins, how permission lists merge, what belongs in the committed project file vs your personal one, and a practical team configuration with permissions, hooks, and environment variables.

Claude Codetoolingdeveloper experienceintermediate

Claude Code's behaviour — default permission mode, allowed and denied commands, hooks, environment variables, model — comes from a stack of JSON settings files. Once more than one person works on a project, or you use Claude Code across several projects, knowing which file to edit saves a lot of confusion. This reflects Anthropic's documentation as of September 2026.

The files and their precedence

Highest precedence first:

# Level Location Who it's for
1 Managed managed-settings.json, MDM policy, or server-managed from the claude.ai admin console Your organisation; can't be overridden
2 Command line claude --settings <file-or-json> and flags This session only
3 Project local .claude/settings.local.json You, in this project (not committed)
4 Shared project .claude/settings.json Everyone in the repo (commit it)
5 User ~/.claude/settings.json You, in every project

On Windows, ~/.claude is %USERPROFILE%\.claude.

A key set at a higher level overrides the same key lower down — with one important exception below.

Separately, Claude Code keeps ~/.claude.json for its own state (sign-in, per-project trust decisions, and MCP server configurations). You don't normally edit it by hand; project-shared MCP servers go in .mcp.json at the repo root. (Claude Code MCP Servers.) And instructions — as opposed to settings — live in CLAUDE.md files. (How to Write a CLAUDE.md.)

Lists merge

Array settings such as permission rules merge across levels rather than replacing each other. So a team's deny rules in .claude/settings.json still apply when you add your own allow rules in settings.local.json — you can't accidentally wipe out the team's safety rules by defining your own list. (A few ordered settings, like model fallback chains, are taken whole from the highest level that defines them.)

And deny rules win over allow rules: a command matched by any deny rule is blocked in every permission mode. (Claude Code Permission Modes.)

What goes where

.claude/settings.json (committed) — the team contract:

  • Permission rules: commands that are always safe to run (tests, lint, type check), commands that must always ask (push, deploy), and files that must never be read (secrets).
  • Hooks everyone should run — formatters after edits, guards before dangerous commands. (Claude Code Hooks.)
  • Non-secret environment variables the project needs.

.claude/settings.local.json (git-ignored) — your personal exceptions in this repo: an extra allowed command, a different model, local paths. Claude Code creates it (and ignores it in Git) when you approve a "don't ask again" prompt for a project.

~/.claude/settings.json — your preferences everywhere: default permission mode, theme-like options, personal hooks such as desktop notifications.

Managed settings — organisation policy: disabling bypass or auto mode, mandatory deny rules, allowed MCP servers, minimum versions.

A practical team file

{
  "permissions": {
    "allow": [
      "Bash(npm run test *)",
      "Bash(npm run lint)",
      "Bash(npx tsc --noEmit)",
      "Bash(git status)",
      "Bash(git diff *)"
    ],
    "ask": [
      "Bash(git push *)",
      "Bash(npm publish *)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)",
      "Bash(rm -rf *)"
    ]
  },
  "env": {
    "NODE_ENV": "development"
  },
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }]
      }
    ]
  }
}

(Hooks receive details of the tool call as JSON on standard input — here, jq pulls out the edited file's path.) Settings files are strict JSON: no comments, no trailing commas. A syntax error shows up as a settings error at startup.

Permission rule patterns

  • Bash(npm run test *) — a command and anything after it.
  • Read(./.env) — a specific file, relative to the project.
  • Read(./secrets/**) — a directory tree.
  • Edit(src/**), WebFetch(domain:docs.example.com), and MCP tool names follow the same idea.

Keep allow rules narrow. Bash(*) or Bash(python *) effectively approve arbitrary code execution — and auto mode drops such broad rules anyway.

Choosing a default mode

permissions.defaultMode sets the starting mode. Note two subtleties from the docs: auto only takes effect as a default from your user settings (not from project files), and bypassPermissions can't be enabled from project files either — so a cloned repository can't silently put you in a less supervised mode.

Changing settings

  • /config — an interactive menu for common personal options; writes the right file for you.
  • /permissions — view and edit allow/ask/deny rules.
  • Edit the file directly — Claude Code watches settings files and applies most changes to the running session without a restart.
  • claude --settings '{"model": "…"}' — one-off overrides.

Debugging "why isn't my setting applied?"

  1. /status — shows which settings sources were loaded.
  2. claude doctor — reports invalid entries and rejected keys.
  3. Check whether a higher level sets the same key (a local file overriding the project file, or a managed policy).
  4. Check the key is allowed at that scope — some keys are ignored in repository files by design.
  5. Validate the JSON.

Security notes

  • Never put secrets in .claude/settings.json — it's committed. Put them in your shell environment, a secret manager, or settings.local.json at most. (Secrets Management Beyond .env Files.)
  • Review changes to .claude/settings.json and .mcp.json in pull requests as carefully as CI config: they change what an agent may do on every teammate's machine.
  • Deny rules and permission prompts limit what Claude asks to do; isolation limits what an approved command can reach. Use both. (How to Run AI-Generated Code Safely.)

EasySpawn runs Claude Code in a persistent, isolated workspace per project, so your committed .claude/settings.json, hooks, and MCP config apply the same way for everyone who opens it. See how it works or join the waitlist.

Related: Claude Code Permission Modes · Claude Code Skills · Claude Code on a Large Codebase

Keep reading