Workflow verify stage fans out 20x past size guideline with no confirmation or cost preview

Status Open
Reported on v2.1.246
Maintainer reply None cached
Activity 0 comments · opened Aug 26, 2026

Summary

A Claude-authored Workflow script (fleet-sweep) with a per-finding adversarial verify stage launched 355 Opus 5 agents in one run (724 Opus launches across the original run and two resumes) in a session whose workflow size guideline was the default "medium — keep workflows under 15 agents". Nothing at the Workflow tool or runtime layer previewed the projected fan-out, asked for confirmation, or capped it. The first launch ran straight into the 5-hour session limit: 278 verifiers died at 15:02–15:03Z with You've hit your session limit.

The fan-out factor (one Opus verifier per finding) was chosen by the tool-authored script, not by the user's prompt. The count was knowable before the stage launched (fs.length is computed before parallel() is called), so a runtime gate is feasible.

Repro

  1. Claude Code 2.1.246, session model claude-fable-5[1m], default workflow size guideline (medium, ~15 agents).
  2. Ask: "sweep 4 repos for silenced errors, mocked features, checks that prove nothing, chores and git-history flip-flops; adversarially verify each finding".
  3. Claude authors and launches a script of this shape (abridged):
const targets = [] // 4 repos × 4 lenses = 16
const results = await pipeline(
  targets,
  t => agent(findPrompt(t), { phase: 'Find', schema: FIND_SCHEMA }),
  async (found, t) => {
    const fs = found.findings.filter(f => !f.justified)      // count known here
    const verified = await parallel(fs.map(f => () =>
      agent(refutePrompt(f), { phase: 'Verify', model: 'opus', schema: VERDICT })))
    return verified.filter(x => x?.verdict && !x.verdict.refuted)
  })
  1. Find returns ~355 unjustified findings → Verify stage launches 355 Opus agents.

Expected

  • When a stage's projected agent count exceeds the session's workflow size guideline (here 15), pause and confirm — or cap — showing the projected count and model. The guideline (workflowSizeGuideline / the /config "Dynamic workflow size" choice) is currently only prose injected into the model's system prompt; the runtime enforces only the concurrency cap (min(16, CPUs−2) = 14 here) and the 1000-agent backstop, neither of which bounds total spend.
  • A projected usage preview (agents × model) before a fan-out stage launches. The one-time usage warning at tool approval cannot carry this information because the count is computed at runtime.
  • On session-limit exhaustion mid-fan-out, stop launching further agents and surface the reason (the 278 deaths are recorded only as {"type":"failed"} in journal.jsonl, cf. #89709).

Actual

  • The Workflow permission dialog at launch (open ~4 min, 14:36→14:40Z) showed only the script's one-line meta.description. No count or usage projection at any point.
  • Verify stage fanned out to 355 Opus agents (~24× the guideline) with no prompt. Two workflows were launched back-to-back from the same session; the other one (wave0-build, 91 agents: 53 Opus + 38 Sonnet) was also running.
  • First launch hit the session limit mid-fan-out: 278 verifiers got a synthetic You've hit your session limit · resets 3:40pm (UTC) message (0 tokens each). The workflow then died with the Claude process; two resumes (resumeFromRunId) were needed to complete.
  • skipWorkflowUsageWarning: true was present in ~/.claude/settings.json (since at least 2026-08-20 — before the first Workflow call in any surviving transcript; undocumented and agent-writable per #78019). The only code path that writes it is the consent-dialog acceptance, but no record of that acceptance survives and the operator does not recall it. It also disables the advisory ≥25-agent / ≥1.5M-token size warning (CLAUDE_CODE_WORKFLOW_SIZE_WARNING_AGENTS/_TOKENS); that warning is per-workflow, not per-stage, and would not have carried the projected verify count anyway.
  • The built-in claude-code-guide agent, asked about this exact settings file on 2026-08-26 16:50Z (Claude Code 2.1.246), answered: "skipWorkflowUsageWarning is not a valid settings key — the warning appears when a run schedules >25 agents or projects >1.5M tokens; there's no setting to suppress it." The binary contains the key (Failed to persist skipWorkflowUsageWarning) and it does suppress the dialog. The user therefore had no way to learn from the product's own documentation or guide that this flag was disabling a spend guardrail.

Numbers (from the on-disk run record and agent transcripts, not estimates)

| | |
|---|---|
| Run record | wf_d7468eb7-bec, status: completed, agentCount: 371, durationMs: 2371298 (39.5 min) — final launch 16:02:48→16:42:19Z |
| Final run agents | Find: 16 × claude-fable-5 (all replayed from cache); Verify: 311 live × claude-opus-5[1m] + 44 cached |
| Agents across all 3 launches | 740 agent-*.jsonl: 16 Fable finders + 724 Opus verifiers (278 died on the session limit with 0 tokens) |
| Tokens — Opus verifiers | 3,114 assistant messages · 6.2k input · 14.96M cache-write · 125.2M cache-read · 407k output |
| Tokens — Fable finders | 302 assistant messages · 96k input · 9.71M cache-write · 43.4M cache-read · 251k output |
| Tokens — total | 102k input · 24.7M cache-write · 168.6M cache-read · 659k output |
| Wall clock incl. limit outage | 14:36Z launch → 16:42Z complete; result: 186 confirmed findings |

Token figures are summed from message.usage in the agent transcripts, deduplicated per message.id.

Environment

  • Claude Code 2.1.246 (native install), auto mode, subscription plan (session-limit gated, not API key)
  • NixOS on WSL2 — Linux 6.18.33.2-microsoft-standard-WSL2 x86_64
  • Session model claude-fable-5[1m]; verify stage model: 'opus' resolved to claude-opus-5[1m]
  • Workflow size guideline: default medium (not overridden in /config)

Related

#66023, #67343, #83025 — same failure mode at 46/70/82 agents; this report is the same defect at 355. #78019 — skipWorkflowUsageWarning agent-writable and undocumented (the guide agent denies it exists, see above). #89709 — failed agents carry no cause.

View original on GitHub ↗