Skip to content

Commit ebb0307

Browse files
ytrofrclaude
andcommitted
docs(guides): add dynamic workflows cost-management guide
Covers the per-agent context-inheritance cost driver, measuring spend via /usage + OTEL query_source split, ranked capping levers (per-phase model pinning, fewer agents, effort, in-script budget.spent() guard, /usage-credits), the +Nk-not-wired-in-2.1.158 caveat, and the cumulative/series-aware metrics gotcha. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent d62f093 commit ebb0307

1 file changed

Lines changed: 109 additions & 0 deletions

File tree

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Dynamic Workflows -- Understanding and Capping Token Cost
2+
3+
**Created**: June 2026
4+
**Source**: Production session -- real OTEL measurements
5+
**Evidence**: 3 one-word subagents measured at 393,005 tokens (99.99% cacheCreation); model-pinning cut per-agent cost multiple-fold
6+
**Time to Implement**: 20-30 minutes
7+
**Difficulty**: Intermediate
8+
**Applies to**: Claude Code 2.1.154+ (dynamic workflows shipped 2.1.154)
9+
10+
---
11+
12+
## Overview
13+
14+
Dynamic workflows (Claude Code 2.1.154+) let Claude orchestrate work across tens to hundreds of subagents in the background. They're powerful -- and they can consume **dramatically** more tokens than a normal session. Anthropic's own guidance: *"dynamic workflows consume meaningfully more usage than a typical Claude Code session."*
15+
16+
This guide explains **why** they're expensive, how to **measure** the spend precisely, and the levers that actually **cap** it. Every number here is a real measurement.
17+
18+
**Golden rule**: the cost is dominated by *per-agent context inheritance*, not by the work the agents do. Optimize for that and everything else follows.
19+
20+
---
21+
22+
## Why workflows are expensive: the context-inheritance tax
23+
24+
Every subagent a workflow spawns is a fresh context. It inherits your system prompt, your `CLAUDE.md`, your rules, and your tool schemas -- and **writes all of that into the prompt cache** on its first turn (`cacheCreation` tokens).
25+
26+
A measured example: a workflow with **3 subagents that each replied with a single word** consumed **393,005 tokens** -- and **~99.99% of it was `cacheCreation`**, not the actual output (which was ~16 tokens total). Three agents = three full context-writes.
27+
28+
The implication is blunt:
29+
30+
- **Fan-out is the cost.** 8 agents ≈ 8× the context-write tax, regardless of how trivial each task is.
31+
- A large always-on rule/`CLAUDE.md` stack multiplies this -- each agent pays for it.
32+
- The model each agent runs on multiplies it again (see levers below).
33+
34+
---
35+
36+
## Measuring workflow spend (so you can prove a change worked)
37+
38+
### Built-in: `/usage`
39+
40+
On Pro/Max/Team/Enterprise plans, `/usage` breaks down recent usage and **attributes it to skills, subagents, plugins, and MCP servers** as a percentage of total. This is the zero-setup way to see "how much went to subagents."
41+
42+
### Precise: OpenTelemetry metrics
43+
44+
Claude Code exports two counters you can capture with any OTLP backend:
45+
46+
- `claude_code.token.usage` (unit: tokens)
47+
- `claude_code.cost.usage` (unit: USD)
48+
49+
Both carry attributes that let you split workflow spend from main-loop spend:
50+
51+
| Attribute | Values | Use |
52+
|---|---|---|
53+
| `query_source` | `main` / `subagent` / `auxiliary` | **Workflow agents report as `subagent`** -- this is the key split |
54+
| `type` | `input` / `output` / `cacheRead` / `cacheCreation` | Confirms the cacheCreation tax |
55+
| `model` | e.g. `claude-haiku-4-5` | Proves which model an agent actually ran on |
56+
| `agent.name`, `skill.name`, `effort` | -- | Finer attribution |
57+
58+
Enable export:
59+
60+
```bash
61+
# in ~/.claude/settings.json env, or your shell
62+
CLAUDE_CODE_ENABLE_TELEMETRY=1
63+
OTEL_METRICS_EXPORTER=otlp # default is often "none" -- token metrics need this ON
64+
OTEL_EXPORTER_OTLP_PROTOCOL=http/json
65+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
66+
```
67+
68+
Telemetry env is read at **startup** -- restart Claude Code after changing it. Point the endpoint at any OTLP-compatible collector (Prometheus, the OTel Collector, or a small local receiver). Then sum `token.usage{type=output, query_source=subagent}` to see exactly what your workflows cost.
69+
70+
> **Two gotchas if you build your own metrics consumer.** (1) Claude Code sends token counts as OTLP `asDouble` (floats like `11414.0`), not `asInt` -- format accordingly. (2) These are **cumulative** counters: each subagent run is a *distinct* time series that can collide on the same attribute set. Discriminate series by `startTimeUnixNano` -- take the **max within a series** (collapses 60-second re-reports) but **sum across distinct series** (sums separate runs). Aggregating with a naive "max per attribute key" silently *undercounts* multi-run subagent totals.
71+
72+
---
73+
74+
## The levers that cap cost (ranked by impact)
75+
76+
1. **Pin cheap models per phase (biggest lever).** Workflow agents inherit your **session model by default** -- which is often the most expensive one. In your workflow script, set the model per phase: a fast/cheap model (Haiku/Sonnet) for mechanical phases (grep, read, audit) and the premium model only for the final synthesis. Measured: the same trivial agents ran multiple-fold cheaper on Haiku than on the default premium model.
77+
78+
2. **Fewer, leaner agents.** The context-write tax is *per agent*. Spawn 3 where 3 will do; don't fan out to 8 "to be safe."
79+
80+
3. **Lower the effort level on cheap phases.** Thinking is billed as output, so a high global effort multiplies every agent. Drop it for mechanical phases.
81+
82+
4. **Self-imposed budget guard (in-script hard ceiling).** A workflow script can read a live output-token meter (`budget.spent()`) and stop spawning once it crosses a self-set cap -- e.g. `while (budget.spent() < cap) { ...spawn... }`, with a hard max-iteration runaway guard. This halts the loop deterministically without needing any special prefix. *(Note: a per-turn `+Nk` "token target" directive is described in the Workflow tool's internal contract, but as of 2.1.158 it does not arm a ceiling -- a `+5k` prefix leaves the budget target unset. Use the in-script `budget.spent()` guard instead, and re-check the changelog on future versions.)*
83+
84+
5. **Account-level caps.** On Pro/Max, `/usage-credits` sets a monthly spend limit. On API billing, set a workspace spend/rate limit in the Console.
85+
86+
### The optimization loop
87+
88+
```
89+
run workflow → read the `subagent` line (/usage or OTEL report)
90+
→ pin cheaper models / cut agent count
91+
→ re-run → confirm the subagent number dropped
92+
```
93+
94+
---
95+
96+
## Quick checklist
97+
98+
- [ ] `OTEL_METRICS_EXPORTER=otlp` set + Claude Code restarted (token metrics flowing)
99+
- [ ] Per-phase `model:` pinned in workflow scripts -- Haiku/Sonnet for mechanical phases
100+
- [ ] Agent count scoped to the task (no defensive fan-out)
101+
- [ ] In-script `budget.spent()` guard + runaway max-iteration cap for unbounded loops
102+
- [ ] `/usage-credits` (Pro/Max) or workspace spend limit (API) as the account-level backstop
103+
- [ ] Verified: a real run shows `query_source=subagent` spend, and it dropped after pinning
104+
105+
---
106+
107+
## Summary
108+
109+
Workflows are expensive because every subagent re-writes your full context into cache -- fan-out, not the task, is the cost. Measure it with `/usage` or the OTEL `query_source=subagent` split, then cap it with per-phase cheap-model pinning (the dominant lever), fewer agents, lower effort, an in-script `budget.spent()` guard, and an account-level credit limit. Don't rely on a `+Nk` prefix for a hard ceiling on 2.1.158 -- it isn't wired yet.

0 commit comments

Comments
 (0)