Subagent `model:` frontmatter pin silently ignored in 2.1.117
Bug: subagent model: frontmatter pin silently ignored in 2.1.117
Claude Code version: 2.1.117 (installed at /home/gawkahn/.local/share/claude/versions/2.1.117)
Platform: Linux 6.17.0-22-generic, Ubuntu 24.04, bash shell.
Summary
Subagents defined under ~/.claude/agents/<name>.md with a frontmatter model: field have the pin silently ignored. The API is called with a different model than the pin specifies. No warning, no log, no indication to the user that the pin was not honored.
Expected behavior
Per documented resolution order:
CLAUDE_CODE_SUBAGENT_MODELenv var- Agent tool invocation-time
modelparameter - Agent file frontmatter
model:field - Parent session's model (fallback)
When (1) and (2) are both absent, (3) should take effect. In this case the subagent should run on the pinned model.
Actual behavior
(3) is skipped. The subagent runs on what appears to be the harness default model, not the pinned one.
Reproduction
- Create
~/.claude/agents/security-auditor.mdwith frontmatter:
---
name: security-auditor
description: Scans for security vulnerabilities ...
model: claude-opus-4-7
tools:
- Read
- Grep
- Glob
---
- Confirm no override is in play:
echo "CLAUDE_CODE_SUBAGENT_MODEL=${CLAUDE_CODE_SUBAGENT_MODEL:-<unset>}"
# expect: <unset>
- From within a Claude Code session running on Opus (verified via "You are powered by the model named Opus 4.7" in the session prompt), invoke the subagent via the Agent tool with
subagent_type: "security-auditor"and nomodelparameter.
- After the subagent completes, inspect its transcript:
python3 -c "
import json, sys
with open(sys.argv[1]) as f:
models = {json.loads(l).get('message',{}).get('model')
for l in f if json.loads(l).get('type')=='assistant'}
print(models - {None})
" ~/.claude/projects/<PROJECT_DIR>/<SESSION_ID>/subagents/agent-<AGENT_ID>.jsonl
Evidence
Four subagent transcripts in one session, all with the Opus pin in their agent file, zero env/settings overrides:
| Agent ID | subagent_type | Frontmatter pin | message.model in transcript |
|---|---|---|---|
| a5e106c68515661df | security-auditor | claude-opus-4-7 | claude-sonnet-4-6 |
| afbc0a26e4c44a045 | security-auditor | claude-opus-4-7 | claude-sonnet-4-6 |
| acf1ac78322c311cb | security-auditor | claude-opus-4-7 | claude-sonnet-4-6 |
| a6f34494ab8ddc709 | claude-code-guide | (no pin) | claude-haiku-4-5-20251001 |
All four reviewer agents in this user's ~/.claude/agents/ (code-reviewer, security-auditor, planner, explorer) have identical model: claude-opus-4-7 frontmatter; none of them is honored when invoked without the tool-level model parameter.
Confirmed workaround
Passing the model parameter to the Agent tool at invocation time does work — transcripts of invocations with explicit model: "opus" show claude-opus-4-7 in the message.model field. The invocation-time override is a viable path forward; the frontmatter path is not.
Impact
For teams or individuals who rely on per-agent model pinning for compliance reasons (e.g. "Red Zone security reviews must run on the strongest available model"), the frontmatter pin is a silent failure. Users may believe they are operating under a stricter review standard than they actually are, with no signal from the tool.
Suggested fix
Honor the frontmatter model: field in the documented resolution order. If the field is invalid or unreachable, surface a warning at subagent-spawn time rather than silently falling back.
Additional notes
- The subagent's own self-identification in its output is not a reliable indicator — the running model often mis-reports its own version based on its system prompt contents. The
message.modelfield in the transcript.jsonlis ground truth. - The agent's system prompt (visible when asking the agent to quote its environment block) includes
"You are powered by the model named Sonnet 4.6. The exact model ID is claude-sonnet-4-6."— so the system prompt the harness generates matches the actually-called model, suggesting the harness resolves the model correctly for the system prompt but uses the same (wrong) model for the API call. The frontmatter is essentially being ignored end-to-end.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗