[BUG] Resumed background subagent/teammate loses its spawn-time model override and reverts to parent model
Preflight Checklist
- [x] I have searched existing issues. The closest is #20291 (
/agentsshows "sonnet" for inherit-model subagents) — closed and distinct: that is about the static/agentsdisplay for inherited models. This report is about a runtime model regression on resume of a background subagent/teammate. - [x] This is a single bug report.
- [x] I am using the latest version of Claude Code.
What's Wrong?
When a background subagent (an addressable "teammate" spawned via the Agent/Task tool with run_in_background) is given a spawn-time model override, that override is applied correctly on the first run but is silently dropped when the agent is resumed via SendMessage (resume-by-agentId). On resume, the agent falls back to the parent / main-conversation model instead of the model it was originally spawned with.
Concretely, with the main conversation on Opus 4.8:
| Phase | Requested model | Actual model |
|------|------------------|--------------|
| Initial Agent(subagent_type: "general-purpose", model: "sonnet") | sonnet | sonnet ✅ |
| Resume of that same agent via SendMessage (no model param) | (should stay sonnet) | opus (parent) ❌ |
The per-invocation model override only governs the initial spawn; resumed turns re-resolve the model and, for an agent type without a model: in its .claude/agents/<name>.md frontmatter, drop all the way through to the parent model. This is surprising for long-lived teammates that are meant to be resumed repeatedly — a teammate you deliberately pinned to a cheaper/faster model can silently start running on the parent (more expensive) model after the first turn, with no indication in the UI.
What Should Happen?
A resumed background agent should retain the model it was spawned with. The spawn-time model override should persist across SendMessage resumes for the lifetime of that agentId (or, at minimum, the UI/telemetry should clearly show the resumed model so the change is visible and billable cost is predictable).
Workaround (and the asymmetry that confirms it)
Pinning the model in the agent definition frontmatter instead of the spawn-time param works correctly across resumes:
general-purpose(no frontmattermodel:) + spawn-timemodel: "sonnet"→ reverts to parent (opus) on resume.- A custom agent type with
model: sonnetin.claude/agents/<name>.md→ stays sonnet across resumes ✅.
So the durable fix for users is frontmatter; the bug is that the per-invocation override is not durable across resume, which the model-resolution docs (CLAUDE_CODE_SUBAGENT_MODEL env > per-invocation param > frontmatter > main conversation) do not lead you to expect for a persistent teammate.
Steps to Reproduce
- Start Claude Code with the main model = Opus.
- Spawn a background general-purpose teammate with an explicit Sonnet override:
````
Spawn a background general-purpose agent with model "sonnet" and ask it which model it is running.
→ it correctly reports Sonnet.
- Resume that same agent via SendMessage (by its
agentId), e.g. "say hi again and report your model". - Observe the resumed turn now runs on the parent model (Opus), not the Sonnet it was spawned with.
- For contrast, repeat with an agent type that has
model: sonnetin its.claude/agents/*.mdfrontmatter → it stays Sonnet across resumes.
Error Messages/Logs
# No error — model silently changes between the initial spawn and the resumed turn.
# Initial spawn (model: "sonnet") -> runs sonnet
# SendMessage resume (no model param) -> runs parent model (opus)
Claude Model
Opus (main conversation); teammate spawned with model: "sonnet"
Is this a regression?
I don't know
Claude Code Version
2.1.175 (Claude Code)
Platform
Anthropic API
Operating System
Linux
Additional Information
Related (closed, different surface): #20291. That issue is about the static /agents display for inherited models; this is about the runtime model not persisting across SendMessage resume of a backgrounded, addressable teammate spawned with a per-invocation model override.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗