Auto mode: what the classifier reviews and where it hands back
By the end you can
- Describe what the auto-mode classifier sees and what is withheld from it
- State the decision order that runs before the classifier, and which of your rules auto mode suspends
- Predict whether a given action is blocked or allowed by default
- Choose between a spoken boundary and an ask or deny rule
- Recognise the conditions under which auto mode hands control back
You turned auto mode on because the prompts were unbearable, and the prompts stopped. What replaced them is a second model that reads part of your session and decides, action by action, whether the thing about to run is the thing you asked for. Everything useful about auto mode follows from knowing precisely what that model can see, and what has been withheld from it.
Lesson 10.1 placed auto among the six modes. This is what happens underneath it.
What auto mode replaces
Auto mode lets Claude execute without routine permission prompts. A separate classifier model reviews actions before they run, blocking anything that escalates beyond your request, targets unrecognized infrastructure, or appears driven by hostile content Claude read. Explicit ask rules still force a prompt. — Permission modes
Three things follow. The classifier is a model, so its verdicts are judgements. It runs before the action, adding a round trip that reads and working-directory edits outside protected paths skip entirely. And it is a per-action control:
The classifier is a per-action control, not an isolation boundary — Sandbox environments
It decides whether each call runs. It does not limit what a call can reach once it does — that is what an isolation boundary is for. Lesson 10.4 takes the distinction properly; carry this much of it: nothing about the classifier constrains a command it approved. That is the ceiling Lesson 10.1 quoted — auto mode reduces prompts, it does not guarantee safety.
Rules run before the classifier
Auto mode does not replace your permission rules. It sits behind them.
Deny and explicit ask rules are evaluated before the classifier and still block or prompt. — Configure auto mode
Each action goes through a fixed decision order, first match wins:
| Step | Resolves there |
|---|---|
| 1 | Actions matching your allow, ask or deny rules |
| 2 | Read-only actions and file edits in your working directory — auto-approved, except writes to protected paths and the first read outside the working directories, which prompt you |
| 3 | Everything else — the classifier |
| 4 | If the classifier blocks, Claude gets the reason and tries an alternative — from v2.1.208 that reason is the fixed text Blocked by classifier in most sessions, not an explanation |
That step-2 read prompt fires once, the first time Claude uses Read, Grep or Glob
on a path outside the working directories. Keep allowing runs the read and
stops asking; Block from now on refuses it and writes
permissions.blockReadsOutsideWorkingDirectories into your user settings, which
makes the file tools refuse such reads in every later session and every mode —
that setting requires v2.1.257. The prompt does not appear in non-interactive
-p runs or background sessions; reads there run as before.
Step 1 has exceptions, and they are the cases where a rule you wrote does not end
the matter. Protected-path writes route to the classifier even when an allow rule
matches. So do rm and rmdir removals targeting a critical path — but that
routing is v2.1.218 and later; what holds in every version is the narrower rule
that no allow rule and no PreToolUse "allow" approves such a removal at all.
MCP tools marked requiresUserInteraction, and connector tools your organisation
set to ask, prompt you directly and never reach the classifier. And an ask rule
matching on a command's content, such as Bash(git push *), falls back to a
permission prompt.
Entering auto mode also drops the broad allow rules that grant arbitrary code
execution — blanket Bash(*) or PowerShell(*), wildcarded interpreters like
Bash(python*), package-manager run commands, and Agent rules — and restores
them when you leave. Monitor rules join that list only in v2.1.236 and later;
before that a Monitor allow rule matching the whole tool approved Monitor
commands, which run through the shell, without classifier review.
Narrow rules like Bash(npm test) stay in effect, which is exactly how a
destructive argument the rule's prefix did not anticipate can still slip past
unreviewed. Setting autoMode.classifyAllShell to true suspends every Bash and
PowerShell allow rule while auto mode is active — but the key requires v2.1.193 or
later, and earlier versions ignore it and carry narrow shell allow rules into auto
mode regardless.
What the classifier can see
This is the sentence to memorise:
The classifier sees user messages, tool calls other than read-only lookups such as file reads and searches, and your CLAUDE.md content. Tool results are stripped, so hostile content in a file or web page can't manipulate it directly. — Permission modes
Read both halves. Your CLAUDE.md is classifier input: "never force push" in
a project's memory file steers Claude and the classifier at once. And tool
results are not, deliberately — it is why injected text in a fetched page cannot
directly argue its way past the check. Level 9 showed you a tool result issuing
instructions; this is the architectural answer, and lesson 10.6 takes the subject.
Stripping results has two consequences that look like bugs until you know why:
- Command output is not evidence. A repository is assumed private unless its
remote host and name say otherwise, or evidence in what the classifier reads
shows it is public — your own message naming it, say. The output of a
gh repo viewdoes not reach the classifier and settles nothing. The transcript-evidence half of that check requires v2.1.200 or later. The one documented exception is arranged by Claude Code rather than by Claude: before a command that would discard uncommitted work, it runsgit statusitself and shows the classifier whether staged, modified or untracked work is present — reporting untracked files even where the repo setsstatus.showUntrackedFiles=no. - A delete whose target came from output gets blocked. From v2.1.205, a
recursive forced delete such as
rm -rf "$VAR", where the variable is assigned nowhere in the conversation the classifier sees, is blocked by default: the value came only from earlier output, so the target cannot be checked against the deletion rules. Naming the exact path, or re-running with the literal path, clears it.
One channel lets annotated context through: a PostToolUse hook's
classifierContext field, which requires v2.1.236 or later. Read what the docs
say about its weight — for hooks configured in Claude Code the classifier treats
the note as unverified, application-provided context that never establishes user
intent, and checks any claim that you approved something against your own
messages. The reason to still handle it carefully is the documented warning
against copying untrusted tool output or third-party text into it: doing so hands
back exactly what stripping was protecting.
A second, separate layer: a server-side probe scans incoming tool results and flags suspicious content before Claude reads it. That is not the only place hostile content is considered — the classifier itself blocks actions that appear driven by hostile content Claude read — but it is the only pre-read scan the documentation describes.
Blocked by default, allowed by default
The classifier trusts your working directory and the remotes configured for it
when the session started. From v2.1.200, a remote added or repointed mid-session
with git remote add or git remote set-url is not trusted — before that, such
remotes were trusted too. Everything else is external until you configure it.
Blocked by default includes curl | bash-style download-and-execute, sending
sensitive data to external endpoints, production deploys and migrations, mass
deletion on cloud storage, granting IAM or repo permissions, irreversibly
destroying files that existed before the session, force push, git reset --hard
and its siblings, and terraform destroy. Later releases added, among much else —
this one from v2.1.203:
Content from a sensitive local store, or from a file whose name, path, or type marks it as sensitive, entering a commit, a push, PR or issue text, a gist or paste, or a package publish, unless you named both the source and the destination. — Permission modes
Now the half people guess wrong. Allowed by default covers local file operations in your working directory, installing dependencies declared in your lock files or manifests, read-only HTTP requests — and this:
Reading
.envand sending credentials to their matching API — Permission modes
Auto mode is not a secrets boundary. If .env must stay unread, that is a deny
rule, and it is lesson 10.5. Pushes are the other surprise:
Pushing to any branch of the repository you're working in and creating a pull request that matches your request run without a prompt, unless the push or pull request falls under the blocked list, such as secrets or sensitive data leaving the repository, or a pull request that targets a different repository or organization. — Permission modes
This is the claim most exposed to your version. Any branch, the default branch included, has been allowed by default only since v2.1.211; from v2.1.203 to v2.1.211 the allowance covered the branch you started on, branches Claude created and routine default-branch pushes; before v2.1.203 a direct push to the default branch was blocked outright. Check your own binary before you assume a colleague's session would have let the same push through.
Three qualifiers come attached to that allowance. A non-default branch whose
name marks it as a deploy or publication target, such as production, release
or gh-pages, is not covered by it: the classifier judges a push there on its own
terms, including as a production deploy. The push's content is still checked
against the other rules. And a permissions.deny rule blocks pushes to named
branches outright in every mode, as does the remote's own branch protection.
The trap: a boundary you said out loud
Telling Claude "don't push until I review" does work. The classifier treats a boundary stated in conversation as a block signal, it holds even where the default rules would allow the action, and Claude's own judgement that the condition was met does not lift it. Only a later message from you does. And then:
Boundaries are not stored as rules. The classifier re-reads them from the transcript on each check, so a boundary can be lost if context compaction removes the message that stated it. For a hard guarantee, add a deny rule instead. — Permission modes
Lesson 3.2 drew the line that decides this: what lives on disk comes back after compaction, what lived only in the conversation is summarised with loss. A spoken boundary is the second kind, and losing it costs more than losing an explanation. The docs describe no warning when it happens: the session keeps running, the classifier keeps checking, and the constraint is simply no longer among the things checked against.
Making a checkpoint stick
| Boundary | Mechanism | Behaviour in auto mode |
|---|---|---|
| Prompt before the action | permissions.ask | Always prompts for content-scoped rules; the classifier cannot auto-approve a matching action |
| Never run the action | permissions.deny | Blocks before the classifier is consulted; neither the classifier nor user intent can override it |
| One-off, this session | Say it in conversation | Blocks matching actions, but can be lost to compaction |
The ask recipe is the one most people want and never write. It keeps auto mode on for everything else and puts a human in front of the two actions that usually deserve one:
{
"permissions": {
"ask": [
"Bash(git push *)",
"Bash(gh pr create *)"
]
}
}Lesson 10.2's precedence is doing the work here: ask and deny are evaluated first, so neither the classifier nor a persuasive-sounding intent gets a vote.
If your problem is the opposite — routine internal work getting blocked — the fix
is autoMode.environment, prose entries naming the repos, buckets, domains and
services inside your boundary. Note where that block is read from: user settings,
managed settings, or --settings, and deliberately not the two files that live
in the repo, so a checked-in project or a build step cannot inject its own trust.
That exclusion only became complete in v2.1.207: before it the classifier also
read .claude/settings.local.json, a file a repository can commit and a local
tool can write. The docs still tell you to move any autoMode block out of that
file and into ~/.claude/settings.json — no longer because it is dangerous
there, but because it is inert there, and a trusted-infrastructure list nothing
reads looks exactly like one the classifier disagrees with. Deploying that across
a team is Level 12's subject.
When auto mode hands back
| Situation | What happens |
|---|---|
| A blocked action | A notification, plus an entry under Recently denied in /permissions, where r retries it with a manual approval |
| Repeated blocks | Auto mode pauses and prompting resumes |
| A session that cannot prompt | A -p run without --permission-prompt-tool has nothing to fall back to, so when repeated blocks reach a threshold the action does not run and Claude keeps working. Claude Code does not stop the run |
| A mode switch mid-check | A verdict the new mode would not have requested is discarded; you are prompted instead, or auto-denied in dontAsk |
The second row has exact numbers, and they are not yours to tune:
if the classifier blocks an action 3 times in a row or 20 times total, auto mode pauses and Claude Code resumes prompting. Approving the prompted action resumes auto mode. These thresholds are not configurable. — Permission modes
Any allowed action resets the consecutive counter. The total counter persists for the session and resets only when its own limit triggers a fallback. Repeated blocks usually mean the classifier is missing context about your infrastructure, not that Claude is misbehaving.
A fifth case is not a block at all: the classifier failed to produce a verdict. The docs separate four such failures, and they do not behave alike.
| Failure | What you see, and what it costs you |
|---|---|
| The classifier model is unavailable | A message naming a model and saying auto mode "cannot determine the safety" of the tool. Transient for the (rate-limited), (overloaded) and (server error) categories; retry after a few seconds. On Bedrock it repeats until your account can invoke that model |
| The classifier's response did not parse | Denied for safety, with no verdict, and Claude Code records no Recently denied entry. Retrying usually succeeds |
| A safety check separate from auto mode refused the classifier's own request, because of earlier conversation content | Denied with no verdict and no Recently denied entry. Retrying will not help — the same content trips the same filter. Switch permission mode and approve the action, or start a fresh conversation |
| The conversation outgrew the classifier's context window | Not a denial: in an interactive session auto mode falls back to an ordinary permission prompt for that action, and /compact brings later actions back inside the window. In a -p run with no --permission-prompt-tool, the action does not run and the run continues |
The first row used to hide a second cause, and that one was never transient. A
routine token expiry does not surface as this message any more, because Claude
Code "refreshes the token and retries the request once" — the docs then date that
fix: "Before v2.1.216, an expired or rotated token failed each classifier
request, and auto mode denied every checked action with this message until the
token was refreshed"
(Errors and warnings). The reading habit
that gap taught outlives it, because the message itself still says nothing about
scale. One command failing under a (rate-limited), (overloaded) or
(server error) category is the transient case the row describes, and a retry a
few seconds later clears it. Every checked action failing is not that, and the
docs name one standing case of it: on Bedrock the message repeats until your
account can invoke the classifier model. Retrying is the wrong move there — as it
was on a binary below v2.1.216, where the same wall meant an expired token.
One threshold note, and it is the one that bites on an older binary: the third row is exempt from the pause counters, but only from v2.1.225. Before that, Claude Code counted those refusals like any other block and returned the same rejection message as a genuine classifier block. Do not assume the other rows are exempt either. In all four, reads, searches and edits inside your working directory skip the classifier and keep working.
What this mode actually is
A judgement layer with a known blind spot and a known escape hatch. Choose it deliberately, then write down the one or two boundaries that must survive a compaction. Everything else can stay a conversation.
Checkpoint
-
You tell Claude "don't deploy to staging until I've looked at the diff", work for two hours, and the session compacts. Is the boundary still enforced? What should you have written instead, and where?
Show answerAnswer
Probably not, and nothing tells you. Boundaries are not stored as rules — the classifier re-reads them from the transcript on each check, so a boundary can be lost if compaction removes the message that stated it. The session keeps running and the classifier keeps checking; the constraint is simply no longer among the things checked against. Until then it was doing real work: a stated boundary blocks even where the default rules would allow the action, and Claude's own judgement that the condition was met does not lift it — only a later message from you does.
For a hard guarantee, write it into a settings file's
permissionsblock instead:askfor the thing you actually wanted, a prompt before the deploy, ordenyif it must not run at all. Both are evaluated before the classifier, so neither the classifier nor a persuasive-sounding intent gets a vote — and unlike a sentence in the transcript, neither can be summarised away. -
A teammate says auto mode "protects the classifier from prompt injection because it can't see the page". State what it actually cannot see, and name the one field that lets annotated content reach it anyway.
Show answerAnswer
What is withheld is tool results — all of them, not just fetched pages. The classifier sees your user messages, tool calls other than read-only lookups such as file reads and searches, and your
CLAUDE.mdcontent; results are stripped so hostile content in a file or web page can't manipulate it directly. Two consequences fall straight out of that: yourCLAUDE.mdis classifier input, and command output is not — agh repo viewshowing a repository is public settles nothing, because the verdict is made without it.The one channel through is
classifierContexton aPostToolUsehook, which requires v2.1.236 or later. It is context, not evidence: for hooks configured in Claude Code the classifier treats the note as unverified, application-provided context that never establishes user intent, and checks any claim that you approved something against your own messages. The docs' warning is the operative part — don't copy untrusted tool output or third-party text into it, because that hands back exactly what stripping was protecting. Keep the scope straight too: stripping protects the classifier, not you. Claude still reads the page. -
Your CI job runs
claude -pin auto mode and the classifier blocks the sameaws s3 syncthree times. Describe what happens next in that run — and what would have happened in your terminal instead.Show answerAnswer
Three blocks in a row hits the documented threshold — 3 consecutive or 20 total, and not configurable — so auto mode pauses and prompting resumes. But a
-prun without--permission-prompt-toolhas nothing to fall back to: the action does not run and Claude keeps working. Claude Code does not stop the run, so the job can finish looking healthy with the sync never performed.In your terminal you get the prompt instead, and approving the prompted action resumes auto mode; any allowed action resets the consecutive counter. Each block also raises a notification and leaves a Recently denied entry in
/permissions, whererretries it with a manual approval. Repeated blocks usually mean the classifier is missing context about your infrastructure rather than that Claude is misbehaving — the fix isautoMode.environmentnaming that bucket and those services, read from user settings, managed settings or--settings, and deliberately not from the two settings files that live in the repo. -
Which of these stops a
git pushin auto mode without ending the mode: an allow rule, an ask rule, a sentence in chat, a deny rule? For each, say how firm it is.Show answerAnswer
Three of the four do, and none of the three ends auto mode. An allow rule stops nothing — it does the opposite. (Broad rules granting arbitrary code execution are dropped on entering auto mode and restored on leaving; narrow ones stay in effect, which is a different problem, not a brake.)
An ask rule such as
Bash(git push *)always prompts for content-scoped rules, and the classifier cannot auto-approve a matching action; it resolves at step 1, before the classifier, so it is firm. A deny rule is firmest: it blocks before the classifier is consulted, and neither the classifier nor user intent can override it. A sentence in chat genuinely works — the classifier treats a stated boundary as a block signal, it holds where the default rules would allow the push, and only a later message from you lifts it — but it is the least firm of the three, because it is re-read from the transcript on every check and vanishes silently if compaction drops the message. Without one of these, the push simply runs: pushing to any branch of the repository you are working in is allowed by default.