[BUG] Skill frontmatter model: override ignored when Claude invokes the skill via the Skill tool (works when user types /skill-name)

Status Open
Reported on v2.1.153
Maintainer reply None cached
Activity 4 comments · opened Jul 21, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

The SKILL.md frontmatter model: override is path-dependent: it works when the user types /skill-name, but is silently not applied when Claude invokes the same skill via the Skill tool mid-turn — even though the harness registers the override on both paths (toolUseResult.model and a command_permissions attachment both carry the resolved model ID).

This narrows #45191: the field is parsed and resolved everywhere, applied only on the user-typed path. Since model-triggered invocation is the default path for model-invocable skills, cost-control uses of model: silently fail most of the time.

Reproduced identically on 2.1.153 (CLI, Windows 11) and 2.1.215 (desktop app). Full annotated transcript evidence in first comment below.

What Should Happen?

Per the frontmatter reference (https://code.claude.com/docs/en/skills#frontmatter-reference): "Model to use when this skill is active. The override applies for the rest of the current turn" — regardless of whether the skill was invoked by the user or by Claude via the Skill tool.

Error Messages/Logs

Steps to Reproduce

  1. Create a probe skill at ~/.claude/skills/which-model/SKILL.md (no context: fork):

---
name: which-model
description: Diagnostic probe — report which model is actually sampling right now.
model: opus
---

  1. Set the session to a non-Opus model (tested with claude-fable-5).
  2. Ask Claude in prose to invoke the skill — it fires Skill(which-model) mid-turn.
  3. In a later turn, type /which-model yourself.
  4. Read ground truth from message.model on assistant entries in the session transcript (~/.claude/projects/<proj>/<session>.jsonl) — this field comes from the API response.

Result: step 3 keeps sampling on the session model (override ignored); step 4 switches to claude-opus-4-8 for the rest of the turn (override honored, reverts next prompt as documented).

Control: context: fork + model: is honored on BOTH invocation paths — so parsing and model resolution are fine; the gap is the inline mid-turn application.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.153 (Claude Code) — reproduced identically on 2.1.215 (desktop app)

Platform

Other

Operating System

Windows

Terminal/Shell

VS Code integrated terminal

Additional Information

follow up info here

View original on GitHub ↗

3 Comments

klkr-dev · 1 month ago

Full evidence promised in the report. Ground truth throughout = message.model on assistant entries in the session transcript .jsonl — this field comes from the API response and demonstrably flips per-message (see the fork control at the end), so it's trustworthy.

1. Both paths in one session (2.1.215, desktop app) — annotated transcript

L25 assistant model=claude-fable-5   <-- Claude invokes Skill(which-model); skill content loads
L29 assistant model=claude-fable-5       (all post-load sampling stays on session model)
L31 assistant model=claude-fable-5
L34 assistant model=claude-fable-5
L37 assistant model=claude-fable-5       "override did NOT take effect"
L41 user                             <-- user types /which-model
L46 assistant model=claude-opus-4-8      (override applied immediately)
L48 assistant model=claude-opus-4-8
L49 assistant model=claude-opus-4-8      "override TOOK EFFECT this time"
L53 user                             <-- next user prompt
L54 assistant model=claude-fable-5       (session model resumes, as documented)

2. The override registers even on the failing path (2.1.153) — raw transcript lines

Skill invoked via the Skill tool; the harness resolves model: opusclaude-opus-4-8 in two places:

"toolUseResult":{"success":true,"commandName":"land-branch","model":"claude-opus-4-8"}
"attachment":{"type":"command_permissions","allowedTools":[],"model":"claude-opus-4-8"}

…yet every subsequent assistant entry in the same turn keeps the session model:

L184 assistant model=claude-fable-5  (03:32:41 — after the skill + override registered at 03:32:32)
L185 assistant model=claude-fable-5
L186 assistant model=claude-fable-5
L188 assistant model=claude-fable-5
L189 assistant model=claude-fable-5

So the gap is specifically the inline mid-turn application of an already-registered override — not frontmatter parsing or model-name resolution.

3. Fork control — proves the measurement method

A skill with context: fork + model: haiku, invoked via the Skill tool from an Opus session, produced a subagent transcript (~/.claude/projects/<proj>/subagents/agent-*.jsonl) whose assistant entries are all claude-haiku-4-5-20251001 (5/5). Same harness, same transcript field, override honored — confirming message.model reflects real sampling.

Adjacent observation

The system prompt's "You are powered by the model named …" line is frozen at session start — after /model switches or a successful skill override it keeps claiming the original model (observed claiming Fable while Opus served, and vice versa). Harmless for sampling, but it makes the model's self-report useless for verifying any of this; transcript message.model is the only reliable signal. Happy to split into its own issue if preferred.

Environment detail

  • Session models involved: claude-fable-5[1m], claude-opus-4-8[1m], Anthropic API (the Platform dropdown above should read "Anthropic API")
  • Related: #45191 (closed/locked — this narrows it), #17283 (Skill tool + context: fork — works on the versions above)
  • Supersedes #79654 / #79661 (earlier CLI-filed duplicates of this report, both closed)
KLuuKer · 1 month ago

i am the human that told it to post this.
i have manually open the session log in notepad
manually analyzed it like a caveman back in the punch card days.
and can confirm this issue is real and correct.... yes i also read the whole issue

PHPCraftdream · 1 month ago

Can confirm the underlying mechanism has regressed further since this was filed — as of v2.1.220, model: override now fails even for the invocation path this issue says should work (direct, user-typed /skill-name), not just via the Skill tool. Tested with a minimal throwaway skill (model: claude-opus-4-8), invoked by typing the slash command myself: the command_permissions attachment in the transcript correctly recorded the requested override, but every subsequent assistant entry in that turn still ran on the session's default model.

Filed a broader follow-up covering this (both commands/*.md and skills/SKILL.md, both invocation paths, with full transcript evidence and a working-vs-broken version comparison): #81318. Linking here since it directly extends this report's premise. If you've hit this too, a 👍 there helps signal impact.

Showing cached comments. Read the full discussion on GitHub ↗