← Back to BlogAgentic Coding

Claude Code Can Now Ask Before It Switches Models on You

Claude Code v2.1.251 added hooks to gate a model switch, but only the ones a person or client requests, not the fully automatic ones.

In June 2026, a Claude Code user discovered their session had silently swapped from Fable 5 to Opus 4.8 mid-task, and only because they happened to check the /model command. Anthropic closed the resulting bug report, which asked for so much as a visible notice, as a duplicate. Version 2.1.251, released August 28, 2026, closes part of that gap: two new hook events, PreModelSwitch and PostModelSwitch, let a hook block, require confirmation for, or log a change to the model running a session. The gate has one limit that matters immediately: it covers switches a person or a client asks for. The switches Claude Code decides to make on its own, a safety re-route or an opusplan phase handoff, for example, still happen automatically, and only become visible after the fact, through the same release's PostModelSwitch event.

Sources: Claude Code changelog (Anthropic)

The mechanism behind that June 2026 incident was the built-in switchModelsOnFlag setting, which silently moved the session once a message tripped a safety classifier. Anthropic closing the bug report as a duplicate, rather than a one-off, means it was not an isolated complaint. A model switch changes which system answers the next message, at what price, and under which safety posture, and none of that was surfaced to the user by default.

Sources: switchModelsOnFlag silently switches models without user notification (GitHub, anthropics/claude-code #67469)

This argument favors a category we build in, so read it with that disclosed: we build TLM Forge, a process layer that gates AI-driven changes inside Claude Code before they ship, and the instinct behind it, default to a check instead of trusting silent autonomy, is the same one this release brings to model selection. The sourcing under each claim below lets you check the framing yourself.

Model identity is not a cosmetic setting, and Anthropic's own product decisions say so. The opusplan alias treats Opus and Sonnet as suited to different work, Opus for complex reasoning and architecture decisions, Sonnet for code generation and implementation, which is an admission that swapping one for the other mid-task changes what the session is good at, not only what it costs. The safety-classifier fallback makes a related admission from another angle: a biology- or cybersecurity-flagged request already gets routed to a specific, more conservative model, because Anthropic does not treat every model as an interchangeable stand-in for another on sensitive requests. If model choice already carries that much weight inside Anthropic's own design, it made little sense to leave it ungated for the person accountable for the result.

Sources: Model configuration (Claude Code Docs)

Why Claude Code switches models without asking

Claude Code has changed a session's model on its own for a while, through at least three separate mechanisms that predate this release. The new hooks apply unevenly across them, which matters more than the list itself:

Sources: Model configuration (Claude Code Docs)

  • Overload or availability fallback: configure claude --fallback-model sonnet,haiku, or a fallbackModel array in settings, and Claude Code retries on the fallback the moment the primary model is overloaded, unavailable, or returns a non-retryable server error. Authentication, billing, rate-limit, and request-size errors never trigger it, so the mechanism covers capacity problems only.
  • Safety-classifier fallback: on Fable 5, a request flagged for biology re-runs on Opus 5, and one flagged for cybersecurity re-runs on Opus 4.8. The session stays on that model until someone runs /model to switch back.
  • The opusplan hybrid: Opus runs while a session is in plan mode, then Claude Code hands the session to Sonnet automatically the moment execution starts.

What PreModelSwitch actually covers

PreModelSwitch fires only for a switch a person or a client explicitly requested, not for the automatic cases above. Anthropic's hooks reference lists the exact triggers: the /model command and its picker, the Model setting in /config, turning on fast mode when that changes the session's model, and a set_model request from an Agent SDK host or from Remote Control. A hook can return allow, deny, or ask. Deny cancels the switch and shows the user a reason. Ask prompts for confirmation, though only the interactive /model command can actually show that prompt; everywhere else, including scripted -p mode, ask is treated as a refusal. When more than one hook answers, deny beats ask beats allow.

Sources: Hooks reference (Claude Code Docs)

The hook also receives what the switch will cost before it happens. context_tokens is the size of the prompt the next request re-sends, prompt_cache_warm says whether the current model's cache is still warm right now, the cache a switch is about to forfeit, and estimated_cache_write_usd prices re-caching that context on the destination model. A hook can quote that figure back in its confirmation reason, for example warning that a switch will re-send 180,000 tokens before the next reply. Claude Code also defaults to the stricter of two possible failure modes: a PreModelSwitch hook that does not answer within its 30-second timeout blocks the switch. A PreToolUse hook that times out lets the tool call through instead. A model identity change fails closed by default. A tool call fails open. One field works no matter what a hook decides: systemMessage reaches the user on every decision, including allow, so a hook that is not blocking anything can still report the cost of the switch it just let through.

Sources: Hooks reference (Claude Code Docs)

The matcher that decides which hooks fire has one sharp edge, and it changes how a deny-list hook should be written. Claude Code compares it against the canonical name of the destination model, so an alias like opus, a dated model ID, and a provider-specific Amazon Bedrock ID all resolve to the same match, and a matcher of claude-opus-5 catches every spelling of that model. When Claude Code cannot resolve a canonical name for the destination, for instance a custom model ID only a private LLM gateway knows, it runs every PreModelSwitch hook regardless of the matcher. A hook meant to block one specific model should therefore check to_model directly in its own logic, rather than trust the matcher alone to narrow things down.

Sources: Hooks reference (Claude Code Docs)

Insight

A PreModelSwitch hook cannot see or stop the switches Claude Code makes on its own. Safety re-routing and the opusplan handoff skip PreModelSwitch but still reach PostModelSwitch, so a team can log and guide them after the fact. A same-turn overload retry from a configured fallback chain skips both, because that substitution is built to leave the session's model of record unchanged. Gating, logging, and true invisibility are three different outcomes in this release, not one.

PostModelSwitch: visibility for the switches you cannot gate

PostModelSwitch runs after every model change, including the ones Claude Code makes on its own, and including restoring the model a person had set when a session resumes. It cannot block anything, since the change has already happened, but its source field says whether the switch came from a command, a picker, or an SDK request, versus an automatic fallback or a session resume, and it can hand Claude fresh guidance for the new model through additionalContext. Anthropic's own example injects a one-line instruction whenever a session switches to any Opus model: delegate implementation work to subagents and keep the conversation for planning and review. That is a workable substitute for a block. Nothing stops Claude Code from moving itself to a different model, but a team can make sure the session behaves differently the moment it does.

Sources: Hooks reference (Claude Code Docs)

What triggers the switchPreModelSwitch (can block)PostModelSwitch (log and guide)
/model command or the model pickerYes: allow, deny, or askYes, fires after
Model setting in /config, or fast modeYes: allow, deny, or askYes, fires after
set_model from an SDK host or Remote ControlYes: allow, deny, or askYes, fires after
Same-turn overload retry (fallback chain)No, skipped entirelyNo, the session model is unchanged
Safety-classifier re-routeNo, skipped entirelyYes
The opusplan plan-to-execute handoffNo, skipped entirelyYes
Model restored when a session resumesNo, skipped entirelyYes
Pro Tip

Write a PreModelSwitch hook that checks to_model against a short deny-list of retired or unapproved models, the same pattern Anthropic's own documentation uses to block a switch to a discontinued Opus version, and pair it with an ask decision on any switch whose estimated_cache_write_usd crosses a dollar threshold the team sets. That covers the two failures that matter most: someone picking a model the team no longer supports, and someone triggering an expensive re-cache without seeing the size of the bill first.

The same release makes a foreground subagent watchable live

Version 2.1.251 shipped a second observability change alongside the hooks: a foreground subagent's tool calls and results now stream live to Remote Control clients, so a person connected from claude.ai or the mobile app watches the subagent work in real time instead of seeing a status indicator alone. Background subagents, the default placement, still show status only. Remote Control itself keeps execution on the original machine, filesystem and tool access included, and only mirrors the session to a connected browser or phone. Set next to the model-switch hooks, the pattern holds: gate what a policy can defensibly pre-approve, and make everything else, a subagent's live actions, the model actually answering right now, visible enough that nobody is working blind.

Sources: Claude Code changelog (Anthropic), Continue local sessions from any device with Remote Control (Claude Code Docs)

The release also added a prompt-cache line to the /cost command, an alias for /usage, reporting the session's hit ratio, its miss count, how many tokens were re-cached, and whether the cache is warm or cold right now. A cache miss after a model switch is one of the more expensive and least visible costs in a long session. The new line and the estimated_cache_write_usd field a PreModelSwitch hook can already read cover the same cost from both sides of the event: an estimate going in, a confirmed number coming out.

Sources: Manage costs effectively (Claude Code Docs)

August also extended how separate Claude Code sessions relate to each other. Version 2.1.224, released August 7, added cross-session SendMessage with ListAgents to discover reachable sessions on the same machine, so two sessions can message each other directly instead of staying isolated. Later releases that month let a person type @ in a prompt to address another session by name, and extended the capability to sessions running on Bedrock, Vertex, and Foundry. That is a different feature from the model-switch hooks, but it belongs to the same story as how AI agents keep state across sessions: the boundary around a single Claude Code session keeps getting thinner, and each capability that crosses it needs the same question the model-switch hooks now ask: does this happen silently, or does something get to check first?

Sources: Claude Code changelog (Anthropic)

Gating and watching are the same discipline

TLM Forge is built on the same premise applied to code: an agent's autonomy is fine until a change is irreversible or costly enough that someone should sign off first, and a gate is how a team enforces that instead of hoping for it. A model switch mid-task and an unreviewed merge are the same problem at different scales: something changes the conditions the work happens under, and by default nobody has to approve it. The convergence gate blocks a diff from shipping until repeated review-and-fix cycles bring critical and high-severity findings to zero. PreModelSwitch blocks a model change until a person or a policy agrees it is fine. Different surface, same discipline: default to a check, not to trust.

Neither hook solves memory. PostModelSwitch can tell Claude to behave differently right after a switch, but nothing in the session remembers why a given model got denied last month, or which teammate approved the exception. That kind of decision belongs in a durable, team-visible place, an internal doc, a pinned thread, not inside a session that will eventually end and forget it. MemX, from the same team behind TLM Forge, is built for an individual's version of that same durability problem: a private, persistent memory layer for personal photos, documents, voice notes, and messages, not team engineering decisions.

None of this makes an automatic model switch dangerous by itself. Sonnet finishing a task that Opus started is routine, and the fallback chain exists precisely so an overloaded API does not stop a session cold, then dissolves back to the original model with nothing left to log. What changes with v2.1.251 is that the switches a person or a client asks for are now a governable decision instead of an instant default, and the automatic switches that actually stick, a safety re-route, an opusplan handoff, a restored session, are now a logged, guidable event instead of a disappearing one. A team that wires up both hooks gets to decide, on purpose, which of what remains fully automatic it is still comfortable with.

Frequently asked questions

01What are PreModelSwitch and PostModelSwitch in Claude Code?

Two hook events Claude Code added in version 2.1.251 on August 28, 2026. PreModelSwitch fires before a model switch a person or client requested and can block, confirm, or allow it. PostModelSwitch fires after any model change, including automatic ones, and can only log or add guidance.

02Does PreModelSwitch block automatic model switches like fallback or safety re-routing?

No. PreModelSwitch fires only for switches a person or a client explicitly requested, through /model, the model picker, /config, fast mode, or an SDK set_model call. Safety-classifier re-routing and the opusplan phase handoff skip it and reach PostModelSwitch instead; a same-turn overload retry typically reaches neither hook.

03When does Claude Code switch models automatically?

In at least three cases: retrying a request on a configured fallback model after an overload or server error, re-running a safety-flagged request on a different model (Fable 5 and Opus 5 both do this for certain domains), and the opusplan alias moving from Opus in plan mode to Sonnet once execution starts.

04What version of Claude Code added the model-switch hooks?

Version 2.1.251, released August 28, 2026. The same release added live streaming of a foreground subagent's tool calls to Remote Control clients and a prompt-cache line in the /cost command. Cross-session SendMessage and ListAgents shipped earlier that month, in version 2.1.224 on August 7.

05Can a Claude Code hook see the cost of a model switch before it happens?

Yes, for switches PreModelSwitch covers. Its input includes context_tokens, whether the prompt cache is still warm, and estimated_cache_write_usd, the projected cost of re-caching context on the new model, so a hook can warn the user before an expensive switch instead of after.

Ship AI-written code you can trust

TLM Forge is the missing process layer for Claude Code: a spec audit, independent multi-agent review, enforced TDD, and an adversarial red-team gate.

Get TLM Forge