Claude Code starts in auto mode by default — all six permission modes compared
With v2.1.283 or later a terminal session starts in auto mode on every plan. What the six modes allow, and the two defaultMode values project settings ignore.
Contents
A permission mode sets what Claude can do in a session without asking you first. It is the baseline that applies to anything your allow and deny rules don't already decide.
There are six modes. Two of them cannot be set from project settings at all, which is the detail that most often explains "my defaultMode isn't doing anything".
KEY POINT
What you will learn
- What each of the six modes runs without asking
- Which mode a session starts in, and the order that decides it
- The two values that silently do not apply in project settings
The six modes
| Mode | What runs without asking | Best for |
|---|---|---|
default | Reads only | Reviewing every action yourself, sensitive work |
acceptEdits | Reads, file edits, and common filesystem commands (mkdir, touch, mv, cp) | Iterating on code you're reviewing |
plan | Reads, plus classifier-approved commands when auto mode is available | Exploring a codebase before changing it |
auto | Everything, with background safety checks | Long tasks, reducing prompt fatigue |
dontAsk | Reads and pre-approved tools; anything that would prompt is denied | Locked-down CI and scripts |
bypassPermissions | Everything | Isolated containers and VMs only |
The mode that reviews every action is labelled Manual in the CLI, the VS Code and JetBrains extensions and the desktop app. Its config value is default, and the CLI also accepts manual as an alias (v2.1.200 or later).
Modes set the baseline only. Deny rules block in every mode, including bypassPermissions, and allow rules have no effect in bypassPermissions. The mode decides what happens to everything your rules don't match.
Which mode a session starts in
With Claude Code v2.1.283 or later, auto is the built-in starting permission mode for interactive terminal and VS Code sessions on every plan. On earlier versions it is the built-in starting permission mode only on Pro, Max, and Team plans.
For a new terminal session, Claude Code takes the mode from the first of these that applies:
- The
--permission-modeflag, or--dangerously-skip-permissions permissions.defaultModein a settings file- The built-in default
Two values silently don't apply in project settings
Set "auto" in .claude/settings.json or .claude/settings.local.json and it does not take effect — and Claude Code then uses the built-in default rather than a defaultMode from ~/.claude/settings.json. Set "bypassPermissions" in those two files and it doesn't take effect either: the session starts in Manual mode. Every other value applies from any settings file. The settings documentation also notes that before v2.1.257, bypassPermissions did take effect from any file.
Writing the setting
{
"permissions": {
"defaultMode": "acceptEdits"
}
}
Put it in ~/.claude/settings.json for a personal default across projects, .claude/settings.json to share with the project, or .claude/settings.local.json for yourself in this repository — keeping the exception above in mind.
Picking one
- Everyday development:
acceptEdits. Edits stop interrupting you, and you review them together withgit diffafterwards - An unfamiliar codebase, or design work:
plan. Nothing is changed, so you can hand over investigation safely, then switch once you agree with the plan - Shared project settings: stay on the cautious side. Anyone who wants to move faster can override in their own
settings.local.json - CI and disposable containers:
dontAskfor a strict allowlist, orbypassPermissionsonly where Claude Code cannot damage anything
For what bypassPermissions actually turns off and the conditions the documentation sets for it, see When bypassPermissions is safe to use. For non-interactive runs, see Running Claude Code headless in CI.
Switching temporarily
| How | Scope |
|---|---|
Shift+Tab | The current session; cycles through the available modes |
claude --permission-mode plan | The starting mode for that session |
claude -p ... --permission-mode acceptEdits | One non-interactive run |
None of these rewrite a settings file. "Normally acceptEdits, today just investigating" is a Shift+Tab or a flag, not a config change.
Summary
- Six modes:
default(Manual),acceptEdits,plan,auto,dontAsk,bypassPermissions - Deny rules apply in every mode; allow rules do nothing in
bypassPermissions - With v2.1.283 or later, terminal and VS Code sessions start in auto on every plan unless a flag or
defaultModesays otherwise autoandbypassPermissionsdo not take effect from.claude/settings.jsonor.claude/settings.local.jsonShift+Taband--permission-modeswitch temporarily without touching your settings
FAQ
- Which mode does a session start in?
- With Claude Code v2.1.283 or later, auto is the built-in starting mode for terminal and VS Code sessions on every plan; on earlier versions only Pro, Max and Team plans got it. A --permission-mode flag wins over everything, then permissions.defaultMode from a settings file, then the built-in default.
- Does acceptEdits also run commands automatically?
- No. It auto-approves reads, file edits and common filesystem commands such as mkdir, touch, mv and cp. Anything else still prompts or follows your allow rules.
- Where is defaultMode covered in the official docs?
- The key has its own entry, permissions.defaultMode, in the settings reference, and the settings page's troubleshooting section states that auto and bypassPermissions do not take effect from project or local settings. Before v2.1.257, bypassPermissions took effect from any file.
- Why does my defaultMode in .claude/settings.json do nothing?
- auto and bypassPermissions do not take effect from .claude/settings.json or .claude/settings.local.json. Setting bypassPermissions there starts the session in Manual mode instead. Every other value applies from any settings file.
Questions & answers
Q. In auto mode the classifier blocked installing files into /etc/systemd/system, and no permission prompt appeared. Is there a documented way to get it through?
A classifier block is not an inline prompt. You approve it afterwards, somewhere else. The docs put it this way: "Claude Code shows a notification and lists the action in /permissions under the Recently blocked tab, where you can approve the action so Claude may retry".
That approval is not a rule, though: "Approving an action doesn't add a permission rule. In auto mode, a retried action goes through the check again, so it can be blocked again."
Whether anything can clear the block depends on which tier the matched rule sits in. Inside the classifier, precedence runs in four tiers.
| Tier | Behaviour |
|---|---|
hard_deny | Blocks unconditionally. "User intent and allow exceptions don't apply" |
soft_deny | Blocks next; user intent and allow exceptions can override these |
autoMode.allow | Overrides matching soft_deny rules as exceptions |
| Explicit user intent | Overrides the remaining soft blocks, but your message must "directly and specifically describe the exact action Claude is about to take" |
So the first step is finding out which tier applies. The text in square brackets in the denial is the rule's name, so you can look that rule up.
# Print the full default rule lists as JSON
claude auto-mode defaults
# Read one rule's full wording by label
claude auto-mode defaults --label 'Git Destructive'
For a soft_deny rule, naming the action and the specific thing that makes it dangerous clears it — "Naming the verb alone clears nothing". But "an approval covers the destructive action you named", so it is one action at a time. To stop approving a routine pattern repeatedly, add it to autoMode.allow.
For a hard_deny rule there is no route through inside auto mode. The documented remedy is one line: "To run a step it won't clear, leave auto mode and answer the permission prompt." Cycle the mode with Shift+Tab and approve the ordinary prompt.
The label name could not be confirmed in the docs
The [Unauthorized Persistence] label in the report could not be found in the permission-modes or auto-mode configuration docs. The example they do give is [Data Exfiltration], with Git Destructive and Test Artifacts appearing incidentally. No exhaustive label list is published — the docs tell you to run claude auto-mode defaults to print the lists for your own environment.
One more thing to know: entering auto mode drops broad allow rules — blanket Bash(*), wildcarded interpreters such as Bash(python*), package-manager run commands, and Agent and Monitor rules. "Narrow rules like Bash(npm test) stay in effect", so scope a rule tightly if you want it to survive.
For how the modes differ, see Claude Code starts in auto mode by default and all six permission modes compared.
Q. Under dontAsk mode my Edit allow rule is always denied, while a Read rule written identically works. What differs?
When Read works and only Edit is denied, the fastest thing to rule out is a setting that applies to the write tools alone.
permissions.blockWritesOutsideWorkingDirectories, added in v2.1.314, makes Write, Edit and NotebookEdit refuse paths outside the working directories in every permission mode. Read is not covered, which is exactly why an identically written Read rule still works.
{
"permissions": {
"blockWritesOutsideWorkingDirectories": true
}
}
With it on, an allow rule will not get a write through outside the working directories. Either bring the path in with --add-dir or permissions.additionalDirectories, or turn the setting off.
If that is not it, the dontAsk specification is the next place to look. The documentation says that even in dontAsk, "Actions matching your permissions.allow rules and calls approved by a PreToolUse hook run too" — matching an allow rule is supposed to work. These are denied even with a matching allow rule:
| Denied anyway | Note |
|---|---|
Calls matching an explicit ask rule | dontAsk denies instead of prompting |
The AskUserQuestion tool | Denied even if allow rules match it |
Connector tools your organization set to ask | In sessions where that setting reaches Claude Code |
MCP tools marked requiresUserInteraction | Their approval card needs an answer this mode never collects |
rm and rmdir targeting a critical path | Denied even with an allow rule or a hook allow |
| Reads from a network path | Same |
An ask rule outranks an allow rule
A leftover Edit(...) ask rule means dontAsk denies rather than prompts. The documentation states that even when a hook or mod returns allow, "A call that an ask rule would prompt for still prompts you" — ask wins over allow. Check the Ask tab in /permissions.
The pattern itself is worth re-reading too. A single-segment directory pattern such as Edit(src/**) matches only the src directory in the working directory; use Edit(**/src/**) to match one at any depth. And an allow rule on a path reached through a symlink applies only when both the requested path and the resolved path match.
Writes to protected paths are not auto-approved in any mode except bypassPermissions. For how the modes differ, see Claude Code starts in auto mode by default.
Q. In auto mode, an action I approved in the main session is refused when a subagent tries it. Doesn't my approval carry to the subagent?
It does not. Per the documentation, a subagent's actions go through the decision order again: "While the subagent runs, each of its actions goes through the same decision order as in the parent session, with the same block and allow rules."
What carries is a rule. A one-off approval you gave in conversation is not a rule, so it has no effect on the subagent's evaluation. For an action that should pass consistently, put it in permissions.allow; allow, ask and deny rules are step one of the decision order and resolve immediately on a match.
The classifier looks at subagents at three points:
| When | What happens |
|---|---|
| Before it starts | The delegated task description is evaluated, so a dangerous-looking task is blocked at spawn time |
| While it runs | Each action goes through the same decision order as the parent session. Any permissionMode in the subagent's frontmatter is ignored |
| When it finishes | Its work and final report are reviewed before the parent reads the report. A flagged report is still delivered, prepended with a security warning |
A remote write still reaches the classifier even with an allow rule
Network actions have an exception. The documentation says a shell command carrying per-command allowed domains "also routes to the classifier even when an allow rule matches, because a rule approves the command, not its hosts." An allow rule approves the command, not where it connects. So for a refused remote write, adding an allow rule does not remove the classifier's judgement.
Other cases route to the classifier despite an allow rule:
- Writes to protected paths
rmandrmdirremovals targeting a critical path, which no allow rule approves- MCP tools marked
requiresUserInteraction, and connector tools your organization set toask - Ask rules that match on a command's content, such as
Bash(git push *), which fall back to a permission prompt
The permissionMode detail is the easiest to miss: setting it in a subagent's frontmatter has no effect. For how the modes differ, see Claude Code starts in auto mode by default.
Q. Auto mode blocks harmless actions, like reading project context files. I thought read-only actions never reached the classifier — why are they being denied?
The documentation's "How the classifier evaluates actions" describes auto mode as a fixed four-step decision order where the first matching step wins. Which step your read is landing on is what tells you why it stopped.
Step 2 is the behavior you were expecting: "Read-only actions and file edits in your working directory are auto-approved." A read inside the working directory does not reach the classifier at all. So if one is still being blocked, it is hitting one of that step's exceptions.
The likely causes, roughly in order:
- Server-side classifier review is in effect. Listed as an exception to that same step: "In a session with server-side classifier review, read-only and sandboxed shell commands wait for that review and are blocked if it flags them." A read-only command waiting on a review and then being blocked is documented only here.
- The file is outside your working directories. "The first read outside the working directories" prompts you. A context file that lives outside the repository qualifies. Adding it with
/add-diror theadditionalDirectoriessetting changes that. - A deny rule matches. Those resolve at step 1, and deny rules block in every mode.
- The read is from a network (UNC) path. That prompts you even when an allow rule matches.
Entering auto mode drops some of your allow rules
If the pattern is "this used to go through, and only auto mode stops it", this is why. On entering auto mode, broad allow rules that grant arbitrary code execution are dropped: blanket Bash(*) or PowerShell(*), wildcarded interpreters like Bash(python*), package-manager run commands, Agent allow rules, and Monitor allow rules. Narrow rules like Bash(npm test) stay in effect, and the dropped ones are restored when you leave auto mode.
There is also a documented reason why the denials read as unexplained: "If the classifier blocks, Claude receives the reason. In most sessions the reason names the rule the classifier matched, such as [Data Exfiltration], rather than giving a written explanation."
More detail: Claude Code permission modes.
Q. Auto mode denied my git history-rewrite command as [Git Destructive], and saying yes in chat gets the same denial. Is there no approval path?
There is one — four, in fact, all documented on the auto mode configuration page.
First, why "yes" doesn't work. Per the docs, the explicit user intent that overrides a classifier soft_deny is a message that directly and specifically describes the exact action Claude is about to take. General requests don't count: asking Claude to "clean up the repo" doesn't authorize force-pushing, but asking it to "force-push this branch" does. A bare "yes" names no action, so it isn't treated as intent.
The options:
| What you want | How |
|---|---|
| Allow this kind of action from now on | Add a prose rule to autoMode.allow; allow rules act as exceptions to soft_deny |
| Allow it just this once | Say specifically what the action is in your next message and let Claude retry |
| Recover the denied call | Open /permissions, select the Recently denied tab, press r on the action; exiting the dialog lets Claude retry it |
| Add the rule without editing a file | The Auto mode tab in /permissions (v2.1.246 or later) |
autoMode.allow goes in ~/.claude/settings.json. The classifier does not read autoMode from .claude/settings.json or .claude/settings.local.json — both live in the repo directory, so a checked-in repo could otherwise inject its own allow rules. Include the literal "$defaults" in the array to keep the built-in rules.
{
"autoMode": {
"allow": [
"$defaults",
"git commit --amend --reset-author on unpushed commits is allowed: it only corrects authorship and never rewrites published history"
]
}
}
To read the full wording of the rule that fired, run claude auto-mode defaults --label 'Git Destructive' (v2.1.208 or later). That rule also clears "when the user asked to amend/reword/fixup", so how you phrase the request can be enough on its own.
Primary sources
This article was drafted by AI from official documentation and reviewed by the site operator before publishing. Found a mistake? Let us know via the contact page.