Settings, the whole config model

Almost everything Claude Code does in a session is shaped by a JSON file called settings.json. Permissions, hooks, MCP servers, environment variables, plugins, all of it. Understanding this file is the fastest way to shape the harness around your work. This page walks through the whole config model, with sensible defaults and the things not to do.

Where settings live, and how they layer.

Claude Code reads settings from up to three places. Each more specific than the last. A setting defined at multiple levels wins at the most specific one.

~ where settings live, from broadest to most specific ~

The merging is cumulative: the global file is your defaults; the per-machine file overrides for your current computer; the per-project file overrides for the current repo. Think of it like CSS specificity for agent configuration.

The fields you'll actually use.

The config has a bunch of fields. These are the ones that come up in real use, in rough order of importance.

permissions - the most important field.

Controls what tools the agent can use without asking. Has three sub-fields:

See Permissions for the full design guide - this is the single most important page in the framework.

mcpServers - your installed MCPs.

A map of MCP server name → config. Each entry becomes a set of tools the agent can call. Two shapes:

// Local stdio server
"notion": {
  "command": "npx",
  "args": ["-y", "@notionhq/notion-mcp"],
  "env": { "NOTION_API_KEY": "${NOTION_API_KEY}" }
}

// Remote HTTP server
"github-remote": {
  "url": "https://api.github.com/mcp",
  "headers": { "Authorization": "Bearer ${GITHUB_TOKEN}" }
}

hooks - run your code on agent events.

Array of hook definitions. See Hooks for when and why.

env - set environment variables for every session.

Tokens, paths, feature flags. Available inside tools and MCP servers. Prefer ${VAR} substitution over literal values so your config can be committed without leaking secrets.

enabledPlugins - turn plugins on/off.

A map of plugin ID → boolean. Installed plugins default to enabled; use this to selectively disable.

skipAutoPermissionPrompt - the danger flag.

Boolean. If true, Claude Code does NOT pop an approval dialog for calls that aren't in the allow list. Instead, it uses its own judgment. Only use this with a very strict deny list. Otherwise you're handing full autonomy to the model, which is usually a mistake.

autoUpdaterStatus - let it update itself.

Controls whether Claude Code auto-updates. Leave on default; updates ship often and you want them.

A minimal settings.json that actually works.

If you're starting fresh, this is a good starting config. Adjust permissions once you've run a few real sessions.

{
  "permissions": {
    "defaultMode": "auto",
    "allow": [
      "Read", "Write", "Edit", "Glob", "Grep",
      "Bash(git status)", "Bash(git log:*)", "Bash(git diff:*)",
      "Bash(ls:*)", "Bash(cat:*)", "Bash(head:*)", "Bash(tail:*)",
      "mcp__notion__*"
    ],
    "deny": [
      "Bash(sudo:*)",
      "Bash(rm -rf:*)",
      "Bash(git push:*)",
      "Bash(git reset --hard:*)",
      "mcp__*__delete_*"
    ]
  },
  "mcpServers": {
    "notion": {
      "command": "npx",
      "args": ["-y", "@notionhq/notion-mcp"],
      "env": { "NOTION_API_KEY": "${NOTION_API_KEY}" }
    }
  }
}

Reads: allowed. Writes and safe shell: allowed. Notion MCP: allowed. Dangerous things: denied. Use as a starting point; widen the allow list as you hit friction.

What NOT to do.

~ settings footguns ~

Diffing, sharing, and version control.

The project-level .claude/settings.json is meant to be committed into git. Your team picks up the same permissions baseline, the same MCPs, the same hooks. This is how you scale a safety-conscious agent setup across people.

Keep settings.local.json and anything with real secrets OUT of version control. Reference tokens with ${ENV_VAR} substitution so the committed file has no actual credentials in it.

When your team's settings drift ("wait, who added that to the allow list?"), a git diff on .claude/settings.json answers it in ten seconds. This is where version control pays off the most.

The workflow: settle your defaults, then iterate.

  1. Start with the minimal config above in ~/.claude/settings.json.
  2. Run Claude Code for a week. Every time you approve the same action twice, consider adding it to allow.
  3. Every time something unexpected got auto-approved, tighten the allow list (or add it to deny).
  4. For a specific project with different needs, drop a .claude/settings.json in that repo.
  5. For secrets and per-machine things, use ~/.claude/settings.local.json.

Most people settle into a configuration after 2-3 weeks that they rarely touch. The time invested early pays for itself in thousands of friction-free sessions later.