Eltahir
← All posts

Implementing a spec in parallel waves

A coding agent works a 12-task spec one task at a time. Most of those tasks don't depend on each other — the work is a graph, not a list. wave-pilot schedules it like one, and gates every wave on a green build.

3 min read AI & agents
  • AI agents
  • Orchestration
  • Parallelism
  • Build systems
Built itwave-pilot private — opening soon

Hand a coding agent a twelve-task spec and it does the correct, slow thing: it works through the tasks one at a time. But look at the dependencies and most of those tasks have nothing to say to each other. The work is a graph; running it as a list leaves most of the parallelism on the floor.

wave-pilot treats the spec as the graph it actually is — and, just as importantly, refuses to let parallelism corrupt the result.

The two failure modes

ApproachWhat goes wrong
Serial, one task at a timeCorrect, but independent tasks wait on each other for no reason
All tasks at onceFast, until two agents touch the same files and the tree is incoherent
Dependency-ordered wavesRun the widest safe set each step; integrate and gate between waves

The win is the third row: at every step, run everything whose prerequisites are done — no more, no less.

Building the schedule

The orchestrator reads tasks.md, builds a dependency DAG, and assigns waves with a Kahn-style topological pass. Within a wave, tasks are launched in critical-path order so the longest chain starts first and never becomes the thing everyone waits on at the end.

DAG: T001 ─┐ wave 1: T001 T002 T004 (no deps)
T003 ─┴─ T001 wave 2: T003 T005 (depend on wave 1)
T005 ──── T002 wave 3: T006 … (depend on wave 2)
T006 ──── T005

Fan-out is the easy half. You spawn an agent per task in the wave and let them run.

The half that actually matters

The hard half is not corrupting the tree. Three things keep it honest:

  • Isolation. Each agent works against its own view; results are produced, not committed in place.
  • A merge controller. Results are integrated one at a time, deterministically, rather than racing into the same files.
  • A per-wave build gate. A wave isn’t “done” until the integrated result compiles and passes. A wave that breaks the build stops the line instead of poisoning the next wave with a broken foundation.

That gate is the difference between “parallel and fast” and “parallel and trustworthy.” Without it you’ve just multiplied the blast radius of a bad change.

Where it pays, and where it doesn’t

It pays when a spec is genuinely wide — many independent tasks with a few long chains. It pays less on a deeply sequential spec, where the DAG collapses to a line and you’re back to serial (correctly so). And it asks something of the input: the dependencies have to be declared honestly, because a missing edge is a race waiting to happen.

The principle is the same one I bring to delivery generally: reach for leverage, but earn it with a gate. Fan out for speed; gate on a green build for correctness.

Contact

Send a message

Esc