5 · Orchestration — Scaling Yourself¶
Once you can drive a single agent well, your own attention becomes the bottleneck. One person can only follow so many tasks at a time. This module is about lifting that limit by running more than one agent at once without losing control, which is the shift from doing the work to leading it.
Orchestration has a few parts: isolated workspaces so parallel agents don't collide, sub-agents and teams for divisible work, and background or scheduled agents for work that doesn't need you watching. The catch is that orchestration multiplies your output and your blast radius at the same time, so everything from Module 3 is a prerequisite. You cannot review what you can't see, and you can't run four agents that each need babysitting.
Parallelism pays off only when the work is divisible and isolated. Give each agent its own workspace (a worktree), a clear slice, and a way to verify itself — then your job is review and integration, not typing. If the slices touch the same files or you have to watch each one, you don't have parallel work; you have one serial task with extra overhead.
Concept¶
-
Isolation first — the worktree. Two agents editing the same checkout corrupt each other's work. A
git worktreegives each agent its own directory on its own branch off the same repo, so they can run truly in parallel and you merge the results like any other branches. Isolation is the precondition rather than a nicety: without it, "parallel" agents just race. Use one worktree per agent, and integrate by reviewing and merging each branch. -
Divisibility — slice so the pieces don't talk. Good parallel work splits into chunks that don't depend on each other mid-flight. Adding the billing-category eval cases and adding the retrieval timeout are independent; refactoring the classifier and refactoring the thing that calls the classifier are not, since they will fight over the same interface. If you can't name the seam cleanly, the work is serial. Cut along seams the codebase already has, such as files, modules, and layers.
-
Sub-agents versus a team. These are two different shapes.
- Sub-agent (fan-out under one driver). One lead agent spawns helpers for parallelizable sub-tasks, such as searching six directories or verifying each of a set of findings, and collects their results. You talk to the lead; the helpers are its tools. This suits divide-and-gather work: search, review, broad edits.
- Team (peers with roles). Several agents with distinct standing jobs, such as a writer, a reviewer, and a tester, pass work between them. This suits work that has genuinely different kinds of step rather than more of the same.
-
Named multi-agent patterns. When you do run several, you are choosing a topology. The useful ones are these.
- Orchestrator–worker. One coordinator splits the task, hands slices to workers, and integrates results. This is the default, and the one to reach for first.
- Handoff. Agent A finishes its phase and passes the baton to B (plan, then implement, then verify). This is a pipeline rather than a parallel fan-out.
- Hierarchical. An orchestrator of orchestrators, for work too big for one coordinator's context. It is powerful and easy to over-build, and most tasks don't need it.
- Blackboard (shared memory). Agents read and write a shared scratch space, such as a file or a doc, instead of messaging directly. This is useful when many agents contribute to one evolving artifact.
The four differ in how work and results flow between agents — a fan-out and gather, a baton pass, a tree, or a shared space:
flowchart TB subgraph OW["Orchestrator–worker (default)"] direction TB o(["Orchestrator"]) --> w1["Worker"] & w2["Worker"] & w3["Worker"] w1 & w2 & w3 -.->|"results"| o end subgraph HO["Handoff (pipeline)"] direction LR p["Plan"] --> i["Implement"] --> v["Verify"] end subgraph HI["Hierarchical"] direction TB t(["Top orchestrator"]) --> s1(["Sub-orchestrator"]) & s2(["Sub-orchestrator"]) s1 --> hw1["Worker"] s2 --> hw2["Worker"] end subgraph BB["Blackboard (shared memory)"] direction TB sh[("Shared scratch space")] b1["Agent"] <--> sh b2["Agent"] <--> sh b3["Agent"] <--> sh end %% invisible links force a 2x2 grid so the four stay large and readable OW ~~~ HI HO ~~~ BBStart with orchestrator–worker. Reach for the others only when the task's shape demands it; extra agents are extra coordination cost rather than free horsepower.
-
Background and scheduled work — getting out of the loop. Not all parallelism happens in real time. An agent can run in the background, where you keep working and it pings you on completion, or on a schedule, as a recurring job that triages new tickets each morning or sweeps for failing evals nightly. The skill here is the inverse of driving: you are not watching, so the work must be able to verify itself and report. This is exactly the Module 3 machinery, now load-bearing.
-
Observability — you can't lead what you can't see. The instant you stop watching each keystroke, you need a way to see what each agent did: which files it touched, which commands it ran, where it stalled, and what it cost. A diff per worktree, a log per agent, a status line. Without it you are not orchestrating, you are hoping. Set up the view before you scale up, not after something goes wrong.
For orientation rather than adoption, it's worth knowing the framework landscape. You'll hear about LangGraph, AutoGen, CrewAI, the OpenAI Agents SDK, and the Claude Agent SDK. They encode the patterns above, such as graphs, roles, and handoffs, so you don't hand-roll the plumbing. Know they exist and what shape they impose, and don't adopt one because it's loud. The patterns are the durable knowledge; the frameworks are this year's packaging of them. Pick one when a real project needs the plumbing, not before.
One serial task vs. three parallel agents — when it's worth it¶
Same goal in Triage — "add billing-category support: eval cases, a tuned prompt, and a retrieval filter."
When this wins: the three pieces share an interface and inform each other (the prompt depends on what the eval reveals). Coordination cost is zero. For tightly coupled work, running serially is the correct choice rather than a slow one.
worktree-a: add billing cases to eval/ (independent)
worktree-b: add a retrieval timeout + filter (independent)
worktree-c: docs + CLAUDE.md update (independent)
You review three diffs and merge.
When this wins: the slices are genuinely independent and each can self-verify (a is gated by the eval, b by a test). Wall-clock drops to the slowest slice. You spend your time on review and integration — the tech-lead job.
worktree-a: refactor classify.py
worktree-b: refactor draft.py, which imports classify.py
→ both edit the shared interface, both branches conflict, you spend longer
merging than the work would have taken serially.
Why it fails: the slices weren't independent. You paid the coordination cost and got merge conflicts instead of speed. When the work isn't divisible, don't parallelize it.
Guided Lab¶
The Practice Repo slice for this lesson is pending. The Triage steps below are a walkthrough for practicing the slicing decision and worktree mechanics; they are not yet backed by a dedicated answer key. Treat your own codebase as the primary hands-on path for this module until the orchestration slice lands.
On the Practice Repo, clone Triage.
- Slice it. Take the billing-category task and write down three slices that don't share a file. If you can't, that's the lesson: pick a different task or admit it's serial.
- Isolate and run. Create a worktree per slice (
git worktree add ../triage-a -b billing-evals, etc.) and run one agent in each, each told to self-verify (run the eval or the test) before declaring done. - Review and integrate. Read the three diffs, merge the clean ones, and reconcile any overlap. Notice where your time actually went: review and integration, not typing.
- Out of the loop. Run one of the agents in the background and confirm it reports back having passed its own check, without you watching it.
On your own codebase, find one task you'd normally do serially that actually has two independent seams. Run it as orchestrator–worker across two worktrees. Separately, set up the observability you'd need to trust a background agent: how would you see, after the fact, exactly what it did?
Keep the artifact¶
From this lesson:
- a reusable worktree-per-agent workflow (a tiny script or
CLAUDE.mdnote: how you spin up, name, and tear down isolated agent workspaces), - a slicing checklist, the two questions you ask before parallelizing (divisible? isolated?), and
- a background or scheduled job (for example, a nightly eval sweep on Triage) that self-verifies and reports.
The worktree workflow and the slicing checklist are the parts you'll reuse on every multi-agent task. Banking them is the compounding move of Module 6.
Self-check¶
You did it right if:
- two or more agents produced independent, non-conflicting changes you integrated cleanly, and you can point to the seam that made them independent;
- your time went to review and integration, not to writing code or babysitting; and
- the background agent reported a self-verified result without you watching.
If the branches fought at merge time, the work wasn't divisible, and no better tooling would have changed that.
Recall¶
Before moving on: what two properties must work have before parallelizing it across agents is worth the overhead, and what's the tell that it lacks them?
Answer
It must be divisible (slices that don't depend on each other mid-flight) and isolated (each agent in its own workspace, e.g. a worktree). The tell that it lacks them: you can't name a clean seam, or the branches conflict at merge, meaning the slices shared an interface and the work was serial all along.