Claude Code permission modes: plan, edit, and auto-accept — and when to switch
Published 2026-05-11 by Owner
The first few days with Claude Code, most engineers land on one of two failure modes: they leave it in auto-accept because it feels fast, or they leave it in plan mode because it feels safe. Both are wrong for most real work. The permission model exists to be switched during a session, not set once and forgotten.
Here is what each mode actually gates, a workflow for switching them mid-session, and the two incidents worth naming so you don’t have to learn them yourself.
What each mode actually gates
Claude Code ships with three permission levels. The naming is slightly non-obvious, so it’s worth being precise.
Plan mode is read-only. Claude can read files, reason about the codebase, and produce a written proposal. It cannot write any file or execute any shell command. You see the plan; nothing changes until you switch modes. This is the right mode for the first turn of any non-trivial task — it forces the model to commit to an approach before it touches anything.
Edit mode (the middle setting, sometimes labeled “ask for permissions” in the UI) allows file reads and file writes. It does not allow command execution without first asking. If Claude wants to run bun install, git checkout, prisma migrate, or any other shell command, it stops and asks before running it. You approve the command individually, or reject and tell it why. File writes go through without a per-edit confirmation, but commands are gated.
Auto-accept removes the per-command gate. File edits and shell commands both run without interruption. Claude sequences through a task autonomously, pausing only when it hits an ambiguity it can’t resolve from context. This is the right mode for bulk mechanical work — renaming 40 functions, reformatting a config directory, applying a code mod — where each individual step is low-stakes and the overhead of approving each command manually is the bottleneck.
The common misread: people assume edit mode still gates individual file writes. It does not. If Claude wants to overwrite config/database.yml in edit mode, it will. What edit mode gates is the shell. That distinction matters a lot on repos where file writes have application-level consequences even without executing a command.
A secondary misread: “auto-accept” sounds like it accepts Claude’s suggestions for you, like a shortcut for clicking “approve” on each diff. It isn’t. It means the agent’s tool calls — including shell invocations — execute immediately without a confirmation step. This is closer to “no guardrails” than it is to “fast-approve.” Worth being clear on that before turning it on for the first time.
The default-mode debate
Auto-accept feels like the right default. It’s fast, it removes friction, it makes Claude Code feel like a fully autonomous agent rather than a tool that needs babysitting. The first time you run it on a greenfield repo, it’s genuinely impressive.
The problem surfaces on day 3 or day 30, on a task that turned out to be more complex than you described. Auto-accept means the agent runs a full sequence of operations before pausing. If the approach was wrong in the first turn, you find out after a dozen file modifications and four shell commands have already run. Rolling back is possible — Claude Code’s git integration means you’re rarely stuck — but the context cost of figuring out what happened and getting to a clean state is real.
Plan mode as a default avoids that cost but introduces its own. I once spent two hours on a large refactor that should have taken forty minutes, because I was in plan mode and kept asking Claude to revise the plan rather than just executing it. For a 50-file rename with no ambiguity, plan-mode round-trips are pure waste.
The middle ground (edit mode as the default) is correct for most work. File edits run freely, which covers the majority of what Claude Code does. Shell commands are gated, which is the actual risk surface. This is a reasonable factory default, and if you’re not sure what to set project-wide, this is the one.
A workflow that switches modes mid-session
The pattern that works in practice:
Phase 1: plan mode. Start any non-trivial task in plan mode. Describe what you want, read the proposal, and verify it covers the cases you care about. Push back on the approach if it’s wrong. This is cheap — no file changes, no commands. If the model is about to go down a wrong path, this is the moment to correct it.
# In Claude Code, toggle plan mode before starting the session, or ask:
"Before making any changes, give me a plan for how you'd approach this."
Phase 2: edit mode. Once the plan is solid, switch to edit mode and let Claude execute the non-trivial parts — the file rewrites, the type changes, the logic adjustments. You’ll see individual command proposals when they come up, which gives you a chance to catch prisma migrate deploy on a production string or a git push --force before they run.
Phase 3: auto-accept for the mechanical tail. Most tasks have a mechanical bulk phase — updating 30 import paths after a file rename, running a linter fix across the whole project, applying a code style pass. Switch to auto-accept for this. The individual operations are low-stakes, you’ve already approved the approach, and approving each one individually is friction without safety benefit.
Phase 4: back to edit mode for verification. When the bulk phase is done and you’re in the verification step — running tests, reading diffs, confirming the generated code is correct — switch back to edit mode. Verification steps sometimes prompt follow-up edits; you want those gated again so you’re not flying blind in a post-change review session.
The switching is three or four keystrokes in the Claude Code UI. It’s not ceremonial overhead. The cost of not switching is occasionally significant.
One practical note on phase 1: asking Claude to “give me a plan” explicitly in chat works as a substitute if you forget to set plan mode before starting. It doesn’t enforce read-only behavior the way plan mode does, but it forces the model to lay out its approach before acting, and you can redirect before it runs anything. Not as reliable as actual plan mode, but better than nothing when you’re already mid-session.
Project-specific defaults via .claude/settings.json
You can bake a default permission mode into a repository so the right behavior is the automatic behavior for anyone cloning the project. The settings file lives at .claude/settings.json at the repo root.
For a repo with destructive risk — database migrations, infrastructure-as-code, deploy scripts — the right default is edit mode with an explicit note in the file about what commands are dangerous:
{
"permissions": {
"defaultMode": "edit"
}
}
For a repo where the main risk is destructive shell commands (a Terraform repo, a Kubernetes config repo, anything with a Makefile full of deployment targets), you might go further and call out specific command patterns that should always require confirmation, regardless of mode. Claude Code’s permission system supports adding explicit allow/deny rules on top of the mode setting.
For a greenfield app or a personal project with no production surface, auto-accept as a project default is reasonable. The time savings are real and the rollback story (git) is clean:
{
"permissions": {
"defaultMode": "acceptEdits"
}
}
The key names for defaultMode I’ve confirmed in practice are plan, edit, and acceptEdits. These are the values accepted by the permission mode toggle in the current Claude Code release.
Beyond the default mode, the settings file supports per-tool allow and deny rules. The shape looks roughly like this:
{
"permissions": {
"defaultMode": "edit",
"allow": [
"Bash(bun install)",
"Bash(bun run test*)"
],
"deny": [
"Bash(git push*)",
"Bash(rm -rf*)"
]
}
}
The allow list pre-approves specific command patterns so they run without a confirmation prompt even in edit mode — useful for bun install and bun run test which Claude needs to call constantly and which are low-risk. The deny list blocks specific patterns even in auto-accept mode, which is the right place to put anything destructive. A deny on git push in a shared-repo environment means nobody accidentally pushes from an agent session regardless of what mode they’re in.
Checking this file into version control matters. New team members get the right behavior without configuring anything. When the risk profile of a repo changes — say, a personal project that added a production deployment target — updating this file is the right place to record that decision.
One thing to watch on teams: Claude Code permission settings are per-developer when set in the local config (~/.claude/settings.json) and per-repo when set in .claude/settings.json. The repo-level file wins for anything it specifies, but local settings can add to it. If one engineer has auto-accept in their global config, the repo-level "defaultMode": "edit" still applies when they’re in that repo. Shared repo settings are the actual safety net; personal settings are convenience overrides.
The two failure modes worth naming
Trusting auto-accept on a destructive task. The incident: a task was phrased as “clean up the old migration files and remove any that aren’t referenced.” Claude Code ran in auto-accept, interpreted “remove” liberally, and deleted twelve migration files that were not referenced in code but were still needed as historical records for prisma migrate resolve. The files were in git, so nothing was permanently lost, but the reset took twenty minutes and killed the session context. The lesson: anything involving delete, drop, remove, or clean should get at least one human-approved command gate before it runs. Edit mode for cleanup tasks, not auto-accept.
The word “clean” in a task description is particularly likely to produce aggressive deletions. The model interprets it correctly — clean usually does mean remove — but the scope of “referenced” is something it has to infer, and its inference is aggressive. If a task uses the words clean, purge, remove, or prune, start it in edit mode regardless of how low-stakes it looks at first glance.
Staying in plan mode on a refactor that needed 50 small edits. The incident: a rename-and-move refactor across a Go codebase, about 50 files. I stayed in plan mode because I’d had a bad experience the week before and was being cautious. Claude kept proposing individual file changes in chat. I kept approving them verbally. Claude kept saying “I’ve updated handlers/auth.go in my plan” without actually updating anything. Two hours later I had a beautiful plan document and zero changes applied. The lesson: plan mode is for alignment, not for execution. Once you’ve agreed on the approach, switch modes or you’re just burning time.
The tell for this failure mode is finding yourself copying file names from Claude’s plan and manually making the changes it’s describing. If that’s happening, something is wrong with the session setup. Either Claude is stuck in plan mode, or it’s in edit mode but responding as if it were in plan. Check the mode indicator and, if needed, explicitly tell Claude: “Now make these changes, don’t just describe them.”
Both incidents have the same root cause: using one mode for an entire session without thinking about what phase the session is in. A session has phases. The mode should match the phase.
What this doesn’t fix
Permission modes are a gate on what runs, not a guarantee of what’s correct. Auto-accept running a correct sequence is fine. Auto-accept running a wrong sequence — one you approved in plan mode, one that turns out to have a wrong assumption — is still wrong after running. The modes reduce the blast radius of an incorrect execution, but they don’t substitute for reviewing the output.
The real discipline is phase-switching combined with reviewing diffs before committing them. Claude Code’s git integration means you can always look at what changed before it becomes permanent. That habit, combined with the right permission mode for the current phase, covers most of the failure space.
If you’re inheriting a team setup where someone has set auto-accept as the default for a repo that has production CLI targets in it, change the .claude/settings.json. Somebody will eventually run a task in a hurry, and the mode they got when they opened the session is the one they’ll forget to change.