A close read of the permission system — modes, rules, Auto mode, sandboxing, hooks, and the settings that govern them.
Prompts and CLAUDE.md shape what Claude attempts. Claude Code applies a fixed enforcement flow before a requested tool can execute.
A permission mode sets the baseline for every session. Rules and hooks layer on top of whichever one is active.
| Mode | Runs without asking | Best for |
|---|---|---|
| default (Manual) | Reads only | Sensitive work, reviewing every action |
| acceptEdits | Reads, file edits, common filesystem commands | Iterating on code you're reviewing |
| plan | Reads, classifier-approved commands where available | Exploring before you change anything |
| auto | Everything, with background safety checks | Long tasks, fewer prompts |
| dontAsk | Only pre-approved tools — denies instead of asking | Locked-down CI and scripts |
| bypassPermissions | Everything | Isolated containers and VMs, nothing else |
A separate classifier reviews unresolved shell, network, protected-path, and higher-risk actions. Routine reads and working-directory edits normally skip it.
Piping to a shell (curl | bash), production deploys, mass deletions, IAM changes, terraform destroy, force pushes.
Working-directory edits, dependencies declared in manifests or lock files, read-only HTTP, and ordinary pushes within the current repository.
The shared shape hides different matchers: tool-specific specifiers, top-level parameter rules, and MCP tool-name wildcards do not have identical semantics.
| Rule | Use | Matches |
|---|---|---|
| Bash(npm run *) | allow / ask / deny | npm scripts, not npm install |
| Read(./.env) | allow / ask / deny | That path under the rule's anchor |
| WebFetch(domain:*.example.com) | allow / ask / deny | Subdomains of example.com |
| mcp__github__get_* | tool-name wildcard | GitHub MCP tools beginning get_ |
| Agent(model:opus) | ask / deny parameter rule | Calls explicitly requesting Opus |
Inside the declarative rule lists, the order is fixed and specificity does not change it: deny precedes ask, which precedes allow.
Highest wins for a single value; array-type keys like permissions.allow merge across every level instead.
MDM, org console. Locks a rule so nothing below can override it.
claude --settings, for one run.
.claude/settings.local.json — personal, gitignored.
.claude/settings.json — checked in, whole team.
bypassPermissions executes almost everything immediately, including protected-path writes. A short list still requires separate handling.
Explicit ask rules · critical-path rm/rmdir · interaction-required tools · organization-gated connectors · cross-session messaging safeguards.
Prompt injection or model error can trigger destructive action without review. Protected paths such as .git and .claude are writable in this mode.
Permission modes decide whether a call happens. The Bash sandbox — Seatbelt on macOS, bubblewrap on Linux/WSL2 — decides what it can touch once it does. The two are independent.
By default, writes stay inside the working directory, session temp directory, and added directories. Broader access requires explicit sandbox configuration.
First request to a new domain prompts — or in auto mode, goes to the classifier. Nothing is reachable until it's explicitly allowed.
In the Agent SDK, canUseTool replaces the interactive permission prompt. Calls approved earlier normally never reach it.
type CanUseTool = ( toolName: string, input: Record<string, unknown>, options: { signal: AbortSignal; blockedPath?: string; decisionReason?: string; } ) => Promise<PermissionResult>;
// return one structured result return { behavior: "allow", updatedInput: input }; return { behavior: "deny", message: "Reason", interrupt: false }; // dontAsk skips this callback
Protected paths resist silent writes. Critical paths add a special circuit breaker for Unix rm/rmdir.
| Examples | In bypassPermissions | |
|---|---|---|
| Protected paths | .git, .claude, .mcp.json, shell rc files | Write proceeds without the normal protected-path prompt |
| Critical paths | Filesystem root, top-level directories, home, working-directory parents | rm/rmdir still asks for approval |
Managed settings are the only layer nothing downstream can override — the actual governance surface.
Removes the highest-risk permission mode from governed sessions.
Removes classifier-based Auto mode; other modes remain independently configurable.
Makes the sandbox a hard requirement, not a best-effort fallback.
Uses managed sources only for allow, ask, and deny permission rules.
No single control is the whole safety model. Authorization determines whether a requested call executes; interception and isolation limit what that execution can do.