Permission modes
How Claude Code's six permission modes decide what runs without asking, how to switch between them, and the checks no mode can skip.
Every Claude Code session runs in a permission mode. The mode is the baseline answer to one question: when Claude wants to edit a file, run a shell command or reach the network, does it ask you first? You can change the answer at any point in a session, and you can set a different starting mode per machine, per project or across a whole organisation.
This page walks through each mode, how a session picks its starting mode, and the guard rails (protected paths and critical paths) that stay in place whatever you choose. Permission rules sit on top of modes and are covered in Permissions; this page links there where the two meet.
The six modes at a glance
The config value is what you put in settings files, pass on the command line and see in hooks and the SDK. The CLI, IDE extensions and desktop app show friendlier labels.
| Config value | Label in the UI | Runs without a prompt | When I reach for it |
|---|---|---|---|
default | Manual | Reads only | Unfamiliar repos, anything touching production config |
acceptEdits | Accept edits / Edit automatically | Reads, file edits and basic filesystem commands inside your working directories | Iterating on code I will review with git diff afterwards |
plan | Plan | Reads, plus classifier-approved commands when auto mode is available | Scoping a change before any file is touched |
auto | Auto | Almost everything, with a classifier reviewing each risky action | Long tasks where I trust the direction |
dontAsk | Don't ask | Reads and anything you have explicitly pre-approved; everything else is refused | CI jobs and scripts with a fixed allowlist |
bypassPermissions | Bypass permissions | Everything | Throwaway containers and VMs only |
Two notes on naming:
- Manual mode's config value is
default. The CLI also acceptsmanualas an alias anywhere you type a mode, soclaude --permission-mode manualand"defaultMode": "manual"both work. - Modes set the baseline only. A deny rule blocks its tool in every mode, including
bypassPermissions, while allow rules do nothing inbypassPermissionsbecause nothing is being asked anyway. Deny and ask rules do not apply to theEndConversationtool as long as Claude has at least one other tool available.
Things no mode will approve on its own
Some actions always need a human or are refused outright, regardless of mode:
- Any tool matched by an explicit
askrule. - Connector tools your organisation has set to
ask, where that setting reaches Claude Code. - Tools that need you by design: the built-in
AskUserQuestiontool and MCP tools flaggedrequiresUserInteraction. rmandrmdirtargeting a critical path. Neither an allow rule nor aPreToolUsehook returning"allow"can approve these.- The cross-session messaging safeguards described under bypassPermissions.
- File-reading Bash commands that reach outside your working directories while
permissions.blockReadsOutsideWorkingDirectoriesis on (v2.1.257 or later). Unsandboxed retries that need approval also prompt. A command the parser cannot trace, such as one that changes directory twice or opens a subshell, prompts too, unless the Bash sandbox is enforcing the block.
Picking a setup
Modes decide whether Claude asks. The Bash sandbox and outer isolation decide what an approved action can actually reach. These are the combinations I see most often:
| Goal | How to start | Isolation |
|---|---|---|
| Approve every action yourself | claude --permission-mode default | None needed |
| Fewer prompts locally, no classifier | Manual mode, then /sandbox and choose auto-allow (or set sandbox.enabled to true) | Built-in sandbox on macOS, Linux or WSL2 |
| Investigate first, change later | claude --permission-mode plan | None needed |
| Hands-off work | claude --permission-mode auto | Optional, but a sandbox or container adds depth |
| CI with a precise allowlist | claude -p "lint and test" --permission-mode dontAsk --allowedTools "Bash(pnpm lint)" "Bash(pnpm test)" "Read" | Whatever your runner provides |
| Fully unattended | claude -p "<task>" --dangerously-skip-permissions | Required: container, VM or sandbox runtime, running as a non-root user |
In the manual-plus-sandbox setup, deny rules still apply and content-scoped ask rules such as Bash(git push *) still prompt. Cloud sessions ignore dontAsk and bypassPermissions when they come from settings files.
How a session chooses its starting mode
For a session started from a terminal, Claude Code uses the first of these that applies:
- A
--permission-modeflag, or--dangerously-skip-permissions. permissions.defaultModefrom a settings file. Two values are ignored in project files (.claude/settings.jsonand.claude/settings.local.json):autofalls back to the built-in default (and skips any value in~/.claude/settings.json), andbypassPermissionsstarts the session in Manual. Every other value works from any settings file.- The built-in default.
The built-in default depends on how you are running Claude Code. The first matching row wins:
| Situation | Built-in starting mode |
|---|---|
Any settings file sets disableAutoMode to "disable" | default |
claude -p or the Agent SDK | default when the session fetches feature flags. When it does not (third-party provider, telemetry off), auto on v2.1.285 or later, otherwise default. Organisations whose policy withholds the auto default get default |
| HIPAA configuration applied and the session is eligible | default (v2.1.285 or later), with auto still available to switch to |
| Interactive terminal or VS Code extension | auto on v2.1.283 or later. Earlier versions use auto only on Pro, Max and Team plans in sessions that fetch feature flags |
The built-in auto default needs v2.1.228 or later on macOS, Linux and WSL, and v2.1.233 or later on native Windows. Before that, the default is Manual.
A few edge cases worth knowing:
- In the first session after an install or upgrade, Claude Code may choose the mode before feature flags arrive, so that session can start differently.
- If anything selects
autobut auto mode is unavailable (unsupported model, a settings file turning it off, or Anthropic switching it off server-side), the session starts in Manual. - The first time the built-in default puts you in auto mode, the terminal shows a one-off notice at the top of the session and VS Code shows a dismissible card.
- If
~/.claude/settings.jsonsets some otherdefaultModeand nothing else sets one, you keep starting in that mode. On Pro, Max and Team plans, and in sessions that do not fetch feature flags, Claude Code asks once whether you want to switch the setting toauto. Saying no leaves it alone.
For resumed sessions, see Sessions.
Setting a different starting mode
| Scope | What to do |
|---|---|
| One session | Pass a flag, for example claude --permission-mode acceptEdits |
| Every terminal session on this machine | permissions.defaultMode in ~/.claude/settings.json |
| Every terminal session in one project | permissions.defaultMode in the project's .claude/settings.json (any value except auto and bypassPermissions; the VS Code extension ignores project files for this) |
| Every session in the organisation | permissions.defaultMode in managed settings. Users can still switch to auto unless you also set permissions.disableAutoMode to "disable" |
When several files set permissions.defaultMode, normal settings precedence applies, so project and managed values beat your user file. My own laptop starts every session in plan mode, because I prefer to see the approach before anything changes:
{
"permissions": {
"defaultMode": "plan"
}
}
Saved in ~/.claude/settings.json, the next session shows ⏸ plan mode on in the status bar.
Organisations with the HIPAA configuration
When the HIPAA configuration applies, the built-in auto default is switched off. Terminal and VS Code sessions start in Manual unless something else chooses a mode, and the terminal shows Auto mode isn't the default for your organization · Shift+Tab to switch (VS Code shows nothing). Auto and bypass remain available:
- Switch with
Shift+Tabor your interface's mode control. - Start in auto with
--permission-mode auto, or withpermissions.defaultMode: "auto"in user or managed settings. - Remove auto entirely with
permissions.disableAutoMode: "disable"in managed settings. - Block bypass with
permissions.disableBypassPermissionsMode: "disable"in managed settings.
This needs v2.1.285 or later.
Switching modes during a session
Terminal and JetBrains
Press Shift+Tab to cycle. From auto, the first press drops you to default, then the cycle continues default, acceptEdits, plan. Optional modes join after plan, with bypassPermissions first and auto last. The JetBrains plugin runs the CLI in the IDE terminal, so the same keys and flags apply there.
The status bar tells you where you are: ⏸ manual mode on (grey), ⏵⏵ accept edits on, ⏸ plan mode on, ⏵⏵ auto mode on, ⏵⏵ don't ask on or ⏵⏵ bypass permissions on.
Not every mode is in the cycle:
autoappears when auto mode is available, and cycling to it needs no confirmation.bypassPermissionsappears only if you launched with--permission-mode bypassPermissions,--dangerously-skip-permissions,--allow-dangerously-skip-permissions, ordefaultMode: "bypassPermissions"in user,--settingsor managed settings. The--allow-flag adds bypass to the cycle without switching to it.dontAsknever appears. Use--permission-mode dontAsk.
There is also a shortcut from Bash prompts: in Manual and acceptEdits, when auto is available, a Bash permission prompt offers Yes, and switch to auto mode (v2.1.247 or later). PowerShell prompts do not offer it, and neither do prompts forced by your own ask rules or a hook, since auto mode would still show those.
The --permission-mode flag works the same with -p for headless runs.
VS Code
Click the mode indicator under the prompt box. The labels are Manual, Edit automatically, Plan, Auto and Bypass permissions.
New conversations start in the first of these that applies:
claudeCode.initialPermissionModein your VS Code user settings. It acceptsdefault,manual,acceptEdits,planorbypassPermissions, but notauto.- The mode you last picked from the indicator, if it was Manual, Edit automatically or Auto. Plan and Bypass only last for that conversation.
permissions.defaultModefrom managed settings or~/.claude/settings.json.- The built-in default.
The extension never reads project settings for the starting mode. With claudeCode.claudeProcessWrapper set, steps 3 and 4 are skipped and conversations start in Manual unless step 1 or 2 applies. Bypass only appears once you turn on Allow dangerously skip permissions in the extension settings; without it a bypass value from step 1 or 3 starts in Manual. See VS Code for more.
Desktop app
In the Code tab, use the mode selector beside the send button. Auto appears when available. Bypass needs the Allow bypass permissions mode toggle on Pro and Max, and organisation policy on Team and Enterprise. The desktop app reads the same defaultMode as the CLI. A mode you choose in the selector is remembered per folder and wins over defaultMode, except Plan, which only applies to the current session. The Cowork tab has its own separate modes. See Desktop.
Web, mobile and Remote Control
On claude.ai/code use the dropdown beside the prompt; in the mobile app tap + then Permission.
- Cloud sessions offer Accept edits, Plan and Auto. Cloud sessions pre-approve file edits anyway, so "Accept edits" is really
default. They still honourdefaultMode: "acceptEdits"from settings. Auto appears only if your organisation allows it and the model supports it. Bypass is not offered. - Remote Control sessions offer Manual, Accept edits, Plan and Auto, never Bypass. The dropdown mirrors the local session's mode, including changes made in the terminal. The local machine must be signed in with a claude.ai account (API keys are not supported). You can set the starting mode when launching, for example
claude remote-control --permission-mode plan.
acceptEdits: edit freely, review later
acceptEdits lets Claude create and change files in your working directory without asking. It also auto-approves a small set of filesystem commands: mkdir, touch, rm, rmdir, mv, cp and sed, including when they are prefixed with harmless environment variables (LANG=C, NO_COLOR=1) or wrappers such as timeout, nice and nohup.
That approval only covers paths inside your working directory and additionalDirectories, after the symlink check resolves them. Still prompted: anything outside that scope, protected paths, critical-path removals, and every other Bash command apart from the built-in read-only set.
With the PowerShell tool enabled, Set-Content, Add-Content, Clear-Content and Remove-Item (and their usual aliases) are also auto-approved on in-scope paths. A positional argument containing a quote character, such as Set-Content .\todo.txt "Don't forget", still prompts because its quoted and unquoted readings differ. Pass text via -Value to avoid that.
From Manual, one press of Shift+Tab gets you here, or start with claude --permission-mode acceptEdits.
plan: research before changing anything
In plan mode Claude reads, explores with shell commands and writes up a plan, but does not edit your source until you approve. How shell commands are handled during planning depends on the first matching case:
- Interactive terminal with bypass permissions available: no classifier and no prompt for planning commands (see bypassPermissions for the few exceptions).
- Auto mode available and
useAutoModeDuringPlanon (the default): the classifier reviews commands, apart from critical-path removals. Approved ones run, rejected ones are blocked. - Otherwise: anything outside the read-only set prompts, even if the sandbox's auto-allow mode is on.
Enter plan mode with Shift+Tab, prefix a single prompt with /plan, or launch with claude --permission-mode plan. Press Shift+Tab again to leave without approving.
Approving the plan
When the plan is ready you get these choices:
- Yes, and use auto mode: approve and continue in auto. If auto is unavailable it reads Yes, auto-accept edits; if the session started with bypass enabled it reads Yes, and switch to BYPASS PERMISSIONS (no further prompts) for this session.
- Yes, manually approve edits: approve and review each edit.
- No, keep planning: stay in plan mode and give feedback.
Ctrl+G opens the plan in your editor so you can change it before Claude proceeds. With showClearContextOnPlanAccept enabled, an extra first option approves and clears the planning context. Approving also gives the session a generated title unless you have already named it.
To make plan the project default for terminal sessions, set defaultMode to plan in .claude/settings.json. For VS Code, use claudeCode.initialPermissionMode instead.
auto: a classifier instead of prompts
Auto mode removes routine prompts by having a second model, the classifier, review actions before they run. It blocks things that go beyond what you asked for, target infrastructure it does not recognise, or look like they were steered by hostile content Claude read. Explicit ask rules still prompt.
Warning: Auto mode cuts prompts, it does not guarantee safety. Use it where you trust the overall direction of the work, and keep sensitive steps behind ask or deny rules.
The classifier also reviews each SendMessage Claude sends to another agent (v2.1.222 or later), both in auto mode and in plan mode when the classifier is active. Auto mode also nudges Claude to keep going instead of stopping for clarifying questions, unless your prompt or a skill relies on asking. If you want that more autonomous style while still being prompted, try the Proactive output style.
Availability
All of these must hold:
- Plan: any plan. On Team and Enterprise it is on by default; admins can turn it off with
permissions.disableAutoMode: "disable"in managed settings. - Model on the Anthropic API or Claude Platform on AWS: Opus 4.6 or later, Sonnet 4.6 or later, Haiku 5.5, or a Fable model.
- Model on Bedrock, Google Cloud's Agent Platform, Microsoft Foundry and signed-in Claude apps gateway sessions: Sonnet 5 or later, Opus 4.7 or later, Haiku 5.5, or a Fable model. Haiku 5.5 on these needs v2.1.293 or later. Older models (Sonnet 4.5, Opus 4.5, Haiku 4.5, claude-3) are never supported.
- Provider: on by default for all of the above.
If auto shows as unavailable, check those requirements and look for disableAutoMode in any settings file. Anthropic can also switch it off server-side or reject it for an account; a session that hears either answer keeps auto off until it ends. A separate message saying auto mode "cannot determine the safety" of an action means a classifier request failed: usually transient, though on Bedrock it repeats until your account can invoke the named model. See Errors.
If you put defaultMode: "auto" in settings and still start in Manual with no error, it is almost certainly in a project file. Move it to ~/.claude/settings.json.
Between v2.1.158 and v2.1.206, cloud providers needed CLAUDE_CODE_ENABLE_AUTO_MODE=1. The variable is still accepted but does nothing from v2.1.207.
When managed settings turn auto off via an admin-deployed source, a running auto session leaves it and shows auto mode disabled by settings (before v2.1.251 it kept auto until the session ended).
Server-side review
Rather than sending its own classifier requests, Claude Code can ask the server to review actions as part of the normal model request. This applies to direct Anthropic API connections (interactive terminal from v2.1.271 on Pro, Max and Team, v2.1.278 on Enterprise and API accounts; -p, SDK, VS Code and desktop from v2.1.281; and from v2.1.282 any session that does not fetch feature flags), to cloud providers and ANTHROPIC_BASE_URL gateways (v2.1.278), and to signed-in Claude apps gateway sessions (v2.1.280).
If the server does not review the session, typically because a gateway strips the review, Claude Code falls back to its own classifier calls and may show a notice about classifier charges. If the server gives no verdict for a particular action, the action is denied rather than run unreviewed; after ten verdict-less responses in a row the turn stops.
Set CLAUDE_CODE_AUTO_MODE_SERVER=0 to always use local classifier requests (v2.1.281 or later on direct API connections), or 1 to opt in where it is not yet on. CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 with the server variable unset also stops server review.
What gets blocked and allowed by default
The classifier trusts your working directory and the git remotes configured when the session started. Remotes added or changed mid-session are not trusted, and everything else counts as external until an admin describes it in auto mode configuration.
Blocked by default, grouped roughly:
- Running untrusted code: piping downloads into a shell, launching other unattended agent loops (for example anything using
--dangerously-skip-permissions,--no-sandboxor--yes-always), and flags that switch off safety checks such as--insecure. - Data leaving: sending sensitive data to external endpoints; printing live credentials; committing or pushing changes that would send secrets outside the repo or widen what a deploy publishes; pushing secrets or confidential material to a public repo; putting sensitive details (internal paths, code names, live API data such as emails or account IDs) into PRs, issues, commits or comments on public or untrusted repos; links to paste or diagram services that carry the content in the URL (v2.1.261); content from sensitive local stores such as SSH keys, cloud credentials, browser profiles, shell history or session transcripts entering a commit, PR, gist or package (v2.1.203).
- Destructive operations: irreversibly deleting files that existed before the session;
git reset --hard,git checkout -- .,git restore .,git clean -fd,git stash drop,git stash clear; force pushes;git commit --amendon a commit Claude did not create this session or that has been pushed (message-only rewords of Claude's own unpushed commits are fine);terraform destroy,pulumi destroy,cdk destroy,terragrunt destroyand destructive plans; mass deletion in cloud storage; tearing down stateful resources you did not name; wildcard or age-based deletes in/tmp,$TMPDIRand other shared scratch areas; recursive forced deletes of an unresolved shell variable (v2.1.205). - Infrastructure and access: production deploys and migrations; changes to shared infrastructure, protected IaC scopes, DNS, TLS certificates or secret managers; granting IAM or repo permissions; production feature flag changes; draining cluster nodes; cluster-wide writes beyond the named resource; DaemonSets and admission webhooks; interactive shells or port-forwards into sensitive targets; public tunnels and reverse shells.
- Bypassing review and controls: merging unapproved PRs, approving Claude's own PR, disabling CI checks; posting comments that trigger automation (
atlantis apply,/deploy); weakening security tests; repointing API base URLs, proxies, webhooks or registry mirrors at unrelated third parties; changing push targets withgit remote set-urloraddunless you named the remote; opening PRs against, forking or pushing to other repos or organisations you did not name; bypassing an internal package registry. - Self-modification: writing to Claude Code's
.jsonltranscripts under~/.claude/projects/(v2.1.205), and sending keystrokes to its own tmux pane. - Host escape (v2.1.257): instance-metadata credentials such as
169.254.169.254, using the machine's own service identity, reading host credentials, scanning sibling containers or the node, and reaching public hosts via tunnels or rewritten resolvers. If your setup legitimately needs one of these, describe it in a Host containment entry inautoMode.environment. - Browser: Claude in Chrome actions that could send page content, cookies or credentials off-origin.
Allowed by default:
- Local file operations in the working directory.
- Installing dependencies declared in lock files or manifests.
- Reading
.envand sending credentials to the API they belong to. - Read-only HTTP requests.
- Pushing to any branch of the current repository, including the default branch (but not branches named like deploy targets, such as
productionorgh-pages, which are judged on their own). - Deleting jobs Claude created earlier in the session.
- Working on security code, configs and threat models.
- Messages between agents in the same multi-agent session.
- Sending data to trusted domains, buckets and services listed in
environment. - Chrome navigation to trusted internal domains, localhost or URLs you named.
Run claude auto-mode defaults to print the full lists as JSON. To keep a human checkpoint before pushes or PRs while staying in auto, add permissions.ask rules such as Bash(git push *).
With the sandbox on, sandboxed commands get no network by default; Claude lists the hosts each command needs and the classifier approves them with the command. See per-command allowed domains.
The first read outside your working directories
With permissions.blockReadsOutsideWorkingDirectories off, reads run freely in auto mode. The first time Read, Grep or Glob touches a path outside the working directories, though, Claude Code asks once (not in -p or background sessions). The options are: allow and stop asking; refuse and set the block setting to true in your user settings for good; refuse and ask again next time; or allow once and ask again next time. To open a blocked path later, use /add-dir.
What you say in conversation counts
Telling Claude "don't push" or "wait for my review before deploying" is treated as a block signal, even for actions the defaults allow. The boundary lasts until you lift it, and Claude cannot decide for itself that the condition has been met. These are not stored as rules, so compaction can drop them. Use a deny rule when you need a guarantee.
The reverse also works. Approving a blocked action in conversation can clear it, but only if you name the action and the specific risky detail ("force-push feature/login to origin" rather than "you can force-push"). An approval covers that one action unless you make it standing. For recurring patterns, add them to autoMode.allow instead. Some blocks cannot be cleared this way; leave auto mode and answer the prompt.
When auto mode steps back
- Blocked action: you get a notification and the action appears in
/permissionsunder Recently denied, whererretries it with manual approval. - Repeated blocks: three in a row or twenty in total pauses auto and returns to prompting. Approving the prompted action resumes auto. These thresholds are fixed; the total resets only when it triggers. In
-pwithout--permission-prompt-toolthe action simply does not run and Claude carries on. - No verdict: if the classifier's own request is refused by a separate safety check or its answer will not parse, the action is denied quietly.
- Mode changed mid-check: a verdict the new mode would not have requested is discarded and you are prompted (or denied in
dontAsk).
Frequent blocks usually mean the classifier lacks context about your infrastructure. Report false positives with /feedback and have an admin fill in auto mode configuration.
How each action is evaluated
- Allow, ask and deny rules resolve first, with exceptions: protected-path writes still go to the classifier; critical-path removals cannot be allowed;
requiresUserInteractionMCP tools and org-askconnector tools prompt you; commands carrying per-command domains go to the classifier; content-matching ask rules prompt; a symlink that resolves to a protected path prompts. - Reads and working-directory edits are approved, except protected paths and the first outside read. Under server-side review, read-only and sandboxed shell commands wait for that review.
- Everything else goes to the classifier.
- If blocked, Claude gets the reason, usually as the rule name such as
[Data Exfiltration].
A mod that handles tool.check can approve an action before step 3.
On entering auto mode, broad allow rules that amount to arbitrary code execution are suspended: Bash(*), PowerShell(*), wildcarded interpreters like Bash(node*), package-manager run commands, Agent rules and Monitor rules. Narrow rules such as Bash(make test) survive, and the dropped ones return when you leave auto.
Before commands that would discard work, Claude Code runs git status itself and shows the result to the classifier. The classifier sees your messages, non-read-only tool calls and CLAUDE.md, but not tool results, so injected text in a file cannot talk to it directly. A PostToolUse hook can add context via classifierContext (v2.1.236); see Hooks.
Subagents are checked three times: the task description at spawn, each action while running (any permissionMode in the subagent's frontmatter is ignored), and the final report before the parent reads it. Flagged reports still arrive, with a security warning on top.
Cost and latency: the classifier uses Sonnet 5 by default, not your /model choice. If your session model is Sonnet 4.6 or availableModels excludes Sonnet 5, it uses the session model instead (or an Opus model for Fable sessions; on non-Anthropic providers that is ANTHROPIC_DEFAULT_OPUS_MODEL, or Opus 5). On Enterprise and API-billed accounts, and on Bedrock, Agent Platform, Foundry and Claude Platform on AWS, classifier calls count towards usage. Reads and in-directory edits skip it, so the overhead is mostly shell and network actions.
dontAsk: pre-approved only
dontAsk turns every would-be prompt into a denial. Claude can still read inside your working directories, run read-only Bash, use anything in permissions.allow, and run calls a PreToolUse hook approves. Ask-rule matches, AskUserQuestion, org-ask connector tools and requiresUserInteraction MCP tools are all denied, as are critical-path removals even if allowed. The status bar shows ⏵⏵ don't ask on. Cloud sessions ignore it from settings. Start it with claude --permission-mode dontAsk.
bypassPermissions: no checks at all
Bypass removes prompts and safety checks, including for protected paths. The always-checked actions still apply, Remove-Item denials still apply, and Claude cannot read another organisation's public artifact because that needs an approval this mode never asks for.
Two cross-session messaging safeguards remain: the isolatePeerMachines approval for messages to sessions on other machines, and, where no crossSessionInbound value applies, holding inbound messages from your other sessions unless the sender is also in bypass.
In interactive terminal sessions with bypass available, plan mode's blocks are not enforced: Claude is told to plan, but an edit it attempts would run. Ask rules and critical-path removals still prompt. Outside an interactive terminal (-p, SDK, VS Code chat), plan mode keeps its blocks.
Warning: Only use bypass inside an isolated container or VM, ideally without internet access. It gives no protection against prompt injection. Auto mode is the safer way to cut prompts.
Enable it at launch with claude --permission-mode bypassPermissions, the equivalent --dangerously-skip-permissions, or defaultMode: "bypassPermissions" in a non-project settings file. You cannot switch into it from a session that started without it, and --restricted (v2.1.248) refuses it entirely.
The first interactive launch shows a warning dialog. Accepting sets skipDangerousModePermissionPrompt to true in ~/.claude/settings.json; declining exits. Headless runs show no dialog, and --bg background sessions are refused until you have accepted it interactively once.
On Linux and macOS, running as root or under sudo fails with:
--dangerously-skip-permissions cannot be used with root/sudo privileges for security reasons
The check is skipped inside a recognised sandbox; the dev container runs as a non-root user for this reason. Admins can block bypass with permissions.disableBypassPermissionsMode: "disable".
Protected paths
Writes to certain paths are never auto-approved, to stop accidental damage to repository state and Claude's own configuration.
| Mode | Write to a protected path |
|---|---|
default, acceptEdits | Prompted |
plan | Allowed in interactive terminal sessions with bypass available; otherwise classifier if auto is available during planning, prompt if not |
auto | Classifier (but --restricted sessions cannot have the classifier approve these) |
dontAsk | Denied |
bypassPermissions | Allowed |
Allow rules such as Edit(.claude/**) do not change this, because the check runs before allow rules. When prompted for the project's .claude/ folder or ~/.claude/, you can choose a session-scoped "Yes, and allow Claude to edit files in..." option.
Protected directories: .git, .config/git, .vscode, .idea, .husky, .cargo, .devcontainer, .yarn, .mvn, .claude, and any directory loaded with --plugin-dir. Inside .claude the exceptions are Claude's worktrees under .claude/worktrees/, the current session's plan files (in ~/.claude/plans/ or your plansDirectory), a background session's own ~/.claude/jobs/<id>/tmp/, and Markdown files in auto memory and subagent memory directories (not under --restricted).
Protected files:
- Git:
.gitconfig,.gitmodules - Shell:
.bashrc,.bash_profile,.bash_login,.bash_aliases,.bash_logout,.zshrc,.zprofile,.zshenv,.zlogin,.zlogout,.profile,.envrc - JavaScript tooling:
.npmrc,.yarnrc,.yarnrc.yml,.pnp.cjs,.pnp.loader.mjs,.pnpmfile.cjs,bunfig.toml,.bunfig.toml - Bazel:
.bazelrc,.bazelversion,.bazeliskrc - Hooks managers:
.pre-commit-config.yaml,lefthook.yml,lefthook.yaml,.lefthook.yml,.lefthook.yaml - Wrappers:
gradle-wrapper.properties,maven-wrapper.properties - Others:
.devcontainer.json,.ripgreprc,pyrightconfig.json,.mcp.json,.claude.json
Critical paths
Critical paths are the places an rm or rmdir must never be waved through: the filesystem root, any top-level directory (/usr, /etc, /srv), your home directory, Windows drive roots and their top-level folders, your working directory and its parents, and globs directly under your additional working directories (for example rm -rf <dir>/*, though not rm -rf <dir> itself).
These forms also count, because Claude Code cannot be sure what they expand to:
| Pattern | Example | Risk |
|---|---|---|
| Glob or trailing slash under a variable | rm -rf "$OUT"/* | Empty variable means removing from / |
| Same under an unassigned positional parameter | rm -rf "$2"/* | Expands to root |
| Variable plus a common top-level name | rm -rf "$BASE/usr" | Empty variable means /usr |
Variable assigned from $(pwd) or $(git rev-parse --show-toplevel) | R=$(pwd); rm -rf "$R" | Could be your repo root |
| Target that is only a command substitution, recursive | rm -rf "$(find-target)" | Cannot be checked first |
| Critical path followed by a substitution | rm -rf ~/$(echo) | Empty expansion leaves ~ |
| Backslash-only target | rm -rf "\\" | Git Bash reads it as the drive root |
Some trailing /* or /*/ forms | rm -rf build/*/* | Reach is unknowable up front |
Claude Code looks inside subshells, brace groups, command and process substitution, and inline sh -c/bash -c scripts. Double-quoted inline scripts are expanded by the outer shell first, so find . -exec sh -c "rm -rf \"$1\"/*" _ {} \; is flagged; the single-quoted form that binds $1 is not.
To get a flagged command through: guard variables with "${OUT:?}"/* or use a literal path; for normally-set variables like $HOME, or variables from directory-printing substitutions, use a literal path; for pure substitutions, run the substitution first and delete the literal results.
Escape hatches via environment variable: CLAUDE_CODE_DISABLE_SUBSTITUTION_RM_PROMPT=1 for substitution-only targets, CLAUDE_CODE_DISABLE_INLINE_SHELL_RM_PROMPT=1 for critical paths typed in -c scripts.
What each mode does with a critical-path removal
| Mode | Result |
|---|---|
default, acceptEdits | Prompt |
plan | Prompt; handled as in auto when the classifier reviews planning commands and bypass is unavailable |
auto | Terminal prompt with a two-minute countdown; denied immediately anywhere a terminal prompt is impossible (-p, SDK, VS Code chat, desktop) |
dontAsk | Denied |
bypassPermissions | Prompt, with the countdown in the terminal |
An explicit ask rule turns it into a normal prompt with no countdown. A PermissionRequest hook can answer in modes that prompt. When the countdown expires, the command is denied and Claude is told what to do instead; pressing any key stops the clock. After three expired prompts in a session, further removals are denied immediately until you send a new message. This handling needs v2.1.281; CLAUDE_CODE_DISABLE_DANGEROUS_RM_TIMEOUT=1 turns it off (auto then sends removals to the classifier, bypass prompts with no time limit).
Remove-Item and cmd on Windows
With the PowerShell tool on, Remove-Item gets its own rules: system paths (roots, top-level folders, home) are denied in every mode; wildcard targets (bare *, or ending /* or \*, including $dir/*) are denied in every mode before the classifier sees them; recursive removal of your working directory or a parent is treated like any other approval-needing action (bypass skips this one). From v2.1.283 the system-path rule also covers rd, rmdir, del and erase run through cmd. A PowerShell variable after literal text counts as empty, so cmd /c rd /s /q "C:\$x" is denied. CLAUDE_CODE_DISABLE_POWERSHELL_CMD_RM_DENY=1 (environment only, not a settings env block) turns off the cmd check.