Fan-out is an orchestrator releasing N workers on independent items and gathering only what matters. It works when each item fits in a clear request, has a cap, and returns a line you can check. In this lesson you run a shell fan-out with a fake agent, watch the time drop, and redo only the rejected item.
1The forms of fan-out in Claude Code and in the shell
2The delegation request: goal, format, sources, and boundaries
3Cap per worker and return in a file
4Consolidate by the last line and redo only the rejected one
Goal: run a fan-out with N workers, a cap per item, and a short consolidation, redoing only the rejected item.
01 · A fan-out with control
The orchestrator plans and merges; the workers only do their part. Click each step.
Rejected? Only that item goes back on the list; approved ones are not redone
Click each block in the diagram to see what it does.
A fan-out of 500 mechanical files needs no model at all: it's a script. An agent comes in when each item requires judgment.
02 · The forms of fan-out today
Per the Claude Code docs (Run agents in parallel, read on Oct 19, 2026) and Codex CLI 0.163.0.
1. Subagents
Ask for several subagents in the same message. The results come back to the conversation that created them.
For a large, repeatable batch, the docs point to dynamic workflows (a script that runs many subagents and compares their results) and /batch, which splits a large change across 5 to 30 subagents, each in its own worktree.
2. Sessions
claude --bg drops a session into the background; claude agents shows them all on one screen. Before editing, the background session moves into its own worktree in .claude/worktrees/.
Each session spends its own quota. Merge the results by file, in a lead session or in a script.
3. Agent teams
Off by default (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1). A lead and teammates with a task list and messages between them. One team per session, no nested teams, and /resume does not restore in-process teammates.
Teammates don't get a worktree: two editing the same file overwrite each other. Split the files by owner.
4. Shell
Outside the session, an xargs -P with claude -p or codex exec per item. This is the one you control best: cap, output file, resume.
This is the form used in the rehearsal below, because you can swap the agent for a fake script.
03 · Fan-out in shell, with a rehearsal
The AGENTE is any command that reads the request on stdin. For the rehearsal, use a script that sleeps 2 s and answers.
fanout.sh · save it in ~/treino-multi/
#!/usr/bin/env bash
# fanout.sh — one worker per line of the list, N at a time, short return in a file.
# Usage: fanout.sh <lista.txt> <pasta-saida> [N]
# AGENTE = command that reads the request on stdin (default: claude -p). For a rehearsal: a fake script.
# TETO = seconds per worker (default 600)
set -u
LISTA="${1:?uso: fanout.sh <lista.txt> <pasta-saida> [N]}"; OUT="${2:?pasta de saída}"; N="${3:-3}"
export OUT AGENTE="${AGENTE:-claude -p}" TETO="${TETO:-600}"
mkdir -p "$OUT"
trabalho() {
item="$1"; nome=$(printf '%s' "$item" | tr -cs 'a-zA-Z0-9' '-' | cut -c1-40)
if [ -s "$OUT/$nome.md" ] && [ "$(tail -1 "$OUT/$nome.md")" = OK ]; then
echo "pula $nome (aprovado)"; return 0 # only the rejected one comes back
fi
printf 'Task: %s\nAnswer in at most 5 lines. Last line: OK, or FALHA: <reason>.\n' "$item" \
| timeout "$TETO" $AGENTE > "$OUT/$nome.tmp" 2>&1
rc=$?
if [ $rc -eq 0 ]; then mv "$OUT/$nome.tmp" "$OUT/$nome.md"; echo "feito $nome"
else mv "$OUT/$nome.tmp" "$OUT/$nome.erro"; echo "erro $nome (rc=$rc)"; fi
}
export -f trabalho
grep -v '^[[:space:]]*$' "$LISTA" | xargs -d '\n' -P "$N" -I{} bash -c 'trabalho "$1"' _ {}
# the orchestrator merges only the last lines: that is what goes back into its context
for f in "$OUT"/*.md; do [ -e "$f" ] && printf '%s: %s\n' "$(basename "$f" .md)" "$(tail -1 "$f")"; done > "$OUT/../consolidado.txt"
echo "itens: $(grep -cv '^[[:space:]]*$' "$LISTA") · feitos: $(ls "$OUT"/*.md 2>/dev/null | wc -l) · com erro: $(ls "$OUT"/*.erro 2>/dev/null | wc -l) · OK: $(grep -c ': OK$' "$OUT/../consolidado.txt") · FALHA: $(grep -c ': FALHA' "$OUT/../consolidado.txt")"
Terminal · no-quota rehearsal (fake agent)
cd ~/treino-multi && chmod +x fanout.sh
E=${TMPDIR:-/tmp}/ensaio-multi/fanout; rm -rf $E && mkdir -p $E
cat > $E/agente-falso.sh <<'SH'
#!/usr/bin/env bash
pedido=$(cat); sleep 2
case "$pedido" in
*quebrado*) printf 'não consegui ler o arquivo\nFALHA: arquivo quebrado\n' ;;
*) printf 'resumo de uma linha\nOK\n' ;;
esac
SH
chmod +x $E/agente-falso.sh
printf 'resumir docs/a.md\nresumir docs/b.md\nresumir docs/quebrado.md\nresumir docs/c.md\nresumir docs/d.md\n' > $E/lista.txt
time AGENTE=$E/agente-falso.sh ./fanout.sh $E/lista.txt $E/saida 1 # one at a time
rm -rf $E/saida
time AGENTE=$E/agente-falso.sh ./fanout.sh $E/lista.txt $E/saida 3 # three at a time
AGENTE=$E/agente-falso.sh ./fanout.sh $E/lista.txt $E/saida 3 # again: nothing is redone
cat $E/consolidado.txt
Terminal · real, with 2 or 3 items from your project
cd ~/treino-multi
printf 'Resuma runtime/POLITICA.md em 3 linhas\nResuma runtime/ROTEAMENTO.md em 3 linhas\n' > lista-real.txt
./fanout.sh lista-real.txt real/saida 2 < /dev/null
cat real/consolidado.txt
Example from the repository
feito resumir-docs-a-md
feito resumir-docs-b-md
feito resumir-docs-quebrado-md
feito resumir-docs-c-md
feito resumir-docs-d-md
itens: 5 · feitos: 5 · com erro: 0 · OK: 4 · FALHA: 1
real 0m10.094s
(…)
feito resumir-docs-a-md
feito resumir-docs-b-md
feito resumir-docs-quebrado-md
feito resumir-docs-d-md
feito resumir-docs-c-md
itens: 5 · feitos: 5 · com erro: 0 · OK: 4 · FALHA: 1
real 0m4.054s
(…)
pula resumir-docs-b-md (aprovado)
pula resumir-docs-a-md (aprovado)
pula resumir-docs-c-md (aprovado)
pula resumir-docs-d-md (aprovado)
feito resumir-docs-quebrado-md
itens: 5 · feitos: 5 · com erro: 0 · OK: 4 · FALHA: 1
resumir-docs-a-md: OK
resumir-docs-b-md: OK
resumir-docs-c-md: OK
resumir-docs-d-md: OK
resumir-docs-quebrado-md: FALHA: arquivo quebrado
Cuts: the user/sys lines from time. The time dropped from 10 s to 4 s because the fake agent only sleeps: it shows the shape of the gain, not the measurement of a real agent. In the third round, only the rejected item ran again.
feito Resuma-runtime-ROTEAMENTO-md-em-3-linhas
feito Resuma-runtime-POLITICA-md-em-3-linhas
itens: 2 · feitos: 2 · com erro: 0 · OK: 2 · FALHA: 0
(…)
Resuma-runtime-POLITICA-md-em-3-linhas: OK
Resuma-runtime-ROTEAMENTO-md-em-3-linhas: OK
Two claude -p in parallel, 48 s total, in the training project. The text of each summary stayed in real/saida/; two lines reached the orchestrator.
With TETO=1, no worker finishes: the timeout cuts them all with code 124 and the result goes to .erro, not to .md.
A cap is mandatory, but calibrated: run one real item alone, measure it, and leave some slack. Without a cap, one stuck worker holds up the whole batch.
04 · The delegation request
When the fan-out happens inside the session, you are the orchestrator, making the request. The four fields come from Anthropic's post.
Prompt · fan-out with subagents in one session
Split this into subagents, one per item in the list below, all in the same message.
For each subagent, write:
- Goal: <what this item needs to answer>
- Output format: at most 5 lines; last line OK or FALHA: <reason>; write to saida/<item>.md
- Sources and tools: <files or folders it may read>; do not edit anything outside saida/
- Boundary: do not handle the other items; if it depends on another item, stop and say which one
Then read only the last line of each file and give me the item → OK/FALHA table.
Items:
<item 1>
<item 2>
<item 3>
05 · Practice
Rehearsal first; then two real items.
E5 · Fan-out with a fake agent
10 min
Save fanout.sh and run the whole rehearsal.
Done when: the N=1 round takes about 10 s and the N=3 round about 4 s; both print OK: 4 · FALHA: 1; the third prints four pula … (aprovado) lines and one feito resumir-docs-quebrado-md.
E6 · Two real items
10 min
Run the real block (it uses claude -p, through your subscription). If an item comes out FALHA, read only its file and run fanout.sh again.
Done when:cat real/consolidado.txt shows 2 lines, each ending in OK or FALHA: …, and ls real/saida/*.erro finds nothing.
06 · Lesson quiz
Question 1 of 4
Why does the orchestrator read only the last line of each result?skill
Correct
It's the same principle as the subagent: the detail stays out. When it needs to, the orchestrator opens only the file of the failed item.
Not this one
It's the same principle as the subagent: the detail stays out. When it needs to, the orchestrator opens only the file of the failed item.Review: A fan-out with control
Question 2 of 4
What was missing from the request that made three Anthropic subagents repeat the same search?skill
Correct
With a vague request, each subagent interpreted it in its own way and the work was duplicated. The four fields split up the work.
Not this one
With a vague request, each subagent interpreted it in its own way and the work was duplicated. The four fields split up the work.Review: Fan-out in shell, with a rehearsal
Question 3 of 4
In the second round of fanout.sh, who runs again?
Correct
Approved items are not reprocessed. FALHA and .erro come back; this is the rule "only the failed one comes back" from the lesson 1 kit.
Not this one
Approved items are not reprocessed. FALHA and .erro come back; this is the rule "only the failed one comes back" from the lesson 1 kit.Review: Fan-out in shell, with a rehearsal
Question 4 of 4
Two teammates in an agent team need to edit the same file. What does the doc recommend?
Correct
Agent teams don't give each teammate a worktree: editing the same file overwrites it. Partition by owner, or isolation (lesson 5).
Not this one
Agent teams don't give each teammate a worktree: editing the same file overwrites it. Partition by owner, or isolation (lesson 5).Review: The forms of fan-out today
Quiz completed
You got {a} of {n} right. Get them all right and the lesson is marked as completed.
Choose one option. The explanation appears after your attempt.
07 · In three sentences
Frozen itemsOnly what doesn't depend on another item goes into the fan-out; the rest goes before or after.
Cap and fileEach worker with a timeout, a saved result, and a last line of OK or FALHA.
Only the failed one comes backThe orchestrator reads the last lines and reruns only what failed.