# Claude Code settings.json: scopes, precedence and permission rules

> Claude Code reads settings from four places: managed policy, your `~/.claude/settings.json`, the committed `.claude/settings.json` and the untracked `.claude/settings.local.json`. A `--settings` flag adds a fifth for one session. Managed wins, then the flag, then local, project and user. Lists such as `permissions.allow` merge, and deny rules beat ask rules, which beat allow rules.

Mindket editors · Published 2026-11-04 · Updated 2026-11-05 · https://mindket.com/learn/claude-code-advanced/claude-code-settings

## In short

- A key set in several files resolves by one stack: managed, then `--settings`, then local, project and user. List keys such as `permissions.allow` merge instead of overriding.
- Rules are checked deny first, then ask, then allow, and the first match decides. A narrow allow cannot reopen what a broad deny blocks.
- Allow rules in a committed file wait until each teammate trusts the folder. Deny and ask rules take effect immediately.
- Bash rules guard the usual form of a command and are not a security boundary. Pair them with the sandbox or a hook.

## Before you start

This lesson is for people who already use Claude Code every day. If you do not, take the [beginner course](https://mindket.com/learn/claude-code/install-claude-code) first. You need a git repository to try the shared and local files.

Anthropic's docs tie several behaviors to a release. The local settings file lives at the repository root since v2.1.211, and `bypassPermissions` stopped working from project files in v2.1.257. Run `claude --version` if something here does not match your install. The facts below come from [the settings guide](https://code.claude.com/docs/en/settings) and [the permissions page](https://code.claude.com/docs/en/permissions), read on 4 November 2026 and checked again on 5 November.

Settings change faster than most of Claude Code, because a release ships most days. These four releases changed what a settings file can do, with their dates from GitHub and the changelog.

**Settings changes in recent Claude Code releases**

1. **July 15, 2026** v2.1.211: approvals save at the repository root. "Always allow" rules go to the local file at the root, so a session in a git worktree keeps them.
2. **September 1, 2026** v2.1.257: bypass mode leaves project files. `defaultMode: "bypassPermissions"` in a project or local file is ignored, as `auto` already was.
3. **October 30, 2026** v2.1.314: a block on writes outside the project. `permissions.blockWritesOutsideWorkingDirectories` makes Write, Edit and NotebookEdit refuse paths outside the working directories in every mode.
4. **November 4, 2026** v2.1.318: one dialog for /permissions. Rule details and delete confirmations open in the standard dialog, and pressing Ctrl+C twice there goes back instead of quitting.

Sources: [Claude Code release v2.1.211 on GitHub](https://github.com/anthropics/claude-code/releases/tag/v2.1.211) (read 2026-11-05), [Claude Code release v2.1.257 on GitHub](https://github.com/anthropics/claude-code/releases/tag/v2.1.257) (read 2026-11-05), [Claude Code changelog](https://code.claude.com/docs/en/changelog) (read 2026-11-05)

## Set up a team file and a personal override

A committed file for the team and an untracked file for you cover most projects. The block below is the permissions part of Anthropic's example team file, plus the schema line that gives your editor autocomplete and validation.

````json
{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": [
      "Bash(npm run *)"
    ],
    "ask": [
      "Bash(git push *)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)"
    ]
  }
}
````

1. Save the block as `.claude/settings.json` at the top of the repository and commit it. Claude Code reads the shared file from the session's primary working directory, so start `claude` at the repository root.
2. Create `.claude/settings.local.json` for your own exceptions. Claude Code keeps a file it writes itself out of git. If you create the file by hand, add it to `.gitignore` yourself.
3. In the local file, set a key the team file also sets. Local sits above shared project, so only your sessions change. `{"spinnerTipsEnabled": false}` turns the tips under the spinner off for you alone.
4. Run `/status`. The `Setting sources` line names each file Claude Code loaded, such as `User settings` or `Project local settings`. It confirms which files were read, not which file supplied a key.
5. Run `/permissions` to list every rule and the file it comes from. Run `claude doctor` to list the entries Claude Code rejected.
6. Edit a rule while a session runs. Claude Code watches the files and applies most edits, including `permissions` and `hooks`, without a restart.

## Which value wins when files disagree

Claude Code uses the value from the highest level that sets a key. Managed settings sit on top, above even `--settings`, and nothing in your own files overrides a managed key.

Lists are the exception to winner takes all. When `permissions.allow` appears in several files, Claude Code combines the lists, so each file adds entries and removes none. Four model keys follow their own rules: `fallbackModel`, `modelPicker`, `availableModels` and `modelSettings`.

Environment variables are not a level. When a behavior has both a variable and a key, the pair decides. `ANTHROPIC_MODEL` exported in your shell beats the `model` key from any file, while `ANTHROPIC_DEFAULT_MODEL` applies only when no file sets `model`. An `env` block inside a settings file is an ordinary key that follows the table, and its values overwrite the same variable in your shell.

| Level | Source | Applies to |
| --- | --- | --- |
| 1 | Managed: `managed-settings.json`, an MDM policy or server-managed settings | Everyone your organization deploys it to |
| 2 | Command line: `--settings` with inline JSON or a file path | One session. It writes nothing to disk |
| 3 | Project local: `.claude/settings.local.json` | You, in one project |
| 4 | Shared project: `.claude/settings.json` | Everyone who clones the repository |
| 5 | User: `~/.claude/settings.json` | You, in every project on this machine |

## Deny, then ask, then allow

Claude Code checks deny rules first, then ask, then allow. The first match decides, and a narrower rule does not win for being narrower. A deny on `Bash(aws *)` blocks `aws s3 ls` even when an allow rule names that exact command. A deny in any scope beats an allow in any other, in either direction.

The config below runs npm scripts and commits without asking and refuses `git push`. Rules reach past Bash, too. `mcp__puppeteer__*` matches every tool of one [MCP server](https://mindket.com/blog/add-mcp-server-claude-code), and `Agent(Explore)` in deny turns one [subagent](https://mindket.com/blog/claude-code-subagents) off.

> Permission rules are enforced by Claude Code, not by the model.
>
> Anthropic, Claude Code documentation, [Claude Code docs: Configure permissions](https://code.claude.com/docs/en/permissions) (read 2026-11-04)

````json
{
  "permissions": {
    "allow": [
      "Bash(npm run *)",
      "Bash(git commit *)"
    ],
    "deny": [
      "Bash(git push *)"
    ]
  }
}
````

- Put the `*` after the subcommand. `Bash(git log *)` allows only `git log` commands, while `Bash(git *)` allows every git command. Claude Code warns at startup about an allow rule with a `*` before the subcommand, such as `Bash(git * main)`.
- A trailing ` *` with a space also matches the bare command, so `Bash(ls *)` matches `ls`. The space matters: `Bash(ls*)` matches `lsof` as well.
- A compound command needs every part allowed. `Bash(safe-cmd *)` does not approve `safe-cmd && other-cmd`, and a deny or ask rule fires when any part matches.
- Claude Code strips a fixed set of wrappers before matching, such as `timeout`, `time`, `nice` and `nohup`. It does not strip runners like `npx`, `docker exec` or `devbox run`, so a rule for `devbox run *` allows whatever follows `run`.

## Path rules and where they anchor

Read and Edit rules use gitignore syntax, and the leading slash trips most people. A single slash is not an absolute path. A rule that starts with `/` anchors at the settings source, so a `/secrets` rule in your user settings blocks the `secrets` folder under `~/.claude` and leaves the one in your project alone. The block below lists the four anchors with Anthropic's examples.

Depth depends on the rule type. A one-segment directory pattern such as `src` covers only the `src` folder under the current directory as an allow rule, and a folder of that name at any depth as a deny or ask rule. To allow a name at any depth, start the pattern with a double star, as in the last line of the block.

````text
//path   Read(//Users/alice/secrets/**)   absolute path from the filesystem root
~/path   Read(~/Documents/*.pdf)          from your home directory
/path    Edit(/src/**/*.ts)               under the primary working directory, in project settings
path     Read(*.env)                      relative to the current directory

allow    Edit(src/**)                     only the src folder under the current directory
deny     Read(secrets/**)                 a secrets folder at any depth
any      Edit(**/src/**)                  a src folder at any depth
````

> A path rule written for `Write`, `NotebookEdit` or `Glob` is accepted and never matches. Use an `Edit` rule in place of `Write` and a `Read` rule in place of `Glob`.

## What a deny rule does not stop

A Bash rule matches the command text Claude writes, after Claude Code splits compound commands and strips wrappers. The same program called another way is a different string, so the rule covers the usual form and nothing more. Anthropic's table shows three examples.

Files have the same gap. `Read(./.env)` stops `cat .env` and the file tools, and it does not stop `grep -r` run over the directory or a script that opens the file itself. When a limit must hold, the permissions page points to two tools. Sandboxing enforces filesystem and network limits at the OS level, and a PreToolUse hook can inspect the whole command, as in the [hooks lesson](https://mindket.com/learn/claude-code/claude-code-hooks). A hook that exits 2 blocks the call before any allow rule is read.

| Rule | Stops | Does not stop |
| --- | --- | --- |
| `Bash(curl *)` | `curl https://example.com` | `/usr/bin/curl https://example.com` and `sh -c 'curl https://example.com'` |
| `Bash(rm *)` | `rm -rf build/` | `/bin/rm -rf build/` and `bash -c 'rm -rf build/'` |
| `Bash(git push *)` | `git push origin main` | `git -C . push origin main` and `git 'push' origin main` |

## Sharing a file with a team: trust and the keys that never travel

A committed file cannot grant capability by itself. `permissions.allow` and `permissions.additionalDirectories` in `.claude/settings.json` apply only after each teammate accepts the workspace trust dialog for that folder. Deny and ask rules apply at once, because they only restrict. We would fill the committed file with secret-file denies first and convenience allows second, since the denies protect from the first session.

Non-interactive runs skip the dialog. `claude -p` and SDK sessions never show it, so project allow rules go unused and Claude Code prints a `this workspace has not been trusted` warning to stderr. Hooks and the `env` block from the repository still run. Before you run `claude -p` in a repository you did not write, pass `--setting-sources user`, or start with `--bare`, which the next lesson covers.

Some keys never take effect from a repository file at all.

- `permissions.defaultMode` set to `auto` or `bypassPermissions`. Set it in your user settings, or pass `--permission-mode` for one session.
- The OpenTelemetry exporter variables in an `env` block, apart from a few values that turn telemetry off. Set them in managed or user settings.
- Any key whose Scope in the [settings reference](https://code.claude.com/docs/en/settings-reference) reads `User`, `User or managed`, `User, local, or managed`, `Managed` or `Global config`.

## How Claude Code's creator shares permission rules with his team

Boris Cherny created Claude Code and works on Claude at Anthropic. His thread of customizing tips is [on X](https://x.com/bcherny/status/2021700332292911228), and tip 5 starts from the defaults. Claude Code pre-approves a small set of safe commands, you add more through `/permissions`, and the rules go into the team's settings.json. His examples are a Bash rule for `bun run` and an Edit rule for a docs folder, both in this lesson's wildcard syntax. The Edit rule starts with a slash, so in the team file it anchors at the project. Pasted into your user file, it would point at `~/.claude/docs` instead.

Five minutes later, tip 12 [said the same](https://x.com/bcherny/status/2021701636075458648) about every setting. He counted 37 settings and 84 environment variables that day and suggested the `env` field over wrapper scripts. Treat those counts as a February snapshot. The [settings reference](https://code.claude.com/docs/en/settings-reference) lists every key today.

Each "Yes, and don't ask again" writes one more rule into `.claude/settings.local.json`, so your own approvals pile up there. After a week of work, open `/permissions`, move the rules every teammate would approve into the shared file, and commit it.

> When you do customize, check your settings.json into git so your team can benefit, too.
>
> Boris Cherny, Creator of Claude Code, at Anthropic, [X](https://x.com/bcherny/status/2021701636075458648) (read 2026-11-05)

[![Boris Cherny (@bcherny) on X, 11 February 2026, tip 12 of his thread: Claude Code is built to work great out of the box. When you do customize, check your settings.json into git so your team can benefit, too. We support configuring for your codebase, for a sub-folder, for just yourself, or via enterprise-wide](https://mindket.com/blog/shots/x-bcherny-settings-in-git.webp?v=2e05ab2e9874)](https://x.com/bcherny/status/2021701636075458648)

Boris Cherny on X, 11 February 2026

> A screenshot of X's own embed of the post, taken on 5 November 2026, with the time in UTC. X cuts the post short with Show more. Select it to open the post on X.

## Common mistakes

- A trailing comma or a `//` comment in a settings file. The files are strict JSON, and Claude Code shows a Settings Error at the next start. A `-p` run shows no dialog and skips the broken file, so run `claude doctor` after a run that ignored a setting.
- Trying to carve an exception out of a deny. An allow rule cannot reopen what a deny blocks. Narrow the deny instead.
- Reading `/status` as a trace of each key. It lists loaded files and not the file behind each value. `/permissions` shows where each rule comes from.
- Writing Windows paths as Windows writes them. Claude Code normalizes `C:\Users\alice` to `/c/Users/alice` before matching, so a rule for that drive starts with `//c/`.
- Expecting "Yes, and don't ask again" to beat a project rule. That choice saves an allow rule to your local file, and an allow there does not outrank an ask rule from a project or managed file.

## Try it yourself

- Add `Read(./.env)` to the project file's deny list, ask Claude to read `.env`, then open `/permissions` and find the file that rule comes from.
- Put `Bash(git push *)` in ask in the team file and the same rule in allow in your local file. Predict whether Claude Code prompts, then ask it to push and check.
- Set `spinnerTipsEnabled` to `false` in your user file, then start one session with `claude --settings '{"spinnerTipsEnabled": true}'`. The tips return for that session only.
- Run `/status`, then `claude doctor`, and write down what each one tells you that the other does not.

## Next: headless runs

Settings decide what a session may do. In the next lesson, [headless runs](https://mindket.com/learn/claude-code-advanced/claude-code-headless), `claude -p` runs where nobody can answer a prompt, so the rules from this lesson become the whole safety model.

Hooks, from an [earlier lesson](https://mindket.com/learn/claude-code/claude-code-hooks), run your own commands at set points of a session. Standing instructions still belong in a [CLAUDE.md file](https://mindket.com/blog/claude-md-file), which settings do not replace.

## Check yourself

1. Your user settings deny Bash(npm run deploy *) and the committed project file allows Bash(npm run *). What happens to npm run deploy prod?

   A. It runs, because the project file is shared with the team
   B. It is blocked, because a deny in any scope beats an allow
   C. It prompts once and then runs
   D. Claude Code loads neither file and reports a conflict

   Answer: B. Claude Code checks deny rules first, then ask, then allow, across every scope, and the first match decides.

2. Which file holds your own overrides for one project and stays out of git?

   A. .claude/settings.json
   B. managed-settings.json
   C. .claude/settings.local.json
   D. ~/.claude/settings.json

   Answer: C. Project local settings apply only to you in one project and sit above the shared project file in the precedence stack.

3. You commit "defaultMode": "auto" in .claude/settings.json. What do your teammates get?

   A. Nothing, because auto does not take effect from project or local settings
   B. Auto mode once they trust the folder
   C. Auto mode at once, on every machine

   Answer: A. The values auto and bypassPermissions only take effect from user or managed settings, or from --permission-mode for one session.

4. Which protection still holds when Claude runs /usr/bin/curl instead of curl?

   A. A Bash(curl *) deny rule
   B. A CLAUDE.md line that says not to use curl
   C. A sandbox network allowlist

   Answer: C. A Bash rule matches the command text as written, while the sandbox restricts network access at the OS level whatever the command looks like.

## Frequently asked questions

### Where is the Claude Code settings.json file?

There are four sources: `~/.claude/settings.json` for you in every project, `.claude/settings.json` committed with a project, `.claude/settings.local.json` for you in one project, and a managed file or policy your organization deploys. Installing Claude Code creates none of them. On Windows, `~/.claude` means `%USERPROFILE%\.claude`.

### Where does "Yes, and don't ask again" save my choice?

In `.claude/settings.local.json`, as an allow rule that only you get. It outranks the shared file, and Claude Code keeps the local file out of git when it creates it.

### How do I stop Claude Code from reading my .env file?

Add `Read(./.env)` and `Read(./.env.*)` to `permissions.deny`. Claude Code then excludes matching files from discovery and search, and blocks Edit and Write on those paths. A command that never names the file, such as `grep -r` over the folder, still gets through, so turn on the sandbox when the file must stay unreadable.

### Why is my permission rule ignored?

Start with `/status`. A higher level may set the same key, or a project allow rule may still wait for workspace trust. Other causes are `auto` or `bypassPermissions` in a project file, an invalid entry that Claude Code skipped, and a `Write` or `Glob` path rule, which never matches. `claude doctor` lists what it rejected.

### Do I need to restart Claude Code after editing settings?

Usually not. Claude Code reloads user, project, local and managed files when they change, including `permissions`, `hooks` and credential helpers. A few keys load once at session start, and removing `permissions.blockReadsOutsideWorkingDirectories` mid-session keeps the block until you restart each session.

### Can I set the permission mode for a whole project?

Yes for `default`, `acceptEdits`, `plan` and `dontAsk`, through `permissions.defaultMode` in `.claude/settings.json`. The values `auto` and `bypassPermissions` take effect only from user or managed settings, or from `--permission-mode` for one session.

### Can an admin stop developers from changing these settings?

Yes. Managed settings sit above every other level, and `allowManagedPermissionRulesOnly` makes them the only source of permission rules. `permissions.disableBypassPermissionsMode` set to `"disable"` removes bypass mode, and a developer can see the policy in `/status`.

## Sources

- [Claude Code docs: Settings files and precedence](https://code.claude.com/docs/en/settings) (read 2026-11-05)
- [Claude Code docs: Configure permissions](https://code.claude.com/docs/en/permissions) (read 2026-11-05)
- [Claude Code docs: Example settings files](https://code.claude.com/docs/en/settings-example) (read 2026-11-04)
- [Claude Code docs: Settings reference](https://code.claude.com/docs/en/settings-reference) (read 2026-11-04)
- [Claude Code release v2.1.211 on GitHub](https://github.com/anthropics/claude-code/releases/tag/v2.1.211) (read 2026-11-05)
- [Claude Code release v2.1.257 on GitHub](https://github.com/anthropics/claude-code/releases/tag/v2.1.257) (read 2026-11-05)
- [Claude Code changelog](https://code.claude.com/docs/en/changelog) (read 2026-11-05)
- [Boris Cherny on X: pre-approve common permissions](https://x.com/bcherny/status/2021700332292911228) (read 2026-11-05)
- [Boris Cherny on X: customize all the things](https://x.com/bcherny/status/2021701636075458648) (read 2026-11-05)

[Browse kits](https://mindket.com/kits)
