Claude Code Workflows Pin the Script — Running Dozens of Subagents from One File

Claude Code has had three ways to run a multi-step task for a while: subagents, skills, and agent teams. A fourth column has now been added, and it differs from the other three on one axis that turns out to matter more than scale.
In the first three, Claude holds the plan and decides turn by turn what to spawn next. In a dynamic workflow, a JavaScript script holds it. Claude writes the script, a runtime executes it in the background, and Claude’s context ends up holding only the final answer.
- Who decides what runs next
- What was actually happening when we asked in conversation
- What is inside the script
- How a run starts
- Caps and the warning
- The rules when a run stops
- The shape of the cost
- The script this site ran
- The one refuted finding was the point
- Saving it and calling it by name
- What to put in a script at the 3D printing bench
- The short version
- Sources
Who decides what runs next
| Subagents | Skills | Agent teams | Workflows | |
|---|---|---|---|---|
| What it is | A worker Claude spawns | Instructions Claude follows | A lead agent supervising peer sessions | A script the runtime executes |
| Who decides what runs next | Claude, turn by turn | Claude, following the prompt | The lead agent, turn by turn | The script |
| Where intermediate results live | Claude’s context window | Claude’s context window | A shared task list | Script variables |
| What is repeatable | The worker definition | The instructions | The team definition | The orchestration itself |
| Scale | A few delegated tasks per turn | Same as subagents | A handful of long-running peers | Dozens to hundreds of agents per run |
| Interruption | Restarts the turn | Restarts the turn | Teammates keep running | Resumable in the same session |
The row that changes how the work feels is the third one. When intermediate results live in a context window, a large fan-out competes with the conversation for room, and a long run degrades as the window fills. When they live in script variables, it does not.
What was actually happening when we asked in conversation
Before workflows, a review of seven articles across seven criteria meant asking Claude to delegate, then watching every finding land in the conversation. Forty-nine results, each carrying its own reasoning, all of it occupying the same window as the writing that came next. The practical ceiling was not the model; it was room.
Moving the plan into code lifts that ceiling, but it also buys something less obvious: a repeatable quality pattern. A script can have independent agents adversarially review each other’s findings before any of them are reported, or draft a plan from several angles and weigh them. That is harder to do reliably when Claude is improvising the orchestration turn by turn.
What is inside the script
A saved workflow is a meta block followed by plain JavaScript with top-level await. Three functions do the orchestrating: agent() spawns one subagent, pipeline() runs one per item in a list, and parallel() runs a set of tasks at the same time and waits for all of them. phase() groups the agents that follow under a title in the progress view, and log() prints a line above the phases.
Pass a schema on an agent() call and that subagent returns JSON matching the shape instead of prose. Claude Code checks the schema before starting the subagent and fails the call when it can prove the schema contradicts itself. If the output still fails validation after five attempts, the call fails with the last validation error attached.
Two constraints on the script body are easy to trip over. Module loading is refused: a script containing import() fails before the run starts. And Date.now(), Math.random(), and a no-argument new Date() all throw inside the script, so that a relaunched run repeats the same agent() calls. Pass a timestamp in through args instead.
How a run starts
You can ask for one in your own words, include the keyword ultracode in a prompt you type yourself, or set /effort ultracode so Claude plans a workflow for every substantive task in the session. Saved workflows run as /name, and the bundled /deep-research is there to try the shape without writing anything.
The keyword is an opt-in only in a prompt you type. It does not start a workflow when it arrives via -p, from an SDK application that does not stamp the input as human, from a scheduled task prompt, or from a webhook payload or pull request comment relayed into the conversation. That boundary is deliberate and worth knowing about before you let untrusted text near a session.
Caps and the warning
| Constraint | Value | Why |
|---|---|---|
| Concurrent agents | 16 by default, fewer with fewer CPUs | Bounds local resource use |
| Items in one parallel() or pipeline() | 4,096 | A longer list is rejected with an error rather than silently truncated |
| Total agents per run | 1,000 | Prevents runaway loops |
| Mid-run user input | Not accepted | For sign-off between stages, run each stage as its own workflow |
| Filesystem and shell from the script | Not available | Agents read, write, and run commands; the script coordinates them |
Separately, Claude Code flags a run that grows unusually large. More than 25 scheduled agents, or a projected total past 1.5 million tokens, puts a Large workflow warning on the run’s progress line. It is advisory: it does not pause or limit anything. If you set a size guideline yourself, its agent count replaces the 25-agent threshold, and sessions with ultracode on do not show the warning at all.
The rules when a run stops
A run is resumable within the same session, and the replay rule decides how much work you pay for twice. Claude Code replays agents in the order they started, and each one either returns its saved result or runs again.
- Completed: returns its saved result. The first agent whose prompt differs from the previous run, because you edited the script or an earlier agent returned something different, runs again, and so does every agent after it
- Still running when you stopped: starts over. Stopping the whole run does not count any agent as failed
- Failed: runs again, and so does every agent that started after it, even ones that completed. Stopping a single agent counts as failing it
The consequence is worth planning around. If a script starts A, B, C, and D in that order and B fails, relaunching returns A from cache and runs B, C, and D again. Put the expensive, reliable stages early and the fragile ones late.
The shape of the cost
A workflow spawns many agents, so one run can use meaningfully more tokens than doing the same task in conversation. Runs count toward your plan’s usage and rate limits like anything else.
Caching is the part that saves you. Two agents running with the same model, effort level, agent type, tools, output schema, and working directory build the same prefix, so an agent starting after a matching sibling reads that sibling’s cache. In a fan-out, Claude Code holds all but the first agent for up to five seconds by default so their first requests read the prefix the first one cached.
One caveat: workflow agents fall outside the main conversation’s cache TTL bucket, so their cache holds for five minutes by default even on a subscription. Set subagentPromptCacheTtl to 1h to keep it for an hour, remembering that one-hour cache writes bill at a higher rate.
The script this site ran
The task was a review of one week of drafts across seven criteria, with every finding adversarially verified before it reached the report. The shape was a pipeline of seven review agents, each feeding a parallel fan-out of verifier agents over its own findings, so verification for one criterion started while another was still reviewing.
| Item | Value |
|---|---|
| Agents | 14, being 7 reviewers and 7 verifiers |
| Elapsed | about 10 minutes 15 seconds, in the background, while the session kept writing |
| Tokens | about 2.08M across subagents as reported by /workflows, excluding about 18.30M of cache reads. 237 tool calls |
| Claims checked | 315 |
| Findings | 54, weighted MUST 2, SHOULD 20, CONSIDER 32 |
| Verdicts | 53 confirmed, 1 refuted, and the refuted one was a MUST |
The one refuted finding was the point
One of the two MUST-level findings did not survive verification. A reviewer had flagged a passage as contradicting its cited source; the verifier read the source and found the passage correct. Under the old arrangement that finding would have reached the report, and the fix would have made a correct sentence wrong.
The script also taught us something about its own bookkeeping. Our first version matched findings to verdicts by exact string comparison, which counted two of the 54 as mismatched purely because the verifier had lightly reworded the finding’s title. We changed the matching to compare on position and on the text with formatting stripped. Worth checking in your own script: a reconciliation step that compares generated text to generated text will drift.
Saving it and calling it by name
Run /workflows, select the run, press s, and the script saves as a command. Project location .claude/workflows/ is shared with everyone who clones the repository; ~/.claude/workflows/ is available in every project and visible only to you. If both define the same name, the project one runs.
A saved workflow can take input through the args global, so a review script does not need editing for each week. Before you edit a saved script, or ask Claude to, run the bundled /workflow-authoring skill so Claude works from the script-writing reference; that requires Claude Code v2.1.248 or later.
What to put in a script at the 3D printing bench
The test is whether the same check has to run across many items, and whether a wrong answer is expensive enough to be worth verifying twice.
- Checking every STL in a directory against the same wall-thickness and overhang rules, with each finding verified before it is reported
- Recomputing quotes for every part in a catalogue after a filament price change, one agent per part
- Auditing a slicer profile directory for settings that drifted apart between printers
- Reviewing a batch of drafts against a fixed checklist, which is the case above
What does not suit a script: anything that needs you to decide something halfway through. A run takes no mid-run input, so a stage that ends in a judgement call should be its own workflow.
The short version
- A workflow moves the plan into a script, so intermediate results live in variables instead of a context window
- agent(), pipeline(), and parallel() do the orchestration; no imports, and no Date.now() or Math.random(), so a relaunch replays identically
- Caps are 16 concurrent agents, 4,096 items per call, and 1,000 agents per run. An advisory warning appears past 25 agents or 1.5 million projected tokens
- A failed agent reruns everything that started after it, so put fragile stages late
- Workflow agents get a five-minute cache TTL by default even on a subscription; subagentPromptCacheTtl changes that
- Our 14-agent run checked 315 claims in about ten minutes and the adversarial pass caught one MUST-level finding that was wrong
Sources
- Claude Code, Orchestrate subagents at scale with dynamic workflows
- Claude Code, How Claude Code uses prompt caching





