Skip to content

Parallel Fan-Out and Join

Open mutually independent work at the same time, and wait to join it back together at the one point where nothing can be decided until every result is in. The hard part isn't the opening — it's where to wait, when to stop, and what to do with a branch that failed, and no tool decides those for you.

Problem

Ask "look into these three libraries and tell me which to use," and they usually get investigated one after another. But that ordering doesn't exist because each step consumes the previous one's output. It exists because that's how the request was phrased. The three investigations never reference each other. Ordering dependency and data dependency have been conflated.

The cost of that conflation isn't only latency. Read all three in a single context and three investigations' worth of clutter piles up in the same place, so by the time the comparison happens the first one read has faded. Not splitting the work damages both the wall clock and the context.

Yet the moment the work is split, three questions appear that didn't exist before. When does the joining happen? If one branch out of three fails, is the whole thing discarded? What ends an open-ended search? Tools supply the mechanism for opening branches in parallel; answering these three is left to the practice.

Context

Applies when:

  • The branches don't need each other's results — three libraries to investigate, four review perspectives, the same question asked of several repositories
  • Each branch's result compresses into a summary — the joining side doesn't have to receive full text
  • The judgment only becomes possible after joining — comparison, ranking, or synthesis sits at the end

Doesn't apply when:

  • Every branch must share the same context, or the branches depend heavily on each other. This isn't speculation — it's a limit the Official docs name explicitly, and the same source goes as far as saying most coding tasks contain fewer truly parallelizable parts than research does (source in the Practice section)
  • There are only one or two branches. Designing the fan-out and the join costs something in itself. The round trips of opening and joining can exceed the cost of just reading in sequence
  • The cost can't be paid. More branches means more interactions with the model. The price tag belongs to The Break-Even Point of Delegation

Boundaries with adjacent patterns:

  • Read-and-Discard Isolation — that pattern handles the inside of a single branch (what to discard, what to bring back as a summary). This pattern handles how many branches there are and how they get bundled
  • The Break-Even Point of Delegation — that pattern is the price tag on whether to delegate; this one is the arrangement after delegation has been decided
  • Session Boundary Design — both touch "when to stop," but the trigger differs. That pattern's trigger is context degradation; this pattern's trigger is new results having dried up
  • Computation as Code — at the join point, merging, deduplicating, and normalizing results are settled procedures. That pattern takes over that portion

Solution

Sequential versus fan-out and joinThe top path is sequential: three independent investigations pile up in one context in order, and by the time of the comparison all of the first investigation's clutter is still present. The bottom path fans out: three investigations run at the same time in separate contexts and each returns only a summary. The third one has failed, but because it is isolated the remaining two continue. The join point sits only at the comparison step, which is the step that cannot be decided until every result is in. Before the join there is a stopping condition: halt once new results stop appearing.Sequential (the ordering isn't a data dependency)Investigation AInvestigation BInvestigation CCompareThree investigations' clutter accumulates in one context; by the comparison, the first has fadedA, B and C never reference each other — the only reason they are in a row is how it was askedFan-out and join (exactly one waiting point)RequestA (separate context)B (separate context)C (failed — cut loose)Joinsummaries onlyComparePut the waiting point only where nothing can be decided until all results are in; more of them means going back to sequentialWhether to cut a failed branch loose, and when to call off a search, is decided by the practice — not the tool

First, separate ordering dependency from data dependency. Of the steps written as "then do this," which ones actually read the previous output? The ones that don't have no reason to be in a row. Only a person who knows the substance of the work can make this distinction; the tool simply follows the order it was given.

Second, put the waiting point only where nothing can be decided until every result is in. Comparison, ranking, and synthesis qualify. Conversely, if something can proceed each time one branch reports, that isn't a waiting point. Every additional waiting point pushes the shape back toward sequential and erases the reason for splitting. Splitting and joining are a pair: split without deciding how to join, and the joining place never gets decided at all.

Third, decide in advance what a failed branch means. If one of three fails, may the judgment proceed on the remaining two, or is a judgment without all three meaningless? The nature of the work decides this — not the tool's default. If "we could only look at two of the three libraries" is an acceptable basis for the choice, the branch can be cut loose; if it isn't, the whole thing gets redone. ⚠ Within the range checked, neither vendor's primary sources recommend this "cut it loose and continue" (Absence Confirmed; search terms and range in the Practice section). There are nearby statements, but they are about resuming from where a failure occurred — not about cutting a branch loose.

Fourth, give an open-ended search a stopping rule from outside. Requests of the form "collect everything that might be relevant" have no natural end. One way to stop: check whether what comes back duplicates what's already held, and call it off once a stretch produces nothing but duplicates. ⚠ This too is absent from the primary sources (Absence Confirmed). What's nearby is "let the model judge whether enough information has been gathered," which is a different thing from imposing a mechanical stopping condition from outside. The former depends on the model's judgment; the latter doesn't.

Of the four, tools help with the first and partway into the second. The third and fourth are, within the range checked, territory where nobody has written a recommendation, so whoever is doing the work has to decide. Run without deciding, and the default behaviour becomes the policy.

Trade-offs

Benefits

  • Wall clock shrinks to the slowest single branch instead of the sum
  • Branches' clutter doesn't mix. Only summaries arrive at the join, so the first investigation hasn't faded by the time of the comparison
  • Tools and permissions can differ per branch. The joining side doesn't need to know how each branch went about it

Costs

  • Consumption goes up. Each branch generates its own interactions with the model. Both vendors state this in Official docs (Practice section). The price tag belongs to The Break-Even Point of Delegation
  • Branches don't know about each other. If two of them investigate the same thing, that can't be noticed while they run — only once they join
  • Deciding the shape takes effort. Where to wait, what a failed branch means, and when to stop have to be decided per task. For a two-branch job, that effort costs more than it saves

GitHub Copilot in Practice

The mechanism for opening branches in parallel exists on several surfaces. Recommendations about joining, failure, and stopping do not exist within the range checked. Below, the mechanisms surface by surface, then the range over which the absences were confirmed.

Copilot CLI — instruct parallelism with /fleet

Parallelism can be requested from the human side (source: Running tasks in parallel with the /fleet command, retrieved 2026-07-16) Official:

Context window: Each subagent has its own context window, separate from the main agent and other subagents. This allows each subagent to focus on its specific task without being overwhelmed by the full context of the larger task.

The same page also states the cost Official:

Each subagent can interact with the LLM independently of the main agent, so splitting work up into smaller tasks that are run by subagents may result in more LLM interactions than if the work was handled by the main agent. Using /fleet in a prompt may therefore cause more GitHub AI Credits to be consumed.

VS Code — the branch contract comes from the human

On the surface where the main agent spawns subagents, the official docs say to state what each branch is to do and to return (source: Subagents in Visual Studio Code, retrieved 2026-07-16) Official:

To optimize subagent performance, clearly define the task and expected output.

That is the design of the join point itself. If the shape the joining side receives isn't fixed, waiting for everything still doesn't make it comparable. But note that the original says only "define it clearly" — it says nothing about where to wait.

The other vendor — joining appears as a description of an implementation

The counterpart primary source (source: How we built our multi-agent research system, retrieved 2026-07-27; 180,431 bytes retrieved in full with curl) states that the current implementation of the research system runs subagents synchronously, waiting for each set to complete before proceeding, with synthesis performed by the lead agent Official. ⚠ The scope is a research system — it is not written as a general design guideline for agents.

The same source names the cases where this doesn't apply, which is the basis for this page's Context section Official:

Further, some domains that require all agents to share the same context or involve many dependencies between agents are not a good fit for multi-agent systems today. For instance, most coding tasks involve fewer truly parallelizable tasks than research, and LLM agents are not yet great at coordinating and delegating to other agents in real time.

⚠ The same source also gives token consumption multipliers, but this page doesn't carry those numbers. The Break-Even Point of Delegation is where they belong. This page states only the direction: it goes up.

What wasn't there (with range)

On 2026-07-27, two subagents separate from the one that fetched the source material retrieved and checked 17 primary sources: eight on the GitHub side (/fleet, three Copilot CLI custom agent references, and VS Code's subagents, agents concepts, overview, and custom agents — all retrieved in full as raw markdown from the official repositories) and nine on the other side (Claude Code best practices, sub-agents, and hooks; the Agent SDK subagents reference; Agent Skills best practices; structured outputs; prompt chaining; the tool use overview; and the research system article above — all retrieved in full).

What was looked forSearch termsResult
Cutting a failed branch loose and continuingpartial / isolat / error propagation / graceful / rather than failingIn the research system article, partial 0 hits, isolat 0 hits. ⚠ What was found is "resume from where the error occurred" and "retries with regular checkpoints" — not cutting loose
Stopping via deduplication and a run of empty resultsdeduplic / new result / stop condition / stopping / converg / terminationIn the same article, deduplic 0 hits, new result 0 hits, stop condition 0 hits, converg 0 hits. ⚠ What was found is "let it judge whether enough information has been gathered" and "scale effort to query complexity" — not a mechanical stopping condition
An established name for the waiting pointbarrier / joinNo use as a name could be confirmed. Joining appears as "wait" and "synthesize," and as the ordering of an implementation

This is Absence Confirmed. It doesn't mean "you shouldn't do this," and it doesn't mean "the capability is missing" — only that no recommendation appeared within the 17 sources checked. This catalogue infers nothing about behaviour from that.

Also Known As

NameSource
Parallel Fan-Out and JoinDescriptivethis catalogue's descriptive name; no primary source uses it
Subagent / /fleetPrimary — but these name the mechanism that opens a branch, not this pattern (sources in the Practice section)

Don't cite "join," which this catalogue used in the name, as an official term. Across the 17 sources checked, no established name for the waiting point was found. The same goes for the diagrammatic vocabulary the source material uses (nodes and edges, barriers) — treat all of it as this catalogue's coinage.

The reason not to borrow a mechanism's name for a practice is the same one given in Read-and-Discard Isolation. The practice holds even where no parallel mechanism exists — investigating in several separate sessions at once and writing the results back into one place has the same shape regardless of tooling.

  • Read-and-Discard Isolationa single branch of this pattern is that pattern. That one handles the inside of a branch (what to discard, what to bring back as a summary); this one handles how many branches there are and how they get bundled. Only summaries reach the join point because that pattern is doing its work
  • The Break-Even Point of Delegationthat pattern holds the price tag. Both vendors' Official docs state that more branches means more interactions with the model (Practice section), and the multipliers and the break-even estimate belong there. This page states only the direction
  • Session Boundary Designthe trigger for "when to stop" differs. That pattern's trigger is context degradation; this one's is new results having dried up. Same act of calling it off, different needle being watched
  • Computation as Codeit takes over the inside of the join point. Of the bundling work, merging, deduplicating, and normalizing are settled procedures with no reason to be left to inference. ⚠ Note that pattern claims determinism, not that it's cheaper
  • Making the Output Contract Explicit — deciding what each branch returns is a precondition for bundling. That pattern handles the shape of output a human receives; here the same problem appears as the shape the joining side receives
  • Making the Verification Target Explicit — if what each branch is confirming is left vague, joining them still doesn't make them comparable
  • If reading just one more next: The Break-Even Point of Delegation — having decided the shape, it's next to see what the shape costs