[BUG][REGRESSION] model:/effort: frontmatter override silently broken for BOTH commands/*.md and skills/SKILL.md (v2.1.220, worked on v2.1.197)
This is not a duplicate — please don't auto-close it as one
I know this looks similar to several older reports, and I want to head that off explicitly: this is a fresh, broader regression, confirmed today on the current version (v2.1.220), and it's more severe than any single prior report because it now affects both mechanisms at once (commands/*.md and skills/SKILL.md), for the simplest possible case (direct, user-typed slash invocation — no Agent/Task tool involved). The stale-bot auto-closed every prior related report without a fix (see "Related reports" below) — please don't repeat that here without someone actually looking at it. If maintainers confirm it's truly the same root cause as one of those, I'm happy to have this merged/redirected there instead of closed outright — I'd just like a human to make that call, since the stale-bot closures previously buried this without resolution for months.
Summary
Setting model: and/or effort: in the frontmatter of a custom slash command (~/.claude/commands/<name>.md) or a skill (~/.claude/skills/<name>/SKILL.md) no longer switches the model/effort for that invocation. The override is silently ignored — no error, no warning — and the turn silently runs on the session's default model/effort instead. This removes a basic, previously-reliable control surface: there is currently no working way to pin a specific model/effort to a specific slash command.
Severity / impact
This is a sharp regression, not a missing feature: the exact same override mechanism worked correctly in the same long-lived session on v2.1.197 (2026-07-02) and fails on v2.1.220 (2026-07-26). Anyone who built tooling around per-command model/effort selection (multi-model workflows, cost-tiering cheap/expensive models per task, reasoning-effort tiering) has lost that control with no warning that anything changed.
Context
Found this while building cc-arch-hands — an open-source installer that generates per-model/per-effort slash commands and sub-agents for Claude Code (e.g. /oh, /o1h, /sx in the repro below are its generated commands). The whole tool's value proposition depends on this override actually working, which is how the regression surfaced so clearly.
Repro — commands/*.md
~/.claude/commands/o1h.md:
---
model: claude-opus-4-8
effort: high
---
$ARGUMENTS
Invoke /o1h test in a session whose default model is claude-sonnet-5 (no /model switch in between). Repeated for a few variants in the same sitting:
| Command | frontmatter model: | frontmatter effort: | actual model used | actual effort used |
|---|---|---|---|---|
| /o1h | claude-opus-4-8 | high | claude-sonnet-5 | — |
| /oh | claude-opus-5 | high | claude-sonnet-5 | — |
| /sx | claude-sonnet-5 | xhigh | claude-sonnet-5 | high |
Repro — skills/SKILL.md
~/.claude/skills/cah-model-switch-test/SKILL.md:
---
name: cah-model-switch-test
description: diagnostic skill
model: claude-opus-4-8
effort: high
---
Reply with exactly this text and nothing else: "skill override test ok".
Invoked directly by the user typing /cah-model-switch-test (not via the assistant calling the Skill tool programmatically — i.e. the invocation path some other reports say should work). Same failure.
Evidence it's a real execution mismatch, not just a display bug
The session transcript (~/.claude/projects/<proj>/<session>.jsonl) records an attachment entry of type command_permissions at invocation time, capturing the requested override, e.g.:
{"type":"attachment","attachment":{"type":"command_permissions","allowedTools":[],"model":"claude-opus-4-8"},"timestamp":"2026-07-26T07:03:21.540Z","version":"2.1.220"}
But every subsequent assistant entry in that same turn (thinking, tool_use, text) — starting from the very first one — reports "message.model":"claude-sonnet-5". The API call itself ran on the session default, not the requested override. This isn't the status bar mislabeling something: the field that identifies which model actually produced the tokens says session-default, for the entire turn, both for commands/*.md and for skills/SKILL.md.
The same holds for effort:, tracked separately via the statusLine envelope's effort.level field: requested xhigh, observed high (the session default) for the full turn.
Before/after (this exact mechanism used to work)
In the same long-lived session, on v2.1.197 (2026-07-02), the identical command_permissions → subsequent-assistant-entries pattern correctly switched to claude-opus-4-8 for an entire multi-tool-call turn — several consecutive assistant entries all showed "model":"claude-opus-4-8" right after the override attachment. So this isn't "frontmatter override was never reliable" — it demonstrably worked, on this exact machine/session, 24 days ago.
Related reports (older, narrower, auto-closed by the stale-bot — not fixed)
- #63599 —
effort:ignored incommands/*.md(claimed skills honor it; that's no longer true either, see above) - #56819 —
model:frontmatter override inconsistent for slash commands (closed as dup of #45191) - #45191 — Skill frontmatter
model:field ignored at runtime - #79664 / #79661 / #79654 — Skill frontmatter
model:override ignored specifically when invoked via theSkilltool (works when user types/skill-name) — this report shows it now fails even for the user-typed path - #81313 — Skill frontmatter
effort:applied on slash-command invocation but ignored via theSkilltool
None of these were resolved — they were auto-closed for inactivity by the stale-bot, most are now locked, so I couldn't comment on them directly. I left detailed reproduction data (raw transcript excerpts) as comments on #63599 before opening this — linking here for anyone who wants the fuller trace: https://github.com/anthropics/claude-code/issues/63599#issuecomment-5082484411 and https://github.com/anthropics/claude-code/issues/63599#issuecomment-5082495834
Environment
- Claude Code v2.1.220 (regression window: v2.1.197 → v2.1.220)
- Windows 11
- Reproduced across
claude-opus-4-8,claude-opus-5,claude-sonnet-5as the target override
Ask
If you've hit this too — a 👍 on this issue (rather than a duplicate comment) helps signal how many people currently have zero working way to pin model/effort per command. Happy to attach fuller transcript excerpts or a minimal repro repo if useful.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Pinging folks from related reports in case this is useful context (or in case any of you are still hitting this) — several of your issues got locked after auto-close, so tagging you here since you can no longer comment on your own threads:
model:override inconsistent for slash commands, locked)model:ignored at runtime, locked)And from the still-open/commentable related reports:
effort:ignored incommands/*.md)model:override ignored via theSkilltool)effort:ignored via theSkilltool)model:frontmatter)If any of you have a still-reproducing case (especially on a recent version), a comment with your Claude Code version + a transcript excerpt would help build the picture of how far this regression window actually extends. And a 👍 on this issue is a low-effort way to signal "still affected" even without new repro details.
Independent corroboration on v2.1.220, plus a discriminator I haven't seen posted anywhere: the override works in print mode (
claude -p) and fails in the interactive TUI, on the same machine, same account, same binary, minutes apart.That narrows this from "the override is broken" to "the override is not applied on the interactive code path," which may be useful for whoever picks this up.
Probes (all v2.1.220, same session settings,
"model": "claude-opus-5[1m]"set insettings.json)Scratch commands, each a bare frontmatter pin over a trivial prompt:
| Invocation | frontmatter
model:| model that served the turn | pin ||---|---|---|---|
|
claude -p "/pin-fable"|fable|claude-fable-5| ✅ fired ||
claude -p "/pin-sonnet"|claude-sonnet-5|claude-sonnet-5| ✅ fired ||
claude -p "<plain prompt>"| — |claude-opus-5| n/a (correct default) ||
claude -p --resume <opus-session> "/pin-fable"|fable|claude-fable-5| ✅ fired, mid-session || interactive TUI, user-typed
/captain|fable|claude-opus-5| ❌ recorded, not applied |The resume case matters: it rules out "the override only binds at session creation." It flipped the model on an already-running Opus session — in print mode.
Scale of the interactive failure
Censused every
assistantentry on the main chain (.isSidechain != true) across 422 local transcripts in one project:| Command | frontmatter
model:| invocations | pin demonstrably fired ||---|---|---|---|
|
/captain|fable(alias) | 121 marked sessions | 1 ||
/handoff|claude-sonnet-5(full ID) | 220 | 0 |Combined ≈ 1 in 290 (~0.3%). Two details from that census:
claude-sonnet-5) has the worse record of the two. Thecommand_permissionsattachment shows the alias resolving correctly —"model":"claude-fable-5"— so resolution happens and is then discarded.Ruled out on this machine
claude-fable-5headless on demand the same day, and the Sonnet pin fails identically at 0/220 — so it isn't about one model tier being gated.settings.jsonmodel pin fighting the override."model": "claude-opus-5[1m]"was in force for all four passing headless probes.command_permissionsintact.Untested, offered as leads
Two hypotheses fit everything above and I can't separate them from client-side evidence: the model may be bound at prompt-submit before command frontmatter is parsed (a TUI-only ordering difference from the print path), or interactive session-model state may take precedence over a per-turn override in a way the print path doesn't implement.
On the regression framing
One wrinkle worth flagging rather than asserting: my own interactive failures extend back to 2026-07-20 through 07-24 on
claude-opus-4-8, before the v2.1.220 window. That doesn't contradict the before/after evidence in the original report — it may simply mean an interactive-path flakiness predates the regression and v2.1.220 made it total. Recording it in case the bisect comes back cleaner than expected.Practical note for anyone hitting this
There's no in-band signal — the model's own system prompt names the pinned model whether or not the pin fired, so an agent asked to "act as X" will believe it is X. The only reliable check is the transcript:
Setting the model at session level with
/modelworks and survives across turns; it's the only workaround I've found that holds.Follow-up to my earlier comment (the headless/interactive discriminator): we ran the controlled interactive negatives on v2.1.220. Same setup — a user-level command whose frontmatter pins
model:to a model different from the session's, macOS, Max plan. Three runs, three different conditions, zero fires:/modelpicker, then selected "Default (recommended)" (stdout:Set model to Opus 5 (1M context) (default)), then invoked the pinned command. First turn after the invocation and every main-chain turn thereafter served onclaude-opus-5; zero pinned-model turns. One caveat for anyone reproducing: selecting "Default" still sets a session model per the stdout, so the TUI may have no true no-selection state to test./modelactivity at all, no prior assistant turn. All 12 main-chain turns onclaude-opus-5, zero pinned-model turns./clear./clear, one ordinary turn, then the pinned command. (This mirrors the single interactive fire in our 422-transcript census, which occurred minutes after a/clear— we wondered if cleared context was the trigger. It isn't, or at least isn't sufficient.) All post-invocation turns onclaude-opus-5.In every run the transcript records the request faithfully — the
command_permissionsattachment carries the pinned model ID — and the API turn is served on the session model anyway. Headless-pon the same binary/machine/account applies the override correctly, including on--resume.Takeaway for the bisect: this argues against session-model-selection precedence as the mechanism — the override fails even under the account default and even on a session's first prompt, where no explicit selection exists to outrank it. It is consistent with the model being bound at prompt-submit before command frontmatter is applied on the interactive path. Sample sizes are small (one run per condition, against our measured interactive fire rate of ~1 in 290), so offered as narrowing evidence, not proof.