[BUG] Subagent 'Warmup' drains 99%+ of subscription input tokens (regression since 2026-04-09; ref #17457 closed NOT_PLANNED)
Preflight Checklist
- [x] I have searched existing open issues — none tracking this. Closely related: #17457 (closed
NOT_PLANNEDon 2026-02-28), #16752, #16961, #25138 — all closed. Reopening the topic because the behaviour re-surfaced / intensified after 2026-04-09. - [x] Single bug report.
- [x] Using latest —
claude --version: 2.1.107.
What's Wrong?
Subagent Warmup is draining subscription tokens on a massive scale. Every registered subagent is spawned at session start with the hard-coded user prompt "Warmup" and pays a full cold-cache input cost (no prompt-cache reuse between sessions). On a machine with plugins that register several agents, this alone consumes 99 %+ of the input tokens billed against the weekly subscription limit.
First "Warmup" message across 27,038 transcripts in ~/.claude/projects/ on my host: 2026-04-09 17:12 UTC. Before that date — zero Warmups, ever. Some behaviour change landed on/around 2026-04-09 that turned the feature back on or raised its intensity, post-dating the NOT_PLANNED closure of #17457.
What Should Happen?
Either of:
- The Warmup turn is prompt-cached across session starts (cache-creation only once per agent-manifest change), or
- Warmup is opt-in per-agent via a manifest key like
warmup: false, or - A granular env var like
CLAUDE_CODE_DISABLE_AGENT_WARMUP=1is provided that does not also disable Ctrl+B,run_in_background: true, and auto-backgrounding (as the currentCLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1does).
In any case: document Warmup in the changelog and in Manage costs effectively so users can correlate sudden token-usage spikes with the feature.
Evidence / Impact
Walked every JSONL under ~/.claude/projects/, deduped on message.id + model + requestId (same key ccusage uses, because Claude Code replays the same assistant turn into every transcript that forks/resumes/compacts from the originating session — up to 30× in my case, inflating naive totals 2–3×). Totals cross-validated against ccusage daily.
Script: mann1x/claude-hooks · scripts/weekly_token_usage.py (stdlib only, no deps).
Per-day split (Fri 2026-04-10 10:00 CEST → Tue 2026-04-14):
| Day | Main input | Sidechain input | Sidechain share |
|---|---:|---:|---:|
| Fri | 2 760 | 7 370 | 72.8 % |
| Sat | 3 795 | 433 308 | 99.1 % |
| Sun | 5 069 | 346 188 | 98.6 % |
| Mon | 4 405 | 600 005 | 99.3 % |
| Tue | 4 493 | 1 304 529 | 99.7 % |
Tuesday breakdown (the worst day):
- 1 143 sidechain user messages carried the literal text
"Warmup". - Only 4 sidechain messages carried a real task prompt.
- ≈ 99 % of the 1.3 M sidechain input tokens were the Warmup spawns, not user work.
Main conversation used only 2–5 k input tokens per day thanks to prompt caching. Warmups pay cache-creation costs every single session start because each agent's context is new.
Dedup validation (anticipating the obvious question)
The per-day totals grow monotonically from Fri → Tue, which could in principle hide a dedup bug. It was checked three ways:
1. Composite key equals single-field key. Dedup key is message.id + model + requestId. Across the whole week's sidechain entries, using message.id alone produces the same deduped count (4 757). No silent collisions — message.id is already unique per API call.
2. Raw-to-deduped ratio is consistent at ~2×. Without dedup the week has 9 338 sidechain assistant entries; with dedup 4 757 (ratio 1.96×). Matches the expected replay pattern — each sidechain turn is written into both the originating transcript and the forked-session transcript it spawns, so most messages appear exactly twice.
3. Growth tracks session count, not a dedup artefact.
| Day | Sidechain sessions | Unique agentIds | Deduped warmup msgs | Deduped input |
|---|---:|---:|---:|---:|
| Fri | 1 | 3 | 95 | 7 370 |
| Sat | 141 | 396 | 567 | 433 308 |
| Sun | 153 | 456 | 696 | 346 188 |
| Mon | 224 | 661 | 1 189 | 600 005 |
| Tue | 390 | 1 148 | 2 210 | 1 304 529 |
Fri has only 1 sidechain session because Warmup had just rolled out (first global Warmup: 2026-04-09 17:12 UTC) and the Fri-10:00-CEST weekly window excludes the handful of Thu-evening Warmups that preceded it. Sessions per day grew Fri → Tue from 1 → 390; warmups-per-session stayed constant at 2–3 (≈ one per registered agent). The 1.3 M Tue figure decomposes cleanly as 390 sessions × ~3 agents warmed × ~1–8 k fresh input tokens each.
4. ccusage cross-check. ccusage daily -z Europe/Berlin --since 20260410 reports the same per-day totals within the CET↔CEST window delta — e.g. this script reports 446 100 541 total Tuesday tokens; ccusage reports 446 712 100 (delta ≈ 0.14 %, attributable to ccusage grouping by full calendar day while this script uses the Fri-10:00-CEST reset-shifted day).
Error Messages/Logs
No error — tokens drain silently. The Warmup entries look like this in the transcript JSONL (~/.claude/projects/<project>/<session>.jsonl):
# user side (sidechain opener)
{"type":"user","isSidechain":true,"agentId":"a72e8af","message":{"role":"user","content":[{"type":"text","text":"Warmup"}]},"timestamp":"2026-04-14T12:44:04.879Z"}
# assistant side (the costly call)
{"type":"assistant","isSidechain":true,"message":{"model":"claude-opus-4-5-20251101","usage":{"input_tokens":8082,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":2}},"timestamp":"2026-04-14T12:44:05.112Z"}
Note the zero cache_read_input_tokens — no cache hits between sessions.
Steps to Reproduce
- Install a plugin that registers several subagents (e.g.
code-analysis@mag-claude-pluginsregisters 13 detective agents) — or simply rely on the ~6 built-in agents (general-purpose,Explore,Plan,claude-code-guide,statusline-setup, user-defineddetective). - Start a few fresh
claudesessions in a row. grep -c '"Warmup"' ~/.claude/projects/*/*.jsonl— count Warmup prompts.- Optional quantitative run:
``bash``
# repro script
git clone https://github.com/mann1x/claude-hooks
python3 claude-hooks/scripts/weekly_token_usage.py --show-sidechain
# Expect: Sub%Inp column reads 95–99 % on any day with agents loaded.
- Apply the only documented mitigation —
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1in~/.claude/settings.jsonunderenv— and re-run the script.Sub%Inpdrops to single digits.
Current (unsatisfactory) workaround
Set in ~/.claude/settings.json:
"env": { "CLAUDE_CODE_DISABLE_BACKGROUND_TASKS": "1" }
Per the official Interactive mode docs, this "disables all background task functionality" — all-or-nothing:
- ❌ Ctrl+B shortcut (TUI backgrounding)
- ❌ Bash tool's
run_in_background: trueparameter - ❌ Auto-backgrounding of long Bash tools
- ❌ (per #17457) subagent Warmup
There is no per-feature toggle. Users who rely on backgrounded Bash have to choose between token savings and ergonomics.
CLAUDE_AGENT_SDK_DISABLE_BUILTIN_AGENTS=1 only applies in -p non-interactive mode — in the interactive TUI the 5-6 built-in agents still warm regardless.
Scope of the ask
- Acknowledge Warmup in a changelog entry and in Manage costs effectively.
- Provide a granular disable (per-agent manifest key or dedicated env var) that does not also kill Ctrl+B /
run_in_background. - Cache Warmup across consecutive session starts so the cost is paid only on first use after an agent-manifest change — a pure performance fix that benefits every user.
- Make the "X % of weekly limit" reported in the UI queryable programmatically (CLI flag or local file), so users can audit the effect of any Warmup-related change.
Permission Mode
n/a (happens at session boot, before any permission prompt)
Can You Reproduce This?
Yes, every fresh claude session fires Warmups deterministically.
Claude Model
All — Warmup spawns whatever model the registered agent specifies (Opus 4.5, Sonnet, Haiku observed on my host).
Claude Code Version
2.1.107 (latest at time of filing). First Warmup observed on my host: 2026-04-09 17:12 UTC (version ≥ 2.0.77).
Platform
Claude Code CLI on Linux (Debian 11). Also reproduced on Windows 11 (same CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 workaround works there).
Impact
High. For a subscription user the weekly token budget is opaque and the UI reports only a percentage. Because 99 % of my daily input tokens are Warmups — not real work — a single day of heavy session starts with plugins loaded can consume the weekly allowance before noon. See the Tuesday row of the evidence table: 1.3 M sidechain input tokens, 4 of which were real work.
Additional Context
Comment cross-posted earlier on #42796 (off-topic there, belongs here). Earlier related closures:
- #17457 —
NOT_PLANNED2026-02-28 — "Multiple duplicate warmup agents spawning causes idle token consumption". Almost the same bug; closed without fix; behaviour has since intensified. - #16752 —
"Agent warmup mode causes infinite retry loop with high API traffic"— closed. - #16961 —
"Tool results echo task name 'Warmup' instead of executing, agent loops 1700+ times"— closed. - #25138 —
claude --agent --printhang on cold start — closed.
Filing separately to make the current state and quantified impact visible, in the hope that the NOT_PLANNED decision can be revisited given the new data.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗