[BUG] Resumed background subagent/teammate loses its spawn-time model override and reverts to parent model

Status Fixed / completed
Reported on v2.1.175
Maintainer reply ✓ Yes — bcherny
Activity 4 comments · opened Jun 12, 2026 · closed Aug 19, 2026
💡 Likely answer: A maintainer (bcherny, collaborator) responded on this thread — see the highlighted reply below.

Preflight Checklist

  • [x] I have searched existing issues. The closest is #20291 (/agents shows "sonnet" for inherit-model subagents) — closed and distinct: that is about the static /agents display 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 frontmatter model:) + spawn-time model: "sonnet" → reverts to parent (opus) on resume.
  • A custom agent type with model: sonnet in .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

  1. Start Claude Code with the main model = Opus.
  2. 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.

  1. Resume that same agent via SendMessage (by its agentId), e.g. "say hi again and report your model".
  2. Observe the resumed turn now runs on the parent model (Opus), not the Sonnet it was spawned with.
  3. For contrast, repeat with an agent type that has model: sonnet in its .claude/agents/*.md frontmatter → 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.

View original on GitHub ↗

3 Comments

kokodas07 · 3 months ago

Reproduced on 2.1.198 (linux).

Repro:

  1. Spawned a background subagent via the Agent tool with an explicit model: haiku override

→ first turn ran claude-haiku-4-5-20251001 (per-turn usage in the task output JSONL).

  1. After it completed, resumed it with SendMessage (same session, ~20s later, well within cache TTL)

→ the resumed turn ran on the parent session model instead of the spawn-time override.

Usage data (from the subagent transcript JSONL):

| turn | model | cache_creation | cache_read |
|---|---|---|---|
| spawn | claude-haiku-4-5-20251001 | 20,417 | 0 |
| resume (SendMessage) | parent session model | 21,917 | 0 |

Cost side effect worth flagging: the silent model switch also invalidates the prompt cache
(different model = different cache), so the resumed turn re-creates the entire transcript as
cache_creation at the 1.25x write rate — billed at the parent-tier model price. A control run
with no model override (spawn and resume on the same model) reads cache fine on resume
(cache_read = 18,663), confirming the cache loss is a consequence of the model regression,
not a separate caching bug.

ucbmckee · 3 months ago

Reproduced independently (Claude Code 2.1.207, Windows 11, VS Code extension), with a controlled A/B that isolates a variable none of the reports above control for: runtime model: param vs. a custom agent-definition's frontmatter pin.

Setup: orchestrator session model = Sonnet. Spawned two async subagents pinned to Haiku, resumed each via SendMessage after completion.

| Path | Turn 1 | Turn 2 (post-resume) |
|---|---|---|
| subagent_type: general-purpose, model: "haiku" param | claude-haiku-4-5 | claude-sonnet-5 (flipped to orchestrator's model) |
| subagent_type: <custom>.md, model: haiku in frontmatter | claude-haiku-4-5 | claude-haiku-4-5 (held) |

Same defect as above, but the frontmatter-pinned custom agent type was immune in this test — the bug appears specific to the runtime model: param's resolution on resume, not the static agent-definition path.

Real-world cost impact (separate live session): a general-purpose subagent spawned with model: "sonnet" under a Fable-tier orchestrator ran correctly for 91 messages, then one mid-task follow-up flipped it to Fable for the remaining 51 and it never reverted — ~186M input/cache tokens and ~252K output tokens billed at Fable-tier pricing that should have been Sonnet.

Workaround for others hitting this: until fixed, prefer a custom .claude/agents/<name>.md with model: frontmatter over the runtime model: param for any subagent that might receive a follow-up or get resumed — the frontmatter path held in testing where the param path did not.

bcherny collaborator · 1 month ago

Fixed in 2.1.211 — changelog: "Fixed subagents spawned with an explicit model override reverting to the parent's model when resumed or sent a follow-up message" (https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md). Closing — reply to reopen if it still happens on the latest version.

🤖 Generated with Claude Code

Showing cached comments. Read the full discussion on GitHub ↗