← Blog

Claude Code Permissions: Modes, Rules, settings.json

October 5, 2026

AI Coding

Claude Code permissions answer one question: what may the agent do without asking you first? Three things decide it, and they stack:

  1. A permission mode sets the baseline for the whole session.
  2. Allow, ask and deny rules in settings.json override that baseline for specific tools and commands.
  3. The sandbox is an optional operating-system boundary around shell commands, and it holds even when the first two get it wrong.

This guide covers each layer as described in Anthropic's permissions documentation as of October 2026, plus the one-line settings snippet most people are really looking for.

The six Claude Code permission modes

The permission modes page lists six. The name you type is the config value:

ModeRuns without askingBest for
default (labeled Manual)Reads onlySensitive work, unfamiliar code
acceptEditsReads, file edits, common filesystem commands such as mkdir, mv, cpReviewing changes in a diff afterward
planReads; edits stay blocked until you approve a planExploring before changing anything
autoMost actions, while a background classifier reviews themLong tasks with fewer prompts
dontAskReads and pre-approved tools; everything else is deniedLocked-down CI and scripts
bypassPermissionsEverythingIsolated containers and VMs only

Three details trip people up.

Auto is now the starting mode. The docs say that with Claude Code v2.1.283 or later, auto is the built-in starting mode for interactive terminal and VS Code sessions. If the session's model or your organization's settings rule it out, Claude Code starts in Manual instead. Auto reduces prompts. The docs are explicit that it does not guarantee safety.

Switching is Shift+Tab. In the CLI it cycles default, then acceptEdits, then plan, with auto and bypassPermissions slotting in when they're available. dontAsk never appears in the cycle. Set it at launch with claude --permission-mode dontAsk. You can also pass manual as an alias for default on v2.1.200 or later.

Plan mode ends in a decision. Start it with /plan or claude --permission-mode plan. Claude reads, explores and writes a plan without editing your source. When the plan is ready you choose whether to approve it in auto mode, approve it and review each edit yourself, or keep planning. Plan mode is the safest first move on a codebase you don't know.

One more gotcha for settings files. A defaultMode of auto or bypassPermissions in a project's .claude/settings.json or .claude/settings.local.json does not take effect. Put those in ~/.claude/settings.json.

Allow, ask and deny rules: the syntax

A rule is either a bare tool name or a tool plus a specifier in parentheses. A bare name matches every use of the tool, and as a deny rule it removes the tool from Claude's context entirely.

RuleMatches
BashEvery shell command
Bash(npm run build)Exactly npm run build
Bash(npm run *)Any npm run command
Read(./.env)Reading .env in the current directory
Edit(/src/**)Edits under src/ in the project
WebFetch(domain:example.com)Fetches to that domain
mcp__puppeteer__*Every tool from the puppeteer MCP server
Agent(Explore)The Explore subagent

Wildcards have a few rules worth knowing:

  • Put the * after the subcommand. Bash(git log *) allows only git log, while Bash(git *) allows every git command. Claude Code warns at startup about an allow rule with a * before the subcommand.
  • The space matters. Bash(ls *) matches ls and ls -la but not lsof. Bash(ls*) matches all three.
  • Compound commands are split. Bash(safe-cmd *) won't approve safe-cmd && other-cmd. Each part has to match on its own.

File paths use gitignore-style patterns, and the anchors are the part people get wrong:

PrefixMeaning
//pathAbsolute path from the filesystem root
~/pathPath from your home directory
/pathAnchored at the settings source: the project directory, or ~/.claude for user settings. Not the filesystem root
path or ./pathRelative to the current directory

So /Users/alice/file is not an absolute path. Write //Users/alice/file. For a Windows drive the docs give //c/**/.env.

Evaluation order

Rules run deny, then ask, then allow, and the first match decides. Specificity doesn't change the order. A broad Bash(aws *) deny blocks aws s3 ls even if you also wrote a narrower allow for it, and a matching ask rule prompts even when a more specific allow also matches. An allow can never carve an exception out of a deny.

Here is a small .claude/settings.json that uses all three lists and sets a starting mode:

{
  "permissions": {
    "defaultMode": "acceptEdits",
    "allow": [
      "Bash(npm run *)",
      "Bash(git commit *)"
    ],
    "ask": [
      "Bash(git push *)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./secrets/**)"
    ]
  }
}

Edits and tests flow, commits flow, a push always stops for you, and secrets stay unreadable to Claude's file tools. The acceptEdits default is honored from project settings. Allow rules in a committed project file only apply after each teammate accepts the workspace trust dialog. Deny and ask rules apply immediately, since they only restrict.

Where Claude Code permissions live and which file wins

Claude Code reads four sources, per the settings documentation:

ScopeFile
Managedmanaged-settings.json or another organization-delivered source
Project local.claude/settings.local.json, yours only
Shared project.claude/settings.json, committed for the team
User~/.claude/settings.json, every project on your machine

For single-value keys like defaultMode, the order is managed first, then command-line arguments, then project local, then shared project, then user. Nothing you set overrides managed settings.

Permission lists are different. They merge. Claude Code combines allow, ask and deny entries from every file, so each file adds rules without removing another's. Then the evaluation order above applies across the combined set. Two consequences follow:

  • A deny at any level blocks an allow at any other level. A user-level deny beats a project-level allow.
  • A managed deny can't be undone by --allowedTools, while --disallowedTools can add restrictions on top of managed ones.

One surprise from the docs: choosing "Yes, and don't ask again" saves an allow rule to .claude/settings.local.json. That rule does not outrank an ask rule from a project or managed file, so you can approve something and still get prompted.

The /permissions command

Run /permissions (alias /allowed-tools) to see every active rule and the file each one comes from. You can add or remove rules, manage working directories, and review recent auto mode denials. Changes apply from Claude's next tool call, even mid-turn. If a rule isn't behaving, start here before reading JSON.

What permission rules don't protect against

Rules are enforced by Claude Code, not by the model. Telling Claude something in a prompt or in CLAUDE.md shapes what it tries, but it doesn't change what Claude Code allows. The reverse also holds: a rule is only as good as its match, and a Bash rule matches command text.

RuleStopsDoesn't stop
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

The docs call this out plainly: a deny rule covers the form Claude usually writes and is not a security boundary around the program. Argument-constraining patterns are fragile too. Their example is Bash(curl http://github.com/ *), which misses curl -L redirects, other protocols and variables.

Read and Edit deny rules cover Claude's file tools and recognized commands like cat and sed. They don't cover a Python or Node script that opens files itself. For that you need the sandbox.

Where the sandbox fits

The sandbox is OS-level enforcement on shell commands and their child processes. It runs on macOS, Linux and WSL2, and on native Windows commands run unsandboxed. Permission rules decide before a command runs, based on its text. The operating system enforces the sandbox while it runs, whatever the model chose to execute.

It covers shell commands only. Read, Edit, WebFetch, MCP servers and hooks run outside it, which is why the docs recommend using both layers. Toggle it with /sandbox. In auto-allow mode, sandboxed commands run without prompting, though explicit deny rules still apply.

For logic your own code has to decide, such as blocking edits to specific files, the docs point to a PreToolUse hook. A hook can deny a call, but it can't override a deny or ask rule.

Command-line flags

FlagWhat it does
--permission-modeStart in a named mode
--allowedToolsTools that run without prompting, using rule syntax
--disallowedToolsDeny rules; a bare name removes the tool
--toolsRestrict which built-in tools exist at all
--add-dirAdd working directories (/add-dir does it mid-session)
--dangerously-skip-permissionsSame as --permission-mode bypassPermissions
--allow-dangerously-skip-permissionsPuts bypass in the Shift+Tab cycle without starting there
--permission-prompt-toolHands prompts to an MCP tool in non-interactive runs

These are from the CLI reference. For unattended runs, the docs' own CI example is claude -p "run the test suite" --permission-mode dontAsk --allowedTools "Bash(npm test)" "Read". Anything outside the allowlist is denied instead of prompting, so the job never hangs. Our guide to Claude Code headless mode covers the rest of -p. If your servers are the thing you're gating, see MCP server configuration.

The bypass permissions warning

bypassPermissions skips prompts, including for writes to protected paths like .git and .claude. The docs' warning is blunt: it offers no protection against prompt injection or unintended actions, and should only be used in isolated environments such as containers or VMs.

A few specifics worth knowing:

  • Deny rules still block in this mode. Allow rules have no effect, since nothing prompts anyway.
  • On Linux and macOS, Claude Code refuses to start in this mode as root or under sudo.
  • You can't enter it from a session you didn't start with it enabled.
  • Administrators can disable it with permissions.disableBypassPermissionsMode set to "disable". A user can set that in their own settings to lock themselves out.

If you want fewer prompts and still want safety checks, the docs steer you toward auto mode instead. And if a permissive session already did something you regret, permissions can't help. /rewind is the undo.

A different shape of tool

Everything above is the cost of an agent that runs commands on your machine, and for developers it's worth paying. If you're not writing settings.json, Taku is a different shape: an AI-native desktop workspace where you mirror an AI setup someone has already got working, run it, remix it and keep it. It isn't a replacement for Claude Code's permission system, and if you live in a terminal and a repo, Claude Code is the stronger tool. Our free apps show what that looks like. Taku is in Beta, and the Mac app is available now.

FAQ

What are the Claude Code permission modes?

Six: default (labeled Manual), acceptEdits, plan, auto, dontAsk and bypassPermissions. Cycle the first few with Shift+Tab, or start in one with --permission-mode.

What happens when an allow rule and a deny rule both match?

Deny wins. Claude Code checks deny, then ask, then allow, and the first match decides. That holds across settings files too, so a deny in any scope beats an allow in any other.

Where do Claude Code permissions go in settings.json?

Under a top-level permissions key with allow, ask and deny arrays, plus optional defaultMode. Use ~/.claude/settings.json for personal rules, .claude/settings.json for team rules and .claude/settings.local.json for personal overrides in one project.

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

Add Read(./.env) to deny. It covers Claude's file tools and recognized commands like cat, but not a script that opens the file itself, so enable the sandbox for stronger enforcement.

Is --dangerously-skip-permissions safe?

Not on your own machine. It's equivalent to bypassPermissions, which the docs say should only be used in isolated environments like containers or VMs.

How do I see which rules are active?

Run /permissions. It lists each rule with the settings file it came from.