Skip to content

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 valueLabel in the UIRuns without a promptWhen I reach for it
defaultManualReads onlyUnfamiliar repos, anything touching production config
acceptEditsAccept edits / Edit automaticallyReads, file edits and basic filesystem commands inside your working directoriesIterating on code I will review with git diff afterwards
planPlanReads, plus classifier-approved commands when auto mode is availableScoping a change before any file is touched
autoAutoAlmost everything, with a classifier reviewing each risky actionLong tasks where I trust the direction
dontAskDon't askReads and anything you have explicitly pre-approved; everything else is refusedCI jobs and scripts with a fixed allowlist
bypassPermissionsBypass permissionsEverythingThrowaway containers and VMs only

Two notes on naming:

  • Manual mode's config value is default. The CLI also accepts manual as an alias anywhere you type a mode, so claude --permission-mode manual and "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 in bypassPermissions because nothing is being asked anyway. Deny and ask rules do not apply to the EndConversation tool 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 ask rule.
  • Connector tools your organisation has set to ask, where that setting reaches Claude Code.
  • Tools that need you by design: the built-in AskUserQuestion tool and MCP tools flagged requiresUserInteraction.
  • rm and rmdir targeting a critical path. Neither an allow rule nor a PreToolUse hook 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.blockReadsOutsideWorkingDirectories is 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:

GoalHow to startIsolation
Approve every action yourselfclaude --permission-mode defaultNone needed
Fewer prompts locally, no classifierManual mode, then /sandbox and choose auto-allow (or set sandbox.enabled to true)Built-in sandbox on macOS, Linux or WSL2
Investigate first, change laterclaude --permission-mode planNone needed
Hands-off workclaude --permission-mode autoOptional, but a sandbox or container adds depth
CI with a precise allowlistclaude -p "lint and test" --permission-mode dontAsk --allowedTools "Bash(pnpm lint)" "Bash(pnpm test)" "Read"Whatever your runner provides
Fully unattendedclaude -p "<task>" --dangerously-skip-permissionsRequired: 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:

  1. A --permission-mode flag, or --dangerously-skip-permissions.
  2. permissions.defaultMode from a settings file. Two values are ignored in project files (.claude/settings.json and .claude/settings.local.json): auto falls back to the built-in default (and skips any value in ~/.claude/settings.json), and bypassPermissions starts the session in Manual. Every other value works from any settings file.
  3. The built-in default.

The built-in default depends on how you are running Claude Code. The first matching row wins:

SituationBuilt-in starting mode
Any settings file sets disableAutoMode to "disable"default
claude -p or the Agent SDKdefault 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 eligibledefault (v2.1.285 or later), with auto still available to switch to
Interactive terminal or VS Code extensionauto 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 auto but 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.json sets some other defaultMode and 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 to auto. Saying no leaves it alone.

For resumed sessions, see Sessions.

Setting a different starting mode

ScopeWhat to do
One sessionPass a flag, for example claude --permission-mode acceptEdits
Every terminal session on this machinepermissions.defaultMode in ~/.claude/settings.json
Every terminal session in one projectpermissions.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 organisationpermissions.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+Tab or your interface's mode control.
  • Start in auto with --permission-mode auto, or with permissions.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:

  • auto appears when auto mode is available, and cycling to it needs no confirmation.
  • bypassPermissions appears only if you launched with --permission-mode bypassPermissions, --dangerously-skip-permissions, --allow-dangerously-skip-permissions, or defaultMode: "bypassPermissions" in user, --settings or managed settings. The --allow- flag adds bypass to the cycle without switching to it.
  • dontAsk never 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:

  1. claudeCode.initialPermissionMode in your VS Code user settings. It accepts default, manual, acceptEdits, plan or bypassPermissions, but not auto.
  2. The mode you last picked from the indicator, if it was Manual, Edit automatically or Auto. Plan and Bypass only last for that conversation.
  3. permissions.defaultMode from managed settings or ~/.claude/settings.json.
  4. 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 honour defaultMode: "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:

  1. Interactive terminal with bypass permissions available: no classifier and no prompt for planning commands (see bypassPermissions for the few exceptions).
  2. Auto mode available and useAutoModeDuringPlan on (the default): the classifier reviews commands, apart from critical-path removals. Approved ones run, rejected ones are blocked.
  3. 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-sandbox or --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 --amend on 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 destroy and destructive plans; mass deletion in cloud storage; tearing down stateful resources you did not name; wildcard or age-based deletes in /tmp, $TMPDIR and 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 with git remote set-url or add unless 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 .jsonl transcripts 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 in autoMode.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 .env and 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 production or gh-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 /permissions under Recently denied, where r retries 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 -p without --permission-prompt-tool the 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

  1. Allow, ask and deny rules resolve first, with exceptions: protected-path writes still go to the classifier; critical-path removals cannot be allowed; requiresUserInteraction MCP tools and org-ask connector 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.
  2. 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.
  3. Everything else goes to the classifier.
  4. 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.

ModeWrite to a protected path
default, acceptEditsPrompted
planAllowed in interactive terminal sessions with bypass available; otherwise classifier if auto is available during planning, prompt if not
autoClassifier (but --restricted sessions cannot have the classifier approve these)
dontAskDenied
bypassPermissionsAllowed

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:

PatternExampleRisk
Glob or trailing slash under a variablerm -rf "$OUT"/*Empty variable means removing from /
Same under an unassigned positional parameterrm -rf "$2"/*Expands to root
Variable plus a common top-level namerm -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, recursiverm -rf "$(find-target)"Cannot be checked first
Critical path followed by a substitutionrm -rf ~/$(echo)Empty expansion leaves ~
Backslash-only targetrm -rf "\\"Git Bash reads it as the drive root
Some trailing /* or /*/ formsrm -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

ModeResult
default, acceptEditsPrompt
planPrompt; handled as in auto when the classifier reviews planning commands and bypass is unavailable
autoTerminal prompt with a two-minute countdown; denied immediately anywhere a terminal prompt is impossible (-p, SDK, VS Code chat, desktop)
dontAskDenied
bypassPermissionsPrompt, 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.