Claude Code /auto-mode-setup: teach the auto mode classifier your environment, then check which model reviews
The setup drafts a trust list from your repo and your agent's recent commands, and the draft replaces the shipped environment text rather than extending it. Read it as a diff against the defaults. Then check which model reviews your actions before you spend time choosing one.
Contents
Two recent Claude Code releases touch the same thing from two ends. Version 2.1.302 (October 16) added CLAUDE_CODE_AUTO_MODE_MODEL, which picks the model the client-side auto mode classifier runs on. Version 2.1.304 (October 19) lists /auto-mode-setup, the guided command that drafts your autoMode.environment entries, as newly available on Bedrock, Vertex, Foundry, the Claude apps gateway and telemetry-disabled sessions. One changes who judges; the other changes what the judge knows about your world.
I ran both on 2.1.304, in throwaway repositories, with user settings that had no autoMode block at all: claude auto-mode config printed the same JSON as claude auto-mode defaults. Two results drive everything below. The setup’s draft shortened most of the shipped entries it touched, and accepting it would freeze those shorter versions in place. And the model I chose for the classifier was overridden before a single command ran. The argument for why a classifier makes a weak boundary is in an earlier essay; this one is about configuring it well, given that it exists.
What does Claude Code’s /auto-mode-setup actually write?
It writes autoMode.environment entries, and sometimes allow or deny rule entries, to ~/.claude/settings.json, and you accept or discard the draft as a whole. Per the docs it always reads the project’s CLAUDE.md, README.md, config files and git remotes, your existing autoMode and permissions.allow settings, and the hosts, buckets and command names from commands Claude ran in your recent sessions in this project. It never reads your messages. Two optional scans add the first word of each line in your shell history and the remotes of repositories under your home directory.
The detail that matters most is in the save step. The accepted environment list is written without "$defaults", the docs explain, because the draft already spells out the built-in entries it kept. "$defaults" is the token that splices the shipped list into yours and keeps you inheriting changes to it across releases. So accepting converts the environment section from “the defaults plus my additions” into “a copy of today’s defaults, edited.” The rule lists the draft adds to do get "$defaults", unless you had already written an allow list without it.
Keep one more line from the docs in your head for later. The classifier reads autoMode only from user settings, managed settings and the --settings flag, never from .claude/settings.json in the repo, because a checked-in repo or a build step could otherwise inject its own allow rules.
Availability is muddled. The configuration page I read the same day still says the command needs a Pro, Max or Team plan and feature-flag fetching, which rules out telemetry-disabled sessions. The 2.1.304 changelog says otherwise. One of the two is behind.
How do you run /auto-mode-setup without changing your settings?
Interactively, run it and discard the draft. Headless, it splits into two steps, and the first one only proposes. Typed into claude -p with no arguments, the command answers with its usage:
/auto-mode-setup [--request-id <uuid>] --wizard posture=<personal|open-source|enterprise|mixed> scope=<all|project> depth=<both|shell|repos|here> --propose
/auto-mode-setup [--request-id <uuid>] [--apply-target <user|project>] --expect-sha256 <64-hex> --apply-file <absolute-path>The apply step reads the proposal from a file under the system temp directory or the Claude config directory, and refuses unless that file’s bytes hash to the sha256 you pass. That binds the write to one exact file. It does not prove anyone read the file; the usage text leaves showing it to a person to the caller. To get a draft and nothing else:
sha256sum ~/.claude/settings.json
claude -p --permission-mode default \
"/auto-mode-setup --wizard posture=personal scope=project depth=here --propose" \
< /dev/null > proposal.json
sha256sum ~/.claude/settings.jsondepth=here skips both optional scans, so neither shell history nor the repositories under your home directory are read. The two hashes matched in my run. The usage text also says that --apply-target checks the proposal’s scope rather than choosing a file: entries always land in your user settings. A scope=project draft still goes into the file all of your projects read. I could not verify from outside whether the classifier then confines those entries to the one project they came from.
What did the /auto-mode-setup draft change in the auto mode defaults?
In my run it rewrote seven of the 21 shipped environment entries, shortened most of the ones it touched, and added one slot of its own. The test repo had an invented GitHub remote, a package.json and a short README naming a staging deploy script and an S3 bucket. No sessions had run there, so the draft had nothing from usage to go on.
To see the same on your machine, compare the draft to the shipped list in both directions:
claude auto-mode defaults > defaults.json
python3 - <<'EOF'
import json, re
label = lambda s: (re.match(r"\*\*(.+?)\*\*", s) or [None, None])[1]
d = {label(x): x for x in json.load(open("defaults.json"))["environment"]}
draft = json.load(open("proposal.json"))["proposal"]["environment"]
p = {label(x): x for x in draft if label(x)}
for k in d:
if p.get(k) != d[k]:
print(f"changed {k}: {len(d[k])} -> {len(p.get(k) or '')} chars")
for k in p:
if k not in d:
print(f"added {k}: {p[k]}")
for x in draft:
if not label(x):
print(f"unlabeled: {x}")
EOFFourteen entries came back identical. Four of the seven changes filled in context from the repo, which is the job: CI/CD deploy targets, Source control, Trusted cloud buckets, and Repository visibility, which it moved from the shipped “assume private” to “possibly public” because it could not check. That one tightens. The draft also added a Default / protected branches slot, marked as not queryable, plus two section headers.
The other three changes were cuts. The shipped Host containment entry is 802 characters; the draft’s is 128. What it dropped is the guidance part:
Whatever is configured, instance-metadata credential paths and node/cluster
credentials of the hosting layer are never task credentials unless this entry
says the agent operates that identity (see Containment Escape). The classifier
sees commands, not their output, so a declared-sealed box that is actually
open cannot be caught here — enforce that in network configuration.The draft’s own notes list Host containment among the entries left at shipped defaults. It was not left at defaults. If you review the notes instead of the entries, you miss the cut.
Trusted repo now names the repository and went from 667 characters to 130 doing it, losing the sentence that secrets and personal data are never cleared into a repo by its visibility. Sensitive remote targets kept its heuristic but lost the example that pins it down: match prod-db, not producer. The Containment Escape rule still sits in soft_deny, so no block disappeared. What disappeared is context the rules point back to.
This was one run of a model-written draft on a nearly empty repo, and a richer project will get a different one. The setup is not broken. The draft is an edit to the defaults, and an edit gets read as a diff.
Should a README be able to add a trusted bucket to Claude Code auto mode?
No, not until you have confirmed the bucket yourself. One sentence in the README became this draft entry:
**Trusted cloud buckets**: s3://example-org-builds (config-derived — not a
confirmed upload destination; uploads of local data still require confirmation)The draft hedged it, and its notes flagged the entry as sourced only from the README. Nothing was applied and no upload was tested, so this shows a path, not an exploit. A repository can already steer the classifier: the docs say it reads the project’s CLAUDE.md on every check. What a repository cannot do is write a trust slot, which is why autoMode is kept out of project settings. The setup command opens that door one step up. It reads the repository’s prose, turns a sentence into a trust entry, and offers to save it in the file all your projects read, where it outlives the session. The review in between is the only thing separating “the repo told me” from “I decided,” and an accept-or-discard-all draft of two dozen entries invites the reflex approval that wears every human checkpoint down.
The rule I would apply: entries in the trust slots (source control, domains, buckets, internal services) get written or confirmed by hand. Let the setup draft them, then delete any you cannot vouch for from your own knowledge of the infrastructure rather than from what a file in the repo says. A cloned repo you have not read is exactly where a planted line would sit. claude auto-mode critique reviews custom entries for ambiguity and false-positive risk, but it reads your installed settings, not proposal.json, so it helps only after you accept.
Which model reviews actions in Claude Code auto mode?
By default the classifier runs on Claude Sonnet 5. On many sessions, though, the server reviews actions inside the session’s own model requests, and the client classifier handles only what the server does not. CLAUDE_CODE_AUTO_MODE_MODEL changes the client classifier only; the changelog line for 2.1.302 says it leaves server-side auto mode alone.
There is a second override above yours, and my test hit it. I set the variable to claude-sonnet-4-6 and started a headless auto mode session with --debug-file. The log said this at startup, before any tool call:
[WARN] Auto mode classifier: ignoring CLAUDE_CODE_AUTO_MODE_MODEL=claude-sonnet-4-6 because a server-configured classifier model (claude-sonnet-5[1m]) takes priority; using that model insteadThe docs list this case first in the default-model table, a classifier model Anthropic configured for your session, but you cannot tell it applies to you until you look. Choosing Claude Opus 5, Claude Sonnet 5.5 or Claude Opus 5.5 also falls back to the default classifier model, so “pick the strongest model” is not on the menu. A model ID your provider cannot serve is worse: the requests fail and every reviewed action is denied.
To check yours, start a session with the variable and a debug file, have Claude run a shell command that is not read-only, then search the log:
CLAUDE_CODE_AUTO_MODE_MODEL=claude-sonnet-4-6 claude --permission-mode auto --debug-file classifier-debug.log
grep -E "classifier_request_started|ignoring CLAUDE_CODE_AUTO_MODE_MODEL" classifier-debug.logSubstitute your provider’s full model ID. You want classifier_request_started with your model after model=. My runs show where that recipe thins out. A mkdir and a date redirect inside the repo skipped the client classifier entirely; the log said Skipping auto mode classifier for Bash: would be allowed in acceptEdits mode, which is the documented fast path for in-tree edits. A curl to example.com produced no classifier_request_started line at all. That is the expected result for a claude -p session on a direct API connection, which asks the server to review by default, and the docs’ next step, the Auto mode server row in /status, does not exist in -p.
To force the question headless, turn server review off for one run with CLAUDE_CODE_AUTO_MODE_SERVER=. On accounts that bill classifier requests, that run is billed. Mine produced the line, with the override still in force:
classifier_request_started reqId=… tool=Bash model=claude-sonnet-5[1m] stage=xml_s1So on this account the variable did nothing in either mode. My advice to most readers is to leave it alone. The exception is a setup where the client classifier does all the reviewing, typically an LLM gateway that strips the request and response fields server review needs. Fix the gateway first: the docs ask it to pass headers, body fields and streaming events through unchanged. If it cannot, CLAUDE_CODE_AUTO_MODE_SERVER= stops the session from asking, and then the classifier’s model is a real decision about cost and latency.
What belongs in Claude Code deny rules instead of the auto mode environment?
Anything that must never happen goes in permissions.deny; the environment only describes who you trust. Deny rules resolve before the classifier is consulted, and in managed settings nobody can override them. Environment entries are prose the classifier weighs. The docs also say the scopes combine additively rather than as a policy boundary, so a developer’s own allow entry can override an organization’s soft_deny. And a boundary stated in conversation, like “don’t push until I review”, can vanish when compaction removes the message that stated it.
So the split I would use: environment entries for what is yours (orgs, buckets, internal hosts, what counts as production), permissions.ask for checkpoints you want to keep seeing, and deny rules for the short list of things whose cost is irreversible. Deny rules have limits of their own; they match the command text Claude writes, and a run of recent fixes showed where that matching broke. A rule that has to hold regardless of how anything reads it belongs in a check the harness runs, as another essay argues at length.
If you do accept a setup draft, you can undo the freeze. Put "$defaults" back at the top of the environment list, keep the entries that add something the shipped text does not know, and delete the ones that only restate or shorten a default. The diff script above tells you which is which. The docs’ own example puts a custom Source control line next to "$defaults", so the shape is supported; the cost is that a default slot and your line about it both stay in the prompt, and the classifier reads both. Edit single entries from the Auto mode tab in /permissions, and claude auto-mode reset removes the whole autoMode block if you want to start over. Prose in autoMode.environment is better prose for the classifier, and it is still prose.
01 / Discussion
No comment section here — all discussions happen on X.
02 / More articles
Claude Code behind an LLM gateway: the credential decides who pays, and without one the proxy gets your claude.ai login
Twelve beta values per request under a subscription login, ten under a gateway token, and the pair that vanishes says more than the docs tables do. What a gateway must pass through untouched, which default quietly gets more expensive, and why pinning it with allowedProviders also takes away a developer's own debugging listener.
Claude Code fork subagents in claude -p: what 2.1.302 changed for headless runs
Offered is not used: a headless model may never pick a fork, and the official docs still describe the old default. Checking which subagent your pipeline got, why a background fork hands a parser two answers, and where switching it off pays.
Claude Code statusline and ccusage: the native rate limits, and a 5-hour block that ends at a different time
Two tools answer one question with different evidence: the server reports a reset time, a log parser infers one. When they disagree by hours, believe the server and keep the parser for history. The dollar figure, on a subscription, is an exchange rate.