Claude Code switches models without showing it on screen — one config line that can break "verification stays on the top model", found by reading all 789 lines of the spec
Introduction
As an operating policy for my AI coding assistant, I had settled on “use the top model freely for design judgements and verification work; do not downgrade for cost reasons”. That policy and a single line that had sat in my config file for a long time — a setting naming where to go when the model is busy — were in fact in direct tension, and I did not notice until I read the official model-switching specification all the way to the end.
The first time I opened that document, I skimmed the parts that looked necessary and stopped. This time I read all roughly 789 lines to the end, and checked what was written in the parts where I had broken off.
The range I had stopped at when reading in part
On the first pass I confirmed only the default depth of thinking per model (effort) and the handling of the context window, and finished there.
The default effort is
highon every model that supports effort, except Opus 4.7, which defaults toxhigh.
On the Anthropic API, [the supported model set] always run with the 1M window.
I had read that far, but had put off the chapters on organisational model allow-lists and the fallback-chain mechanism, and on environment variables and prompt-cache settings. I was aware there was a range I had not read, so I marked it explicitly as unread and moved to the next piece of work.
Reading the rest turned up an invisible switching route
Days later I read the remaining range to the end. What caught my eye first was a sentence saying that the mechanism by which the model switches automatically does not appear on screen.
Claude Code doesn’t confirm the chain at startup and
/statusdoesn’t display it. The notice shown when a switch happens is the first visible sign that a fallback is configured.
There is a mechanism that switches automatically to an alternative model when the primary is unavailable — busy, or otherwise unusable. But that setting is displayed neither at startup nor by the status command: the notice at the moment a switch actually happens is the only means of visibility.
The switch lasts for the current turn only, so your next message tries the primary model first again.
The switch reverts after a single exchange. Which means that if you miss the notice, there is no way to learn afterwards that just that one exchange was answered by a different model.
Another switching route — it can fire on the conversation’s content alone
Reading further showed that the model also switches by way of an automatic safety judgement.
When a classifier flags a request and the flagged category has a fallback model, Claude Code re-runs the request on that model and shows a notice in the transcript.
Fallback can trigger on the first request of a session, before you send anything unusual, because the first request carries workspace context such as your CLAUDE.md content and git status. A repository that contains security or biology material can trip the classifier on that context alone.
Merely working in a repository containing security-related material means this judgement can fire on the very first exchange of a session, before you have sent anything unusual. And once it fires, the session keeps running on the switched-to model until you manually go back.
After a fallback, the session continues on the fallback model. To return to your original model, run
/model.
The setting for stopping that automatic switch and changing it to “choose each time myself” was in the same specification.
To decide what happens each time a request is flagged, rather than switching automatically, run
/configand turn off Switch models when a message is flagged, or setswitchModelsOnFlagtofalse.
Measuring my own configuration
Rather than settling for an assumption, I checked the relevant part of the actual config file (measured 2026-08-24; implementation-specific values omitted as irrelevant here).
{
"fallbackModel": ["sonnet", "haiku"],
"switchModelsOnFlag": false,
"autoCompactWindow": 200000
}
fallbackModel had alternatives set two deep. Before reading the specification I could not have explained when or on whose judgement that setting went in. Alongside a stated policy of “spare no expense on the top model for verification and design judgements” sat a setting that silently switches to a lower model when things are busy. The measurement also confirmed that switchModelsOnFlag was already false (the side that asks each time rather than switching automatically).
Diagram — where, what, and to which model it switches
mid-exchange on the primary model
│
├─▶ route ①: the primary model is busy or unavailable
│ └─ switch to the fallback chain (the configured alternatives), for that exchange only
│ └─ displayed neither at startup nor by the status command (official)
│ └─ the only means of visibility is "the notice at the moment of the switch"
│ └─(return edge)→ the next exchange reverts to the primary model automatically
│
└─▶ route ②: the automatic safety judgement reacts to the conversation's content
└─ can fire on the session's first exchange alone (which carries working-directory information)
└─ once fired, the session continues on that alternative model until manually reverted
└─ whether to switch automatically or ask each time is configurable (official)
└─ measured: set to the ask-each-time side
The vertical flow is “from an exchange on the primary model, through a switch, and back”, the horizontal branches are the two firing conditions “busy, or safety judgement”, and the nesting at the bottom is the loop of the automatic-or-manual control choice cross-checked against my actual configuration.
What became clear, and what has not
Reading all 789 lines through settled three points.
| What was checked | Result |
|---|---|
| Whether the absence of an on-screen notice for model switching is a failure of observation or the specification | As specified. By design the notice appears only at the moment of the switch |
| Whether a safety-judgement model switch can fire on the conversation’s content alone | It can (stated officially). But no instance of it firing has been confirmed |
| Whether my environment is set to automatic switching or to asking each time | Set to the ask-each-time side (confirmed by measurement) |
On the other hand, when the busy-time fallback setting was put in, and what for, did not become clear from this read-through alone. Reading a specification and tracing the history of your own environment are separate jobs, and I have not started the latter. How many times that policy and this setting have actually collided will not be settled either, short of going back through the notice logs — that too goes in only once measured.
Bigger than what reading it through made clear was how sharply it outlined what reading it through did not. A specification tells you only what can happen. How many times it actually happened in your environment lives not in the spec but on the side of the notice logs.