Chapter 7 of 8
Orchestrating a fleet
One agent is a worker. An orchestrator is the agent that runs a team of them. The pattern is four beats: decompose a goal into independent workstreams, fan out those workstreams to worker agents, verify each worker's output, and synthesize the verified results into one answer. Each worker is typically a subagent invocation, so this composes directly with the delegation you learned. The beat that separates a working fleet from a broken one is concurrency control. Firing a hundred agents at once trips short-window throughput limits and melts your throughput, so a fleet runs in BOUNDED WAVES, never more than a fixed cap of workers at a time, chunking a big job into waves of that size. In this lab an orchestrator splits a ten-item job, runs it in waves of at most three, verifies every worker output before accepting it, and synthesizes a final tally, proving all ten completed, every wave respected the cap, and the synthesis is correct.
The lab: read it, then run it
#!/usr/bin/env python3
"""
LAB CC7: Orchestrating a fleet. Decompose, fan out in bounded waves, verify.
One agent is a worker. An orchestrator is the agent that runs a team of them. The
pattern is four beats: DECOMPOSE a goal into independent workstreams, FAN OUT the
workstreams to worker agents, VERIFY each worker's output, and SYNTHESIZE the
verified results into one answer. The catch is concurrency: firing a hundred
agents at once trips rate limits and melts throughput, so a fleet runs in BOUNDED
WAVES, never more than a fixed cap of workers at a time. In this lab an
orchestrator splits a ten-item job, runs it in waves of at most three, verifies
every worker output before accepting it, and synthesizes a final tally, proving
all ten completed, every wave respected the cap, and the synthesis is correct.
Reference (real Claude Agent SDK: each worker is a subagent invocation via the
Agent tool; the executed lab simulates the fleet offline and deterministically):
agents={"worker": AgentDefinition(description=..., prompt=..., tools=[...])}
Run: python3 modules/academy-content/labs/claude-code-agents/cc7-fleet.py
"""
import sys, os
_cands = [os.path.join(os.path.dirname(__file__), "..") if "__file__" in globals() else None,
os.path.join(os.getcwd(), "..", "labs"), os.path.join(os.getcwd(), "labs")]
for _c in _cands:
if _c and os.path.exists(os.path.join(_c, "academy_llm.py")):
sys.path.insert(0, os.path.abspath(_c)); break
from academy_llm import complete
# The job: classify ten reviews. Each is an independent workstream.
JOB = [
"I love it", "this is terrible", "great product", "worst ever, broken",
"excellent and fantastic", "awful and useless", "the best, amazing",
"boring and slow", "wonderful, recommend", "disappointing, poor",
]
CAP = 3 # bounded waves: never more than this many workers at once
def worker(item):
"""One worker agent: classify a single item. Returns its result."""
return complete(f"sentiment: {item}")
def verify(item, result):
"""The orchestrator checks each worker output before accepting it."""
return result in ("positive", "negative", "neutral")
def waves(items, cap):
"""DECOMPOSE into bounded waves of at most `cap` items each."""
return [items[i:i + cap] for i in range(0, len(items), cap)]
# ── Orchestrate: run wave by wave, verify each output, synthesize. ──────────────
print(f"job has {len(JOB)} items, wave cap = {CAP}")
print("")
verified = []
wave_sizes = []
for w, batch in enumerate(waves(JOB, CAP), 1):
wave_sizes.append(len(batch))
print(f"wave {w}: {len(batch)} workers")
for item in batch: # FAN OUT across the wave
result = worker(item) # a worker agent runs
if verify(item, result): # VERIFY before accepting
verified.append(result)
# SYNTHESIZE: one tally from all verified worker outputs.
summary = {
"positive": verified.count("positive"),
"negative": verified.count("negative"),
"neutral": verified.count("neutral"),
}
print("")
print(f"wave sizes : {wave_sizes}")
print(f"synthesis : {summary}")
all_done = len(verified) == len(JOB)
cap_respected = all(s <= CAP for s in wave_sizes)
correct = summary == {"positive": 5, "negative": 5, "neutral": 0}
print("")
print(f"all items completed and verified : {all_done}")
print(f"every wave respected the cap : {cap_respected}")
print(f"synthesis tally is correct : {correct}")
ok = all_done and cap_respected and correct
print("")
print(f"FLEET COMPLETED ALL TASKS IN BOUNDED WAVES: {'YES' if ok else 'NO'}")
if not ok:
sys.exit(1)
print("Decompose, fan out, verify, synthesize. Next: the complete workflow.")
Runnable lab
cc7-fleet.pyOrchestrate a ten-item job in bounded waves, verify each output, and synthesize a correct tally.
Proves: FLEET COMPLETED ALL TASKS IN BOUNDED WAVES: YES
Runs in your browser via Pyodide. First run loads the runtime once; no install, no server.
The orchestrator broke the job into waves of three, ran ten workers across four waves without any wave exceeding the cap, verified every output before accepting it, and synthesized a correct tally. That is the shape of every fleet you will run: decompose, fan out in bounded waves, verify, synthesize. Two rules carry into real work. Cap the concurrency, a wide fan-out is tempting but a burst of agents trips the same short-window throughput throttle that punishes any big parallel run, so default to modest waves and only go wider deliberately. And verify each output before you trust it, because an unchecked worker result is how a bad answer slips into the synthesis. Next you assemble everything into one complete workflow.
Check your understanding
1. What are the four beats of orchestrating a fleet?
2. Why does a fleet run in bounded waves instead of firing every agent at once?
3. Why verify each worker output before synthesizing?