[Feature Request] Add shell execution primitive to Workflow scripts for deterministic operations
Feedback: subagent fan-out cost — two findings from an instrumented workflow run
Claude Code, macOS 26.5.2, 18 cores. Measured from one Workflow run's own transcripts
(~/.claude/projects/<project>/subagents/workflows/<runId>/agent-*.jsonl), summing theusage block on every assistant message. Numbers below are a live snapshot at 23 agents;
the run had not finished.
The measurement
A multi-agent design-review workflow: one mechanical-lint agent, four parallel reviewer
agents, one classifier, N parallel verifier agents (one per finding), one fix agent, looping
in rounds.
| | value |
|---|---|
| agents | 23 |
| assistant turns (all agents) | 1,030 |
| output tokens | 656,079 |
| cache creation | 5,586,784 |
| cache read | 72,733,002 |
| write : read ratio | 1 : 13.0 |
| avg context per turn | 70,614 |
| avg turns per agent | 44 |
Applying the published multipliers (writes 1.25×, reads 0.10×), the two halves are nearly
equal in base-token-equivalent terms: writes ≈ 7.0M, reads ≈ 7.3M. Neither dominates.
For scale on the user side: this single run consumed roughly 3% of a 20x Max weekly
allowance per round, which puts a 5-round run near 11%. That is the reason for the report —
the cost is real, and most of it is invisible until you sum the transcripts.
Finding 1 — fan-out re-pays cache creation for identical context, N times
Every one of the 23 agents wrote its own cache: 242,903 tokens per agent on average,
5.59M total. A large share of that is the same bytes — the same design document and the
same 10,000-line source file, read independently by each reviewer.
It cannot currently be shared, and the reason is structural rather than a missing feature:
- Prefix caching requires an identical prefix from token 0. Each subagent's prefix diverges
immediately — different agent-type system prompt, different task prompt.
- The shared content (a file) arrives later, as a tool result, at a different offset in
each agent. Under prefix caching that position can never be a cache hit.
What would help, in increasing order of effort:
- Document the pattern. Callers can capture much of this today by prepending shared
context byte-identically before anything agent-specific, so agents 2..N read instead of
write. Nothing in the Agent/Workflow docs suggests this, and it is not obvious — the
natural way to write a fan-out puts the per-agent instruction first.
- A shared-prefix parameter for fan-out — let a caller declare "these N agents share
this prefix", so the platform writes once and reads N−1 times.
What I am explicitly not claiming: that general cross-agent cache sharing is easy or
overlooked. KV entries are position-dependent and conditioned on all preceding tokens, so
splicing a cached block into a different conversation at a different offset is not the same
computation. Relaxing that is a research direction with accuracy tradeoffs, not a flag. I am
reasoning from published prefix-caching semantics and cannot see the implementation.
And the honest bound on the win: cache reads are turns × context, entirely within one
agent — 1,030 turns × 70,614 average context. Sharing between agents does not touch that
half at all. Best case here is a fraction of the write half, maybe 15–25% of the input bill.
Worth having, not a fix.
Finding 2 — workflow scripts cannot run trivial shell commands, so mechanical steps get priced as agents
This one has no physics behind it and a much better payoff.
Workflow scripts have no filesystem or shell access; every action must be an agent() call.
My workflow's first phase runs a Python linter over a document — 0.2 seconds from a
terminal. Because the script cannot invoke it, the phase is an agent that shells out and
then interprets the result.
Measured cost of that one phase:
| | |
|---|---|
| wall clock | 11m 46s (serial — it blocks the entire run) |
| tool calls | 45 (25 Bash, 16 Edit, 4 Read) |
| cache read | 5.56M |
| cache write | 333,546 |
11m46s of a 41-minute round, and ~8% of the run's tokens, to run a command that takes 0.2
seconds. Some of that agent's work was genuine judgment, but the mechanical part — run
script, read exit code, branch — is pure overhead imposed by the missing primitive.
Request: a sh() / exec() primitive in workflow scripts, even a restricted one
(no network, working-directory-scoped, output size capped). Deterministic glue is exactly
what the scripting layer is for; forcing it through a model turns a free step into the
most expensive serial phase in the run.
This also has a correctness dimension, not just cost. The docs rightly push deterministic
control flow into the script and away from model judgment — but with no way to run a check,
every mechanical gate has to be delegated to an agent that may interpret it loosely. A sh()
primitive would let the script compute a gate rather than ask for one.
Reproducing
Any Workflow run leaves per-agent transcripts under~/.claude/projects/<project>/subagents/workflows/<runId>/agent-*.jsonl. Summingcache_creation_input_tokens, cache_read_input_tokens and output_tokens across everyusage block reproduces the table above. journal.jsonl gives per-agent start/result events
for the wall-clock figures.
Incidentally: that per-agent accounting was easy to extract and genuinely useful. Surfacing
a token summary per phase in /workflows would let people tune fan-out without writing a
script to parse their own transcripts.