Model changes mid-turn on a long-running session, with no way to tell user-initiated from app-initiated

Status Open
Maintainer reply None cached
Activity 0 comments · opened Sep 1, 2026

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

  1. 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.
  2. 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.
  3. 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.

View original on GitHub ↗