Claude Code auto mode replaces the permission prompt with a second model: a classifier reviews each action before it runs and blocks what looks destructive, out of scope, or driven by hostile content. Deterministic hooks do something narrower: code you control checks each call against fixed rules and gives the same answer every time. The classifier can weigh intent that a pattern can’t read; a rule holds the same line whether or not the conversation still mentions it. Anthropic says auto mode reduces risk but doesn’t eliminate it. They are not rivals. Run both.
How Claude Code auto mode decides
Each action goes through a fixed order (docs). Your allow, ask and deny rules resolve first. Reads and file edits inside your working directory are approved without review. Everything else (most shell commands, network calls, writes to protected paths) goes to the classifier, which by default blocks things like curl | bash, sending sensitive data out, production deploys and migrations, mass deletion on cloud storage, force pushes, git reset --hard over uncommitted work, and terraform destroy. When it blocks, Claude gets the reason and tries another way. After 3 blocks in a row, or 20 in a session, auto mode pauses and prompts you.
Two design details matter for safety. The classifier sees your messages, Claude’s tool calls and your CLAUDE.md, but tool results are stripped out, so a hostile web page can’t talk to it directly. And boundaries you state in chat (“don’t push”) are not stored as rules; they are re-read from the transcript on every check. In the docs’ words, “a boundary can be lost if context compaction removes the message that stated it. For a hard guarantee, add a deny rule instead.”
“Auto mode reduces risk compared to --dangerously-skip-permissions but doesn't eliminate it entirely, and we continue to recommend using it in isolated environments.”
Classifier vs deterministic rules, call by call
Six situations, two judges. Neither column wins every row, which is the argument for keeping both.
| Situation | Auto mode (classifier) | Bulkhead (rules) |
|---|---|---|
Force-push to maingit push --force origin main | Blocked by defaultForce push is on the default block list. You can clear it in chat by naming the branch. | DeniedEvery time, until a human edits bulkhead.yaml. Talking to the agent changes nothing. |
An unscoped DELETEpsql "$DATABASE_URL" -c "DELETE FROM executives;" | Judgment callDepends on what the classifier can tell about that database and what you asked for. | DeniedNo WHERE clause is the whole rule. It doesn’t need to know which database. |
A delete inside an interpreterpython3 -c "import shutil; shutil.rmtree('/Users/me/backups')" | ReviewedIrreversibly destroying files that existed before the session is on the default block list. | Not coveredA listed known miss: a rule reads the command string, not what Python will do. |
| “All tests pass.” The last npm test exited 1. | Out of scopeThe classifier reviews actions before they run, not the agent’s final message. | Claim ≠ evidenceThe stop is refused and Claude is sent back to work. |
| Hour three of an interactive session, $5 spent | No session capAuto mode reviews safety, not spend, and --max-budget-usd covers -p runs only. | Paused at capEvery call is denied until a human raises budget.session_usd. |
| You said “don’t touch prod/”, then the context was compacted | Can be lostBoundaries stated in chat are re-read from the transcript, and compaction can drop them. | Holds for writesprod/** is a protected path in bulkhead.yaml, not a message. It covers writes and deletes, not reads, and not a script or interpreter that writes there. |
The roster: who decides what
| Layer | Decides by | Good at | Doesn’t do |
|---|---|---|---|
| Auto mode | A classifier model reviews each action | Context, intent, fewer prompts; the long tail no rule list anticipates | The same answer every time; spend caps; a tamper-evident record |
| Sandbox /sandbox, containers, VMs, Docker Sandboxes | The operating-system boundary | Containing what gets past rules: interpreters, scripts, encoded commands | Knowing what “done” means; dollars; receipts |
| Bulkhead | Your rules, in deterministic code | Hard lines, dollar caps, claim checks, receipts | Isolating the machine; judging intent |
| Run all three | Rules first, then the classifier, inside the boundary | At your desk: auto mode plus rules. Unattended: add the boundary. | Guarantee safety. Each layer narrows what one bad call can do. |
Run both: how they stack on one tool call
They don’t compete for the same slot. Claude Code runs PreToolUse hooks before its permission-mode check, so a Bulkhead deny ends the call there, every time. When Bulkhead has no objection it returns no permission decision (it never returns "allow"), and the call goes on to your rules and the classifier exactly as it would have without Bulkhead.
- Claude proposes a tool callClaude CodeA tool name and its input, e.g. a Bash command.
PreToolUseBulkheadProtected paths, blocked commands, dollar caps, loop freeze. A deny ends the call and you see one line; otherwise silence.- Your permission rulesClaude CodeAllow, ask and deny rules from settings resolve first. Reads and in-project edits pass.
- The auto mode classifierClaude CodeReviews what is left. A block sends Claude a reason and it tries another way.
- The tool runsThe toolInside your sandbox, if you run one.
PostToolUseBulkheadRecords what the call proved (tests passed or failed, a commit, a PR) in a hash-chained ledger.StopBulkheadChecks the agent’s “done” against that ledger before the turn can end.
One more interaction is worth knowing. If you set risky.mode: ask in bulkhead.yaml, Bulkhead answers pushes, deploys and other outbound actions with "ask". In auto mode a hook’s ask forces a real prompt: the classifier can still deny that call, but it can’t approve it silently.
claude --permission-mode autonpx @bulkheadtools/cli initWhat the pair gives you: the classifier’s judgment on the long tail (the interpreter call, the unfamiliar host, the instruction buried in a README) and a floor that doesn’t move: 26 of 26 dangerous calls denied in the open corpus, a completion check on “done”, a dollar cap, and a receipt of what happened. What it doesn’t give you is isolation. For unattended runs, put both inside a container or VM (sandbox vs guardrails), and never swap auto mode for --dangerously-skip-permissions. How the hooks work is in Claude Code hooks for safety; the 5 known misses are in the proof.
Questions
Is Claude Code auto mode safe?
Safer than skipping permissions, and not a guarantee. Anthropic’s announcement says auto mode “reduces risk compared to --dangerously-skip-permissions but doesn't eliminate it entirely” and recommends isolated environments. It adds that the classifier may still allow some risky actions when your intent is ambiguous or it lacks context about your environment, and may occasionally block benign ones.
Do I need hooks if I use auto mode?
You need something deterministic for the lines that must hold every time, and for the jobs the classifier doesn’t do: checking the agent’s “done” against evidence, capping spend in interactive sessions, and keeping a tamper-evident record of what ran. Anthropic’s own docs say that for a hard guarantee you should add a deny rule rather than rely on a boundary stated in chat.
Why not just use permission deny rules?
Use them. They are deterministic and they block in every mode. A deny rule matches a tool and a pattern; a hook is a program, so it can also count (repeated calls, dollars), remember (a ledger of what ran and what it proved) and check the agent’s final message against that record. Bulkhead is that program.
What does the auto mode classifier see?
Your messages, Claude’s tool calls other than read-only lookups, and your CLAUDE.md. Tool results are stripped from its requests, so content in a file or web page can’t address it directly. A PostToolUse hook can pass it a short note about a result through the classifierContext field.
Is auto mode on by default?
From Claude Code v2.1.283, auto mode is the built-in starting mode for interactive terminal and VS Code sessions on every plan and provider; earlier releases start in it only on Pro, Max and Team plans. claude -p runs and the Agent SDK start in Manual (default), as does any session where a settings file sets disableAutoMode. The --permission-mode flag or permissions.defaultMode in your settings overrides it.