Agent.Space Blog

Claude Code Model Switch Hooks in v2.1.251

Learn how Claude Code v2.1.251 PreModelSwitch and PostModelSwitch hooks control, confirm, audit, and adapt model changes safely.

Claude Code v2.1.251 adds two lifecycle events for model changes: PreModelSwitch runs before a requested switch and can allow, deny, or ask for confirmation; PostModelSwitch runs after a change and can log it or add model-specific context to the next request. The important distinction is that the first event is a policy gate, while the second is an adaptation and audit point.

That distinction matters if a team uses different models for planning, implementation, or review. A model switch can change cost, available context, and expected behavior without changing the repository. These hooks let you make that transition visible and governed instead of relying on every developer to remember a convention.

This guide focuses on the new model-switch contract. For the separate question of how Claude Code access is billed, start with the Claude Code pricing guide.

What changed in Claude Code 2.1.251

Anthropic's v2.1.251 release notes introduced PreModelSwitch and PostModelSwitch. The same release also added session-staleness and estimated re-cache cost fields to resumed SessionStart hooks, but those are not substitutes for the two new events.

Before this release, a hook could observe session start or intercept tool calls, but neither point represented a model transition precisely. The new events expose the model being left, the requested target, the resolved target, the source of the switch, and an estimate of the prompt-cache rewrite involved.

Both model-switch events require Claude Code v2.1.251 or later. If a shared project configuration depends on them, document that minimum version and verify it in every environment where the policy is expected to run.

PreModelSwitch versus PostModelSwitch

The names sound symmetrical, but their authority and coverage differ.

QuestionPreModelSwitchPostModelSwitch
When does it run?Before a user or client-requested switchAfter the session model has changed
Can it stop the switch?YesNo
Can it require confirmation?Yes, with surface limitationsNo
Does it see automatic fallback?NoYes, when the session model actually changes
Can it add guidance for the new model?Not as additionalContextYes, for the next request
Typical jobPolicy gate or cost warningAudit, environment update, or model-specific guidance

According to the official PreModelSwitch reference, the event runs for the /model command and picker, the Model setting in /config, certain fast-mode changes, and model requests from an Agent SDK host or Remote Control. It does not run for a model change Claude Code makes on its own, such as automatic fallback or restoration during resume.

PostModelSwitch covers those requested changes and also observes a persistent automatic fallback, some mode-driven changes, and the model restored with a resumed session. A one-turn substitution from a fallback chain does not count because the session's selected model has not changed.

Use both events if your rule needs prevention and complete after-the-fact visibility. Using only PreModelSwitch leaves automatic changes outside the audit trail. Using only PostModelSwitch tells you what happened but cannot undo it.

Choose block, ask, annotate, or audit

Start with the job the hook must perform.

Block a disallowed target

Use PreModelSwitch when a repository or organization has a real allowlist. A command hook can exit with code 2, or return a structured deny decision, to cancel the switch. This is appropriate for an unsupported model, a provider route that is not approved for the project, or a temporary freeze during an incident.

Do not depend on the matcher alone. Claude Code normally compares the matcher with the target's canonical model name. If it cannot canonicalize a custom model ID understood only by an LLM gateway, it runs every matching PreModelSwitch hook. The hook should inspect to_model before it allows or denies anything.

Ask before a costly or disruptive switch

The PreModelSwitch input includes context_tokens, prompt_cache_warm, cache_ttl, estimated_cache_write_usd, and the pricing source used for that estimate. A hook can use those fields to explain why a warm-cache switch may resend context.

Treat the dollar value as an estimate, not an invoice. The documentation notes that the server might not need to recache the entire context.

An ask decision has an important limit: only /model in an interactive session can show the confirmation. On non-interactive surfaces, /config, and SDK set_model requests, Claude Code treats ask as a refusal. If automation must continue unattended, choose an explicit allow-or-deny policy instead of assuming a prompt will appear.

Annotate the new model

Use PostModelSwitch when the next model needs conditional context, such as a model-specific review checklist or a reminder about which task phase it owns. Plain-text stdout on a successful command hook, or additionalContext in JSON output, is delivered with the next request after the switch.

Keep this context short and factual. Static project rules still belong in CLAUDE.md; a model-switch hook is better for information that changes with the active model.

Audit every persistent session-model change

Use PostModelSwitch to send structured events to an internal audit endpoint or append them to an approved log. Record at least the time, session identifier, from_model, to_model, and source. Avoid copying the whole transcript or secrets into a log just because the hook can access session metadata.

A minimal safe configuration

Hooks can live in user, project, local, managed, plugin, or component configuration. A project-wide rule normally belongs in .claude/settings.json, where it is shareable and reviewable. A personal experiment belongs in .claude/settings.local.json or user settings instead.

This minimal pattern uses a broad matcher and checks the actual target inside the command. Replace YOUR_APPROVED_MODEL_PATTERN with a deliberately reviewed regular expression before using it:

json
{  "hooks": {    "PreModelSwitch": [      {        "matcher": ".*",        "hooks": [          {            "type": "command",            "command": "jq -e '.to_model | test(\"YOUR_APPROVED_MODEL_PATTERN\")' >/dev/null || { echo 'Target model is not approved for this project.' >&2; exit 2; }"          }        ]      }    ],    "PostModelSwitch": [      {        "matcher": ".*",        "hooks": [          {            "type": "command",            "command": "jq -r '\"Session model changed to \\(.to_model). Apply the matching project review policy.\"'"          }        ]      }    ]  }}

This example is intentionally a pattern, not a universal allowlist. It assumes jq is available and that your reviewed model naming rules can be expressed safely. For production, a dedicated script is easier to test than a long inline shell command.

Use /hooks to inspect the loaded configuration, then test from a disposable session by switching from one allowed model to another and attempting one denied target. Also test resume and any SDK-controlled switching path you actually use.

Operational limits to test before rollout

The official Hooks reference defines several boundaries that should be part of review:

  • PreModelSwitch supports command, HTTP, and MCP tool handlers, not prompt or agent handlers.
  • A timed-out PreModelSwitch command blocks the switch; its default timeout is 30 seconds. Keep a policy hook fast and dependable.
  • When several pre-switch hooks disagree, decision precedence is deny, then ask, then allow.
  • PostModelSwitch cannot block. Its context can arrive one request later if it has not finished within five seconds of the next prompt.
  • Project hook configuration executes code. Review it like any other executable repository change, and do not accept hooks from an untrusted workspace without inspection.
  • Hooks complement Claude Code permissions; they do not replace operating-system isolation, credential controls, provider policy, or code review.

These limits are why a short, explicit policy is usually safer than a clever script that tries to infer every acceptable situation.

Where Agent.Space fits

Model-switch Hooks govern behavior inside Claude Code. They do not select how an API request is funded, discover which models an account can use, or turn one provider protocol into another. Those are different layers.

The Agent.Space Developer API guide describes a separate access layer for verified server integrations: clients discover the live model list, select a supported protocol, and let the selected model determine whether Share or Flex funds a request. Share and Flex remain separate, and requests do not silently move from one to the other. That guide does not currently define a verified Claude Code connection path.

That separation makes the combined workflow easier to reason about:

  1. Use Claude Code's PreModelSwitch and PostModelSwitch events for local or organizational switch policy.
  2. Use the live model discovery and request history of the configured access provider to verify what was actually available and charged.
  3. Keep the harness, model, workspace, and funding source distinct—the same boundary explained in how Agent.Space works.

Do not copy a server SDK configuration into Claude Code or infer compatibility from the Anthropic Messages protocol alone. Use Claude Code only with an access provider and connection path that the provider currently documents and verifies; keep Agent.Space Developer API funding as a separate server-integration decision.

The practical takeaway

Use PreModelSwitch to decide whether a requested transition may happen. Use PostModelSwitch to observe the model that actually became active and adapt the next request. Deploy both when you need policy plus complete visibility, and test automation, resume, custom gateway IDs, and timeout behavior before treating the configuration as a team control.