LEARN · PHASE 12 · LESSON 81

Workflow Runtime Caps

The runtime bounds how many agents are in flight, how long an agent may stay

Type
Learn
Prerequisites
Lesson 80 (The Completion-Order Gotcha)
Time
~40 minutes

Learning Objectives

  • Name the four caps that bound a run, and which one your script's design has to respect
  • Predict what a run does when it crosses the concurrency cap, the list cap, and the total-agent cap
  • Say what a restarted agent keeps and what it loses, in terms of files and transcript
  • Explain why a stalled agent is not the same as a failed one, for the purposes of a relaunch
  • Set the stall window deliberately, for one agent and for the whole run

The Problem

Two incidents, one afternoon.

The first: a workflow was asked to migrate 800 files, one agent per file. The author had assumed 800 agents would run at once. The run took the better part of an hour and looked, on the progress line, like nothing was happening — because sixteen agents were in flight and the rest were queued behind them. Nothing was stuck. The mental model was wrong.

The second: one agent went quiet. It had made three edits, then started a tool call that produced no output for long enough that the runtime gave up on the attempt and restarted the agent from the same prompt. The new attempt began without the stalled attempt's transcript. But — and this is the whole incident — the three files the first attempt had already changed were still changed. The restart is not a rollback. The second attempt began on a repo that the first attempt had half-modified, with no memory that it had.

Both of these are caps. Neither is a model problem, and neither is a bug.


The Concept

Four caps. They bound different things, and each one has a different failure shape when you hit it.

flowchart TB
    A["your task"] --> B["1. list cap<br/>≤ 4,096 items per call<br/>REJECTED if longer"]
    B --> C["2. in-flight cap<br/>≤ 16 agents at once<br/>the rest QUEUE"]
    C --> D["3. run cap<br/>≤ 1,000 agents total<br/>run stops"]
    D --> E["4. stall window<br/>how long an agent may be silent<br/>attempt RESTARTS"]
    E --> F["agent restarts ≤ 5 times<br/>each restart is not a rollback"]
Mermaid source — renders as a diagram where mermaid.js is available

1. The list cap: 4,096 items per call

A single parallel() or pipeline() call holds at most 4,096 items. A longer list is rejected with an error — not truncated, not split.

The docs say why, and the reason is worth more than the number: a silent cap would drop part of the workload without telling the script. That is the same principle as the null slot from Lesson 80. The runtime refuses to be quietly wrong on your behalf.

So if you have more items than that, split the list yourself — and decide what a batch boundary means for your results, because you are the one who has to rejoin them.

2. The in-flight cap: 16 agents at a time, by default

The runtime runs up to 16 concurrent agents by default, fewer when the machine has fewer CPUs — including inside a CPU-limited container. This is the cap behind the first incident: 800 items is 800 agents, but it is 16 at a time.

CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS accepts a value from 1 to 256 and requires a recent version. Raising it does not make the work free: more agents in flight is more tokens per minute and more load on the machine you are also trying to use.

This is also where a fan-out's prompt cache lives. Agents that share a prefix — same model, effort level, agent type, tools, output schema, and working directory — can read each other's cache. So the runtime holds all but the first agent of a matching fan-out until the first one's response begins, then releases them together, up to a cap of five seconds by default. Set CLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS to 0 to disable the hold. A workflow agent's cache lives five minutes by default; subagentPromptCacheTtl of 1h extends it, and the API bills a one-hour cache write at a higher rate.

You do not have to understand the cache to be bitten by the hold: it is one more reason a 20-agent fan-out does not start all at once.

3. The run cap: 1,000 agents total

A single run may spawn at most 1,000 agents. That is the backstop against a runaway loop. If your script recurses or retries unboundedly, it hits a wall instead of your card.

For scale: 4,096 items per call is the list cap; 1,000 agents is the run cap. A pipeline over 4,000 items will not get 4,000 agents — it will stop at the run cap. Know which wall you are closer to before you write the loop.

4. The stall window: where a restart is not a rollback

An agent whose output stops arriving for long enough is restarted from the same prompt. In /workflows its name gains a (retry 1) suffix and its detail shows attempt 2 (stalled).

What the new attempt inherits, and what it does not:

After a stall restart
The stalled attempt's transcriptGone. The new attempt starts without it
Files the stalled attempt already changedStill changed. No rollback
Tokens the stalled attempt spentStill counted. They are in the run's total

An agent restarts at most five times, counting any restart you ask for with r. If the sixth attempt stalls too, the agent() call fails and the error names which of three ways it went:

  • agent stalled on all 6 attempts — every attempt was silent for the whole window. The agent's work keeps it quiet that long; lengthen the window
  • agent lost its reply on all 6 attempts — the response stream went silent. Lengthening the window will not help; a streaming idle watchdog ended it first
  • agent abandoned after 6 attempts — the attempts ended in different ways, which the error lists in order

Two knobs. Per agent: agent(prompt, { stallMs: 1800000 }) for a 30-minute window. Whole run: CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS, which also applies to subagents outside workflows.

Time an agent spends waiting on its own tool calls or on a usage-limit reset does not count toward the window. That is deliberate: a legitimately slow command is not a stall.

The two things that are not caps

A run takes no input mid-flight. It pauses on its own only for agent permission prompts and a usage-limit wait. For sign-off between stages, run each stage as its own workflow and let yourself look at the result.

A workflow has no filesystem and no shell. Agents read, write, and run commands; the script coordinates. A script containing import() fails before the run even starts.

One more number that is advice, not a cap

Above 25 agents, or a projected 1.5 million tokens, the run's progress line shows a Large workflow warning. It is advisory — it does not pause anything. The size guideline from Lesson 78 changes the agent-count threshold when you set it yourself, and the default guideline leaves it at 25. Sessions with ultracode on do not show the warning at all, because turning ultracode on already opts you in to large runs.

The reframe: the caps bound how much is in flight and how long a single

attempt may stay silent — not how much work you may describe — so the number

your script is designed around is concurrency, and the stall window is the

number that decides whether a restart is cheap or destructive.


Build It

1. Count before you run

Take a task you would actually fan out — every file in a directory, every issue in a tracker. Write down three numbers before touching a workflow: the number of items, your estimate of the agents the script will spawn, and the number you expect to be in flight at once.

✅ You pass when all three numbers are different, and you can say which cap each one is measured against.

2. Watch the queue

Run a fan-out over a list comfortably larger than 16 — a directory with 60 or more files is plenty. Do not wait for it to finish; watch /workflows for the first thirty seconds.

✅ You pass when you can see that some agents have not started, and name the cap that is holding them rather than the cap that would reject them.

3. Hit the list cap cheaply

The list cap is enforced before any agent starts, which makes it the one cap you can prove for free. Have the workflow build a list of 4,100 items and pass it to a single pipeline() call.

✅ You pass when the call fails with an error naming the list, and no agents were spawned — verify by checking the run's agent count.

4. Kill an agent by being quiet

This one is about the stall window, and you cannot force it directly. What you can do is give an agent a job that legitimately keeps it silent for a long time — a big build, a long test run — with a short window set through CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS, and watch what /workflows shows.

const slow = await agent('Run the full test suite and report every failure.', { stallMs: 5000 })

✅ You pass when the agent's row shows a (retry 1) suffix or an attempt 2 (stalled) detail, and you can state which of the three error strings you would get if it did that six times.

5. Show that a restart is not a rollback

With an agent that writes a file before going quiet, let it stall, and then check the file it wrote during the first attempt.

✅ You pass when the file is still changed after the restart, and you can say what the second attempt does not know about it.

6. Raise the ceiling and measure

Set CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS to something larger for one run — say 32 — and repeat step 2 on the same list.

✅ You pass when the number of agents in flight at the peak is visibly higher and you have a sentence about what it cost: wall clock, machine load, or tokens.

7. Watch a large-run warning appear

A run above 25 agents will announce itself. If your list is smaller, pick a bigger directory.

✅ You pass when you can point at the warning, and state the one action it offers you rather than the action it takes for you.

Every number here is version-gated, and several are environment-gated — the

concurrency default depends on the machine's CPUs, and the concurrency ceiling

needs a recent version. Verified against

the workflows page on 2026-10-15.

Check https://code.claude.com/docs/llms.txt before you set any of them in

something that has to keep working next month.


Use It

You are about to…The cap that appliesDo this instead
Fan out over 5,000 filesList cap, 4,096 per callSplit the list yourself and decide how the parts rejoin
Assume a big fan-out is instantIn-flight cap, 16 by defaultBudget wall clock as items ÷ in-flight, roughly
Raise concurrency to make it fastCLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS, 1–256Expect more load and more tokens per minute
Retry forever on a flaky agentRun cap, 1,000 agentsBound the loop yourself
Give an agent a long silent jobStall windowstallMs, or CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS for the run
Assume a restart undoes editsIt does notMake the agent's writes idempotent, or check the disk
Pause mid-run for sign-offNot supportedRun each stage as its own workflow
Read config inside the scriptNo filesystemGive an agent the read; branch on its result

Exercises

  1. Take a real directory in this repo and compute, on paper, how long a one-agent-per-file fan-out would take at 16 in flight, assuming each agent is roughly as slow as the slowest one you have watched. ✅ You pass when your estimate and the actual wall clock are within a factor of two, or your note explains what you missed.
  1. Find the script for a run that hit a stall restart, and read the stalled agent's task. Say what a retry of that task would do differently from the first attempt, given that its files were not rolled back. ✅ You pass when your answer names a concrete side effect the second attempt could duplicate rather than a general statement about idempotency.
  1. Set the stall window to something absurdly short, then something generous, on the same task. Report what changed. ✅ You pass when you can say which error string a too-short window produces, and why lengthening the window would not fix a silent response stream.
  1. A run pauses on a usage-limit wait. List the conditions that have to hold for it to pause rather than fail that agent, and one of them that does not apply in headless mode. ✅ You pass when your list matches the docs and you can name which session kinds never get the pause.

Key Terms

TermWhat people sayWhat it actually means
list cap"too many files"4,096 items per parallel()/pipeline() call. Rejected, never truncated
in-flight cap"it should be parallel"16 concurrent agents by default, fewer with fewer CPUs. The rest queue
run cap"a safety limit"1,000 agents in one run. The backstop against a runaway loop
stall window"a timeout"How long an agent may produce no output before the attempt is abandoned and restarted
restart"a retry"A new attempt from the same prompt. No transcript, no rollback, tokens still counted
stallMs"a timeout option"The per-agent override for the stall window, in milliseconds
CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS"the global timeout"The run-wide stall window. Also applies outside workflows
prefix stagger"a delay"Up to 5 seconds of hold so a fan-out's later agents read the first one's prompt cache
stall vs failure"it failed"A stall retries without the run noticing; a failure reruns the tail on a relaunch. Different mechanisms
Large workflow"an error"An advisory warning above 25 agents or 1.5M projected tokens. It does not stop anything

What this lesson skipped

Cost instrumentation. Knowing which agents spend the tokens is a different skill, and it is Phase 14. The size guideline here is a crude brake, not a measurement.

The full environment-variable surface. There are more knobs than the four above, and the env-vars page is the list. Anything you set belongs in a note with the version you set it on.

The Agent SDK host. A run launched through the SDK has its own permission model and no approval prompt. Phase 17.

Permission prompts inside a run. Agents in a run use your permission rules, and the runtime picks their mode by the same rules it uses for subagents — Lesson 33 for the modes, the subagents page for the exact selection order.

Time spent waiting on a usage-limit reset. It is excluded from the stall window, and the wait has its own conditions and a two-wait limit. Covered on the workflows page; not repeated here because it is about your plan, not your script.

Check yourself

6 questions. Answer before you reveal — recognising the right option is not the same as being able to produce it.

  1. A pipeline() fans out over 800 files, one agent per file, with nothing else configured. Roughly how many of those agents are working at the same time?

    1. About 16, or fewer if the machine has fewer CPUs. The rest wait their turn
    2. All 800, since one call means one batch
    3. One at a time, because pipeline() runs items in sequence
    4. Up to 4,096, which is the list cap for a single call
    Show answer

    A. About 16, or fewer if the machine has fewer CPUs. The rest wait their turn

    The runtime runs up to 16 concurrent agents by default, and less when fewer CPUs are available, including inside a CPU-limited container — so 800 items means 800 agents overall but about 16 in flight. The all-800 answer and the one-at-a-time answer are the two intuitions people bring, and both are wrong in opposite directions; the docs explicitly do not give pipeline() a scheduling difference from parallel(). The 4,096 figure is a real number but it is the per-call item cap, not a concurrency figure.

  2. An agent edits three files, then goes quiet long enough to be restarted. What is true of the second attempt?

    1. It starts without the first attempt's transcript, and the three files are still edited
    2. It starts with the first attempt's transcript, and the three files are still edited
    3. It starts without the transcript and the three edits are rolled back
    4. It starts without the transcript, and the tokens the first attempt used are refunded to the run
    Show answer

    A. It starts without the first attempt's transcript, and the three files are still edited

    A restart is a fresh attempt from the same prompt: the new attempt does not inherit the stalled transcript, the files it already changed stay changed, and the tokens it spent stay in the run's total. The rollback answer is the one everybody wants, because 'restart' sounds like 'clean slate' — it is the reason an agent's writes should be idempotent. The transcript and refund variants both describe a restore that the docs do not offer.

  3. A script calls one pipeline() with a 4,100-item list. What happens?

    1. The call is rejected with an error before any agent starts
    2. The first 4,096 items run and the remaining four are reported as skipped
    3. All 4,100 run, split into two internal batches
    4. The last four items are dropped silently so the run can continue
    Show answer

    A. The call is rejected with an error before any agent starts

    The per-call cap is 4,096 items and a longer list is rejected, because a silent cap would drop part of the workload without telling the script. The truncation answer is the tempting one — it is what most systems do — and it is exactly the behaviour the docs call out as unacceptable. Nothing is split automatically, and a silent drop is the failure the cap exists to prevent. This is also why it is the cheapest cap to demonstrate: no agent ever runs.

  4. An agent runs a test command that takes 25 minutes, and the stall window is 10 minutes. Does it count as stalled?

    1. No — time an agent spends waiting on its own tool calls does not count toward the stall window
    2. Yes — any 10 minutes without output ends the attempt
    3. Yes, but only because the test command produces no incremental output
    4. No, but only if the window was set with stallMs rather than the run-wide variable
    Show answer

    A. No — time an agent spends waiting on its own tool calls does not count toward the stall window

    The stall window measures output starvation, and the docs exclude time spent waiting on the agent's own tool calls, or on a usage-limit reset. That exclusion is why a legitimately slow build does not get its agent killed. The 'any 10 minutes' answer is the natural reading of a plain timeout and is the trap: it would make long test runs impossible, which is not how workflows behave. The mechanism you set the window with is irrelevant to whether the wait counts.

  5. An agent fails after six attempts with agent lost its reply on all 6 attempts. What does that tell you to change?

    1. Nothing about the stall window — the response stream went silent and a streaming idle watchdog ended it
    2. Make the stall window longer, since the agent needed more time to produce output
    3. Raise the retry count, since six attempts were not enough
    4. Lower the concurrency cap, since too many agents were competing for the API
    Show answer

    A. Nothing about the stall window — the response stream went silent and a streaming idle watchdog ended it

    This error names the response stream going silent, and the docs are explicit that lengthening the stall window does not help because the streaming idle watchdog ended the response first — its own timeout is a different variable. The length-the-window answer is the strong temptation, because the sibling error, agent stalled on all 6 attempts, is exactly the case where more time does help. The other two options change the wrong number: the attempt count is fixed at six including manual restarts, and concurrency is not implicated.

  6. A workflow schedules 40 agents and is projected to spend well over a million tokens. What does the runtime do?

    1. Shows an advisory Large workflow warning; the run continues unless you stop it
    2. Pauses the run and asks you to approve the spend before continuing
    3. Caps the run at 25 agents and reports the remainder as skipped
    4. Fails the run, because it crossed the projected-token threshold
    Show answer

    A. Shows an advisory Large workflow warning; the run continues unless you stop it

    The warning is advisory: it appears above 25 agents or a projected 1.5 million tokens and points you at /workflows, where you can stop the run — it neither pauses nor limits anything. The pause-and-approve answer is plausible because the launch does prompt in most permission modes, but that prompt happens before the run, not in response to its size. The other two answers treat an advisory threshold as an enforced cap, which it is not.