Model changes mid-turn on a long-running session, with no way to tell user-initiated from app-initiated
Summary
On a long-running always-on session, the active model changed between claude-fable-5 and claude-opus-5 five times within a few minutes, mid-turn, while the session was in the middle of multi-step orchestration (dispatching subagents, cross-session messaging, writing state files).
The operator reports not initiating these switches. From inside the session there is no way to tell whether a model change was user-initiated or app-initiated — both surface identically in the transcript, as:
<command-name>/model</command-name>
<command-args>claude-opus-5</command-args>
<local-command-stdout>Set model to claude-opus-5</local-command-stdout>
labelled as "generated by the user while running local commands". No origin, no reason, no distinction between "the human clicked/typed this" and "something else set it".
This is on macOS (Darwin 25.6.0), Claude Code CLI, in a session that had been running for many hours.
Why this matters more than a cosmetic switch
The affected session is the coordinating agent for a fleet of ~25 concurrent Claude Code sessions — it holds standing program state and dispatches work to the others. A model change landing mid-turn on a coordinator is not the same as switching models between prompts: it arrives partway through orchestration, and the session's own reasoning/behaviour characteristics change while multi-step work is in flight.
It is also not diagnosable from inside the session, which is the part that turns a minor annoyance into a real support problem. The operator believed the app was switching models on its own; the agent could not confirm or refute that, because the transcript representation is identical either way. Neither party can answer "did something switch this, or did I?"
What we'd like
- Model pinning for a session — a way to fix the model for the life of a session so that nothing can change it mid-run. For an unattended/long-running agent this is the important one.
- Attribute the change in the transcript. If a model change is app-initiated (fallback, capacity, load-shedding, error-retry, anything), say so and say why, distinctly from a user-issued
/model. If it is user-initiated, mark that too. Right now they are indistinguishable, which makes the behaviour unfalsifiable from the session side. - Guard mid-turn switching. If a switch arrives while a turn is in flight, either defer it to the turn boundary or require confirmation.
Repro
Not reliably reproducible on demand — reporting the observation and the diagnosability gap, which stands regardless of the cause of the switching. If there is a client-side log that records model-change origin, a pointer to it would be useful and may be sufficient to close item 2.