Claude Code permissions explained

Updated 24 October 2026

Claude Code decides whether to run a tool call, ask you, or refuse it from two things: the permission mode the session is in, and the allow, ask and deny rules in your settings files. This page explains both, the rule syntax that trips people up, which settings file wins, and the prompts no setting can turn off. It’s written against Claude Code 2.1.287; check yours with claude --version.

Quick reference

You want toUse
Change how much Claude asks, right nowShift+Tab to cycle modes
Start every session in a modepermissions.defaultMode in ~/.claude/settings.json
Stop prompts for one commandAn allow rule, such as Bash(npm run *)
Always be asked before somethingAn ask rule, such as Bash(git push *)
Block something completelyA deny rule, such as Read(./.env)
See every rule and where it came from/permissions
Let Claude work in another folder--add-dir, /add-dir or additionalDirectories
Limit what shell commands can touch, whatever their textThe sandbox (/sandbox)

1. Permission modes

The mode sets the baseline: what Claude can do without asking. The status bar under the prompt shows the current one.

ModeStatus barRuns without asking
default (labeled Manual)⏸ manual mode onReads, and a built-in set of read-only commands. Everything else asks.
acceptEdits⏵⏵ accept edits onAlso file edits and mkdir, touch, rm, rmdir, mv, cp and sed, for paths inside your working directories
plan⏸ plan mode onReads and exploring. Edits wait until you approve a plan.
auto⏵⏵ auto mode onAlmost everything. A separate classifier model reviews shell commands and network requests instead of you.
dontAsk⏵⏵ don't ask onReads, the read-only commands and whatever your allow rules cover. Anything that would prompt is denied.
bypassPermissions⏵⏵ bypass permissions onEverything except a short list of checks that always ask

Two things surprise people here:

Use dontAsk for CI, where nobody is there to answer. Use bypassPermissions only in a container or VM; Claude Code --dangerously-skip-permissions covers why.

2. Switching modes

During a session, press Shift+Tab. From auto, the first press goes to Manual, then the cycle runs Manual → acceptEdits → plan → auto (when it’s available) and round again. bypassPermissions only joins the cycle if you started the session with it enabled, and dontAsk never does. You can also prefix one prompt with /plan to plan just that task.

For one session, pass the mode at launch:

claude --permission-mode acceptEdits

The flag accepts manual, acceptEdits, plan, auto, dontAsk and bypassPermissions.

For every session, set defaultMode:

~/.claude/settings.json{
  "permissions": {
    "defaultMode": "acceptEdits"
  }
}

The flag beats defaultMode, and defaultMode beats the built-in default. A project’s .claude/settings.json can set default, acceptEdits, plan or dontAsk, but auto and bypassPermissions only take effect from your user settings, --settings or managed settings. That stops a cloned repository from switching your prompts off.

In the VS Code extension, click the mode indicator under the prompt box. To pin the mode new conversations start in, set claudeCode.initialPermissionMode in your VS Code settings. The extension never reads the project’s settings files for the starting mode.

3. What asks by default

In Manual mode, this is what you get asked about, and what “Yes, and don’t ask again” remembers:

ToolAsks?“Don’t ask again” lasts
File reads, Grep, GlobNo, inside your working directoriesn/a
BashYes, except built-in read-only commandsPermanently, per repository and command
Edit and WriteYesUntil the session ends
WebFetchYes, except a built-in list of documentation domainsPermanently, per repository and domain
WebSearchYesPermanently, per repository

The read-only set includes ls, cat, echo, pwd, head, tail, grep, find, wc, which, diff, stat, du, cd and read-only forms of git. You can’t change the set. To be asked before one of them anyway, add an ask or deny rule for it.

A permanent approval is written to .claude/settings.local.json at the root of the git repository, so it covers subdirectories and worktrees too. Outside a git repository, and on Windows, Claude Code can save it somewhere else; /permissions shows which file each rule is in.

4. Allow, ask and deny rules

Rules sit in the permissions object of any settings file:

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

Claude Code checks deny, then ask, then allow, and the first match decides. Specificity doesn’t matter: with Bash(aws *) in deny, an allow rule for Bash(aws s3 ls) never applies. The same goes for ask over allow.

A deny rule with just a tool name, such as "WebFetch", removes the tool, so Claude never sees it. A scoped rule, such as Bash(rm *), keeps the tool and blocks matching calls.

Type /permissions to see every rule and the file it came from, and to add or remove rules. Changes apply from Claude’s next tool call, even mid-turn. In auto mode it also has a Recently denied tab, where you can press r to retry a blocked action with a manual approval.

For one session, --allowedTools and --disallowedTools add allow and deny rules on the command line:

claude --allowedTools "Bash(npm test)" "Read" --disallowedTools "WebFetch"

5. Rule syntax

A rule is Tool or Tool(specifier). Use the tool’s canonical name from the tools reference, not the label you see in the transcript. A deny or ask rule naming a tool that doesn’t exist gets a startup warning.

Bash

A * matches any text, spaces included. Everything before the first * must match as written, so put the * after the subcommand:

RuleMatchesDoesn’t match
Bash(npm run build)npm run buildnpm run build --watch
Bash(npm run *)npm run build, npm run test --watch, npm runnpm install
Bash(git log *)git log, git log --onelinegit push
Bash(git *)Every git command, including git push and git -c …
Bash(ls *)ls, ls -lalsof
Bash(ls*)ls -la, lsof

Bash rules match text, not programs. Bash(rm *) in deny stops rm -rf build/ but not /bin/rm -rf build/ or bash -c 'rm -rf build/'. Bash(git push *) doesn’t stop git -C . push. For a limit that holds whatever the command looks like, use the sandbox or a PreToolUse hook.

On Windows with the PowerShell tool on, rules use the same shape: PowerShell(Get-ChildItem *). Matching is case-insensitive and also covers common aliases, so that rule matches gci, ls and dir.

Read and Edit

Path rules use gitignore patterns. Edit rules cover every built-in tool that changes files; Read rules cover Read, Grep, Glob and @ mentions on a best-effort basis. Rules written as Write(…) or Glob(…) with a path are accepted but never match, so use Edit(…) and Read(…). The leading characters decide where a path starts:

PatternMeansExample
//pathAbsolute path from the filesystem rootRead(//Users/alice/secrets/**)
~/pathFrom your home directoryRead(~/.zshrc)
/pathRelative to the settings sourceEdit(/src/**/*.ts)
path or ./pathRelative to the current directoryRead(./.env)

WebFetch

MCP tools and subagents

6. Which settings file wins

LevelFileWho it affects
1. Managed/Library/Application Support/ClaudeCode/managed-settings.json (macOS), /etc/claude-code/managed-settings.json (Linux, WSL), C:\Program Files\ClaudeCode\managed-settings.json (Windows), MDM or the claude.ai consoleEveryone your organization deploys it to
2. Command line--settings, --allowedTools, --disallowedToolsThis session
3. Local project.claude/settings.local.jsonYou, in this project. Kept out of git.
4. Shared project.claude/settings.jsonEveryone who clones the repository
5. User~/.claude/settings.jsonYou, in every project

For a single value like defaultMode, the highest level wins. Rule lists don’t override each other: allow, ask and deny from every file are merged, then checked deny first. So a deny anywhere beats an allow anywhere, and a deny in your user settings blocks an allow in a project. Nothing below managed settings can undo a managed deny, and an administrator can set allowManagedPermissionRulesOnly to ignore everyone else’s rules.

One safety catch: allow rules and additionalDirectories in a project’s .claude/settings.json only apply after you accept the workspace trust dialog for that folder, which lists them first. Deny and ask rules apply straight away, since they only restrict.

7. Working directories and additionalDirectories

Claude can read and edit inside the folder you started it in. To add more:

.claude/settings.json{
  "permissions": {
    "additionalDirectories": ["../shared-lib/"]
  }
}

Files there follow the same rules as your working directory: reads don’t ask, and edits follow the mode. Adding a folder grants file access only. Claude Code doesn’t load that folder’s .claude/settings.json or hooks, and folders listed in additionalDirectories don’t load its skills or subagents either; --add-dir and /add-dir do.

To stop Claude reading outside these folders at all, set permissions.blockReadsOutsideWorkingDirectories to true. It applies in every mode, bypassPermissions included.

8. What always asks

Some prompts survive every mode, including bypassPermissions, and no allow rule removes them:

Writes to protected paths are never auto-approved outside bypassPermissions: Manual and acceptEdits ask, auto sends them to the classifier, and dontAsk denies. Protected paths include .git, .claude (except a few, such as .claude/worktrees/), .vscode, .idea, .husky, shell startup files such as .bashrc and .zshrc, .gitconfig, .npmrc, .mcp.json and .claude.json. An allow rule like Edit(.claude/**) doesn’t change this.

That’s on top of what a mode normally asks about. In acceptEdits, for example, edits to paths outside your working directories still ask, and so does any Bash command that isn’t a read-only command or one of the filesystem commands acceptEdits lets through.

9. Sandboxing

Rules decide whether a command may start. The sandbox limits what it can reach once it runs. It’s enforced by the operating system (Seatbelt on macOS, bubblewrap on Linux and WSL2), so it holds whether Claude writes rm or /bin/rm. It’s off by default. Run /sandbox to turn it on, or:

~/.claude/settings.json{
  "sandbox": {
    "enabled": true
  }
}

Sandboxed commands can write to the working directory, a temp folder and any added directories, and reach only the network hosts you allow. In auto-allow mode, sandboxed commands run without a prompt; deny rules and command-specific ask rules such as Bash(git push *) still apply.

Answer the prompts that are left from your browser

However you tune modes and rules, some prompts are meant to reach you, and the session waits until you answer. Agent Pets lets you answer them without going back to the terminal:

npx getagentpets init connects Claude Code. Everything runs on your computer, and the terminal prompt keeps working.

Get Agent Pets — was $25, now $6Get Agent Pets — $25

Questions

What are the Claude Code permission modes?

default (shown as Manual) asks before edits and most commands, acceptEdits lets file edits through, plan only reads and plans, auto has a classifier review actions instead of you, dontAsk denies anything that would prompt, and bypassPermissions skips almost every prompt.

If a command matches both an allow rule and a deny rule, which wins?

The deny rule. Claude Code checks deny rules first, then ask, then allow, and the first match decides. A more specific allow rule can’t carve an exception out of a broader deny rule, and a deny in any settings file beats an allow in any other.

Where does “Yes, and don’t ask again” save the rule?

For Bash commands and WebFetch domains, in .claude/settings.local.json at the root of the git repository, so it applies to future sessions anywhere in that repository. File edit approvals aren’t saved: they last until the session ends.

How do I let Claude Code work in a folder outside my project?

Start Claude Code with --add-dir and the path, run /add-dir during a session, or list the folder in permissions.additionalDirectories in a settings file. Files there follow the same rules as your working directory.

Can I control permissions from CLAUDE.md?

No. CLAUDE.md shapes what Claude tries to do, but Claude Code enforces permissions from settings files, /permissions, the permission mode and hooks. Put hard limits in deny rules.

Sources: Claude Code’s documentation on configuring permissions, permission modes, settings, the settings reference, managed settings and sandboxing; claude --help for Claude Code 2.1.287.

More guides