[BUG] VS Code extension: model/effort picker pill is stale, disconnected from the session's actual resolved settings

Status Open
Reported on v2.1.278
Maintainer reply None cached
Activity 1 comment · opened Sep 20, 2026

Environment: VS Code extension anthropic.claude-code 2.1.278, CLI backend 2.1.263, Linux (WSL2/Debian).

What's wrong: the model/effort pill shown at the bottom of the Claude Code panel (e.g. "Sonnet 5 Medium") does not reflect the settings that are actually resolved and used for the session's real API calls. It appears to be a cached/restored UI value rather than a live read of the settings files on session open.

Repro:

  1. In a workspace, set ~/.claude/settings.json (user scope) to something like:

``json
{ "model": "sonnet", "effortLevel": "high", "modelSettings": { "claude-sonnet-5": { "effortLevel": "medium" } } }
``

  1. In that workspace's .claude/settings.local.json (project-local scope, gitignored), set:

``json
{ "effortLevel": "low" }
``

  1. Close and reopen VS Code on the workspace, and open a brand-new Claude Code session/tab (no prior turns).
  2. Read the pill at the bottom of the panel.

Observed: the pill reads "Sonnet 5 High" — matching neither of the two effort values actually present in the files (medium from the user file's modelSettings.claude-sonnet-5.effortLevel, nor low from the project-local file), and matching only the OLDER, deprecated top-level effortLevel key in the user file, which the picker itself no longer even writes (current picker saves per-model, via modelSettings).

Ground truth, read from the transcript of an actual sent prompt in that same tab: the real API call ran at claude-sonnet-5 / effort low — the project-local file's value, correctly resolved per the documented precedence (project-local > project > user). So:

| source | value |
|---|---|
| picker pill (displayed) | High |
| user file, modelSettings.<model>.effortLevel | Medium |
| project-local file, effortLevel | Low |
| actual API call (verified from the session transcript) | Low |

The actual resolution is correct. The displayed pill is wrong, and matches none of the three candidate sources cleanly — it specifically matches the stale/deprecated top-level key, which is consistent with the pill being restored from some prior cached UI state (extension global/workspace storage?) rather than freshly resolved from the settings files each time a session starts.

Expected: the pill reflects the model/effort the session will actually use (or actually used, once a turn has run), freshly resolved on each new session, exactly as the underlying API call is resolved.

Impact: the pill is the only UI signal for what a session is about to run on. When it disagrees with reality, a user has no way to tell short of grepping the session's transcript JSONL for the model/effort fields on an actual assistant message (which most users cannot easily do). In our case this was caught only because a third-party tool (a UserPromptSubmit hook) independently computed and displayed its own resolution, disagreeing with the pill, which prompted the investigation.

Possibly the same root cause as:

  • #91184 (picker disconnected from a session's real model/effort in both read and write directions, for a settings-file-overridden session spawned via the URI handler) — our repro is a plain interactive session (no URI handler, no cross-session bridging), so if it is the same bug, the "picker is not a live read of session state" defect is broader than that issue's spawn-path scoping suggests.
  • #77374 (closed as stale, not fixed — "Model picker shows Fable but is actually Opus") — same shape (displayed model/effort disagrees with the real one), on an older version (2.1.208); this report reproduces the same class of defect on a current version (2.1.263 / extension 2.1.278).

Not the same as #90408, which is about actual resolution ignoring project scope — in our repro, actual resolution was correct; only the display was wrong. We're not certain whether all of these share one root cause or are several distinct display/resolution bugs that happen to look similar from the outside; flagging the overlap in case it helps triage rather than asserting it.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗