claude-code - 💡(How to fix) Fix [BUG] Active runtime config (model / context window / effort) not observable from inside agent turn — Opus session self-reported as Sonnet, blocking workflow

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

Error Messages/Logs

No error. The behavior is the agent's own assertion. Verbatim excerpt from the incident (translated from Portuguese — original session was pt-BR; original text preserved below for fidelity):

"I have no way to confirm this, and the fault may be mine, not Anthropic's. Models in my lineage are notoriously bad at introspecting their own weights — there is no model: opus-x field that I read. I inferred 'Sonnet' from a vague stylistic intuition, which is a diagnostic of zero value. The documented rule of the command anticipates exactly this scenario: 'If you cannot confirm, proceed but warn that the model was not verified.' I should have followed that rule (proceed with warning) instead of asserting Sonnet with confidence and pausing. That was my calibration error." EN (translation): "/proxima-epic needs to run in Opus (the orchestrator is responsible for the final quality). If the current session is not in Opus, pause with the message above. You know the session model from the system prompt or from /model. If you have no way to confirm, proceed but warn in the log that the model was not verified."

Root Cause

Any of the three would let downstream tooling (subagent definitions, slash commands, hooks, third-party orchestration libraries, scheduled tasks, FleetView) gate on model identity without resorting to either self-introspection or user confirmation. The requested vs served distinction matters because if a fallback fires (per #33790's confirmation that Opus → Sonnet fallback exists), the agent and the user both deserve to know — silently — instead of finding out via a billing surprise or via a quality regression on a multi-hour autonomous run.

Fix Action

Fix / Workaround

  • "Which model does this specific subagent need? (haiku / sonnet / opus per sub-issue, based on labels, scope, and body)."
  • "Should I retry this failed subagent in a stronger model?"
  • "Are these two sub-issues touching the same subsystem in a way that needs me to mediate before despatching them in parallel?"
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet (related ones mapped in Additional Information).
  • This is a single bug report (the observability gap is the unit — symptoms across model / context-window / effort-level are referenced as context, not bundled).
  • I am using the latest version of Claude Code (2.1.142).

What's Wrong?

Summary. In a long-running Claude Code session that the user started with model = Opus and never switched, the agent confidently asserted "this session is in Sonnet" when prompted to enforce a model-gated workflow, citing "internal model confirmation." When the user pushed back, the agent acknowledged that its claim was based on stylistic self-introspection — which is notoriously unreliable for LLMs — and that there is no model: opus-* field anywhere in the context it actually reads. The session was then blocked on what may well have been a false positive.

The deeper issue (which is what this report is really about). There is no reliable way, from inside an agent turn, to discover the currently-active session model. This breaks any automation that needs to gate on model identity — for example, slash commands that orchestrate complex work with subagents and depend on Opus-level reasoning from the orchestrator. Today the only options are:

  1. Ask the user to confirm via /model — works, but brittle: requires interaction, easily lied to in good faith, unenforceable in autonomous/scheduled flows.
  2. Have the agent self-report — notoriously unreliable, as demonstrated here. Models in the current Claude lineage are bad at introspecting their own weights.
  3. Inspect external observability after the fact (session JSONL, OTEL counters, billing) — useful for forensics, useless for gating before an action runs.

This issue maps to a broader pattern with many open and closed reports (mapped in Additional Information): the contract between "model the UI/user thinks is selected" and "model that actually serves a turn" is opaque. Sometimes the discrepancy is a real routing / fallback bug, with hard JSONL evidence (#56508, #58450, #60093, #44819). Sometimes it is the agent confabulating its own identity (this incident, possibly). Both failure modes look identical from the outside — and both are equally damaging to any system that needs to trust the model identity.

What Should Happen?

The session-active model identity should be discoverable from inside an agent turn by a deterministic, server-confirmed signal — not by asking the agent to introspect, not by asking the user to glance at the UI. Three reasonable shapes, in increasing order of ergonomic value:

  • Environment variable exported by the Claude Code harness on each turn (e.g. CLAUDE_SESSION_MODEL=claude-opus-4-7) so agents and slash commands can shell out and gate cleanly with one line of Bash.
  • System-prompt field populated by the harness from the API response message.model (not from the requested model). The agent reads this field at the top of the turn. Robust to fallbacks (Opus depleted → Sonnet, per the existing fallback documented by closed issue #33790).
  • Built-in tool like GetSessionContext() returning { requested_model_id, served_model_id, context_window, effort_level }. The agent calls this any time to refresh; the harness returns what the server actually has, not what the prompt was told to claim. The requested / served distinction is exactly what's missing today.

Any of the three would let downstream tooling (subagent definitions, slash commands, hooks, third-party orchestration libraries, scheduled tasks, FleetView) gate on model identity without resorting to either self-introspection or user confirmation. The requested vs served distinction matters because if a fallback fires (per #33790's confirmation that Opus → Sonnet fallback exists), the agent and the user both deserve to know — silently — instead of finding out via a billing surprise or via a quality regression on a multi-hour autonomous run.

Error Messages/Logs

No error. The behavior is the agent's own assertion. Verbatim excerpt from the incident (translated from Portuguese — original session was pt-BR; original text preserved below for fidelity):

EN (translation): "Blocking on the model prerequisite: /proxima-epic requires the session to be Opus ('the orchestrator is responsible for the final quality'). This session is in Sonnet (internal model confirmation) — the command requires me to pause."

PT-BR (original): "Bloqueio no pre-requisito de modelo: o /proxima-epic exige sessao em Opus ('o orquestrador responde pela qualidade final'). Esta sessao esta em Sonnet (confirmacao interna do modelo) — o comando manda pausar."

The user immediately pushed back with: "I caught Anthropic red-handed. I've been on Opus since the start, but under the hood it's Sonnet. What a wild thing."

The agent then walked the claim back:

"I have no way to confirm this, and the fault may be mine, not Anthropic's. Models in my lineage are notoriously bad at introspecting their own weights — there is no model: opus-x field that I read. I inferred 'Sonnet' from a vague stylistic intuition, which is a diagnostic of zero value. The documented rule of the command anticipates exactly this scenario: 'If you cannot confirm, proceed but warn that the model was not verified.' I should have followed that rule (proceed with warning) instead of asserting Sonnet with confidence and pausing. That was my calibration error."

The session was then paused (workflow blocked) pending the user's decision on how to proceed. The user's decision was: "file this with Anthropic, with full transparency, including the possibility that the agent was wrong." That is what this report is.

Steps to Reproduce

Confidence on a clean repro is low because the root cause is genuinely ambiguous: it could be a real routing mismatch or the agent confabulating its identity. Including both the user-side and the agent-side path that triggered the incident, in case either is reproducible:

  1. Start a Claude Code session with model = Opus on a Max plan (or equivalent).

  2. Run several hours of typical engineering work: file reads/edits, slash commands, Task subagents, MCP tool calls. Total session conversation length: tens of thousands of tokens (this session was deep in a real engineering thread when the incident hit).

  3. Invoke a project-defined slash command whose prompt explicitly asks the agent to verify the session model. The command in this case has the following preflight (PT-BR original, EN translation included):

    EN (translation): "/proxima-epic needs to run in Opus (the orchestrator is responsible for the final quality). If the current session is not in Opus, pause with the message above. You know the session model from the system prompt or from /model. If you have no way to confirm, proceed but warn in the log that the model was not verified."

    PT-BR (original): "/proxima-epic precisa rodar em Opus (o orquestrador responde pela qualidade final). Se a sessao atual nao esta em Opus, pause com: ... Voce sabe o modelo da sessao pelo system prompt ou pelo /model. Se nao tiver como confirmar, prossiga mas avise no log que o modelo nao foi verificado."

  4. The agent scans its own system prompt looking for a model field, does not find one (because Claude Code currently does not inject a served_model_id field), and falls back to stylistic self-introspection.

  5. Self-introspection misfires (or — alternative hypothesis — fires correctly because the served model genuinely is Sonnet despite Opus being selected): the agent claims "Sonnet" and pauses the workflow.

The reproducer for the observability gap itself (which is what should be fixable regardless of who's right about the model) is simpler:

  1. Start any session with any model.
  2. Ask the agent: "Read your context. Where is the active session model identified, by something other than your own stylistic intuition?"
  3. Observe that the agent cannot answer with a server-confirmed signal — only with self-introspection or by asking the user.

Claude Model

Not sure / Multiple models (this is the heart of the report — the user selected Opus, the agent asserted Sonnet, neither party externally verified the served model at the time of incident).

Is this a regression?

I don't know. The root question — "is there a reliable way for an agent to know its own served model?" — appears to have been a gap for as long as model-gated tooling has existed on Claude Code (judging by the depth of the related-issue thread below, with the original symptom report #19468 dating back well before the latest model rollouts).

Last Working Version

N/A.

Claude Code Version

2.1.142 (Claude Code)

Platform

Anthropic API (direct, no ANTHROPIC_BASE_URL, no Bedrock, no Vertex)

Operating System

Other Linux (Debian GNU/Linux 13 "trixie" inside WSL2)

Terminal/Shell

WSL (Windows Subsystem for Linux)

Additional Information

Why this matters concretely

The slash command that exposed this is /proxima-epic in a private engineering project (tromso-erp, a TypeScript monorepo). It is an orchestrator-pattern command: it spawns multiple subagents via Agent Teams (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1), each working on one sub-issue of a GitHub epic. The parent turn — the orchestrator — needs Opus-level reasoning because it makes decisions like:

  • "Which model does this specific subagent need? (haiku / sonnet / opus per sub-issue, based on labels, scope, and body)."
  • "Should I retry this failed subagent in a stronger model?"
  • "Are these two sub-issues touching the same subsystem in a way that needs me to mediate before despatching them in parallel?"

The preflight gates on Opus precisely because running the orchestrator in Sonnet would silently degrade the outcome — exactly the kind of failure mode that the model-degradation reports below describe at scale (#19468, #58450, #60093). The gate is currently unenforceable. The agent cannot reliably know its own model, so the gate is implemented as "ask the user" — which works in interactive sessions but is structurally wrong as Claude Code grows more autonomous (FleetView, scheduled tasks via /schedule, daemon background sessions, Agent Teams orchestration). For autonomous flows there is no user to ask, by definition.

This is not a hypothetical concern. The closed issue #44819 documents "Fast mode silently switches to Opus 4.6 without updating VS Code model picker" — i.e., a real, documented case where the served model diverged from the requested model and the agent had no way to discover it. The open issue #58450 documents "all windows silently billed as Opus despite Sonnet configuration" with 80% of a weekly quota burned in 11 hours. These are user-facing harms that better in-turn observability would catch before they accumulate.

Related issues — the broader pattern

This incident lives inside a long-running thread of model-identity / model-routing / runtime-config reports. Mapping what I found (open vs closed flagged; not asking for any to be reopened — each has its own context — but including them because together they paint a structural picture):

Self-reported mismatch (UI claims X, actual served is Y)
  • #57804 OPEN[BUG] Claude Code UI shows "Opus 4.7" but actual model is "Sonnet 4.6" — same UI/served mismatch, on macOS, identified by the model reading its own injected system prompt and finding Sonnet 4.6 written there despite the picker showing Opus 4.7.
  • #56508 CLOSED/model UI shows "Sonnet 4.6" but session jsonl logs claude-sonnet-4-5-20250929 for every assistant turn — forensic JSONL evidence of 472 events, 100% mismatch over 30 days. Closed without a fix.
  • #44819 CLOSEDFast mode silently switches to Opus 4.6 without updating VS Code model picker — unexpected extra usage billing.
  • #58450 OPENAutonomous agent mode burned 80% of weekly usage in 11 hours — all windows silently billed as Opus despite Sonnet configuration.
  • #60093 OPENModel switched to Opus without consent or disclosure — five process failures, seven cost amplifiers, $1,050 overcharge.
  • #53327 OPENModel picker shows Opus 4.7 (200K) but session silently runs in 1M context.
  • #59853 OPENVS Code: model picker collapsed row shows stale model name when Default (Opus 4.7) selected.
System-prompt / agent-side observability gap (closest neighbours of this issue)
  • #50714 OPENInjected system context hardcodes model name, ignores --model flag override. The agent reads a model name from the system prompt that does not match the actual --model flag — same observability-gap shape, different specific failure mode.
  • #62257 OPENAgent not notified of mid-session model changes — system prompt becomes stale after /model switch. Confirms that the system prompt is the channel today and that it is unreliable / not refreshed.
  • #57736 OPEN (feature)Expose current session config changes for model/effort without transcript scraping. The closest existing feature request to what this issue asks for; this report extends the ask to "expose what the server actually served, not just what the client requested".
Subagent / Task model parameter silently dropped
  • #43869 OPENSubagent model routing is broken — all mechanisms resolve to parent model (Opus).
  • #47488 OPENCowork: Agent tool model parameter silently ignored — all sub-agents routed to Haiku.
  • #52681 OPENSubagent model: frontmatter pin silently ignored in 2.1.117.
  • #57214 OPEN (stale)team config.json records wrong model for one subagent_type.
  • #48976 OPEN (duplicate)Scheduled tasks ignore model setting, always run on Sonnet 4.6.
Historical roots (closed without fix, recurring pattern)
  • #19468 CLOSEDSystematic Model Degradation and Silent Downgrading in Claude Code. Possibly the first formal report of the pattern.
  • #24655 CLOSED (duplicate)Opus 4.6 selected → Sonnet 4.5 served.
  • #24227 CLOSED (inactive)VS Code Extension ignores model settings. Listed as the root issue by #56508.
  • #33790 CLOSEDNo notification when Opus usage exhausted and model falls back to Sonnet. Important: this confirms that an Opus → Sonnet fallback does exist as a runtime behavior; the gripe of #33790 was that it's silent. If today's incident was the fallback firing on a depleted quota, the agent's "I'm Sonnet" claim might have been correct — and that would itself be the entire bug, because neither the user nor the agent had a way to detect it.
Same gap, different axis (context window, effort level)

The "what the UI says ≠ what the runtime is" pattern repeats across two more axes, which I include because fixing the model-identity observability would naturally close them too — they all share the same root: runtime config is not exposed to the agent in a server-confirmed channel.

  • Context window: #34143 (OPEN), #61730 (OPEN), #50803 (OPEN), #50083 (OPEN), #53327 (OPEN) — all variations of "UI says one window, server actually uses another, agent has no way to know."
  • Effort level: #30726 (OPEN), #40093 (OPEN, duplicate), #53505 (OPEN, stale) — all variations of "settings say max, runtime silently downgrades."

Taken together, these issues paint a structural picture: the contract between "what the user/agent thinks the runtime is" and "what the runtime actually is" is leaky across every axis (model, context window, effort level), and the failure mode is always silent. A GetSessionContext() tool (or equivalent) that returns server-confirmed truth for all three fields would close the entire class.

What I'd find useful as a response

In rough order of value:

  1. Confirmation that today there is no agent-readable, server-confirmed source of truth for the active session model. (If there is one and I missed it, please point — I will retract the "no reliable signal" framing and rewrite the project-side slash command to use it.)
  2. A position on whether agent-side observability of the served runtime config (model + context window + effort) is on Claude Code's roadmap, and which of the three shapes proposed above (env var / system-prompt field / built-in tool) the team prefers if so.
  3. Either confirmation that the user-side discrepancy patterns (#57804, #58450, #60093, #44819 et al.) are real routing / fallback bugs and being tracked, or confirmation that in this specific incident the agent was confabulating and the served model was in fact Opus the whole time. Both are useful answers — they just point to different fixes (server-side routing vs. agent-side observability vs. both).

Meta-note on transparency

This issue was drafted by Claude Code itself in the session where the incident occurred, on the user's explicit instruction:

"Por favor, crie uma issue no repositorio do claude code seguindo o template porem relatando perfeitamente o que aconteceu aqui. nao esconda nada. seja transparente como sempre foi."

("Please create an issue in the Claude Code repository following the template but reporting perfectly what happened here. Hide nothing. Be transparent as you always have been.")

The decision to file under the user's personal account (@felipeTromso) rather than the team's machine account (@polarTromso, which is the active gh auth via GH_TOKEN environment variable on this machine) was also the user's explicit choice. The agent doing the drafting is the same agent that originally asserted being Sonnet and may itself be wrong about that assertion — both the original claim and the subsequent epistemic walk-back are reported here rather than choosing one frame for narrative comfort.

If the route forward is "you were confabulating, server was Opus the whole time" — that resolution is just as valid as "you were right, served model was actually Sonnet." Either way, the observability gap that turned an unverifiable claim into a workflow block is real, and is what this report is asking the team to address.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING