On this page · 6 min
You give one coding agent a large question and then watch it work the pieces in order. Sub-problem one, then two, then three. By the time it reaches the part you actually cared about, most of its context window is full of detail from parts it already settled, and every step has spent its life waiting on the step before it.
Plenty of questions do not deserve that. Size the market for on-device speech models, survey the strongest open-source ones, list the risks that would kill the bet: none of those three needs an answer from the other two. Research all three at once and read the answers side by side.
That is a swarm. Splitting the question is the easy half. The hard half is giving every worker somewhere real to work.
A worker needs a whole machine
An agent that can only read and write text is a chat window. The agent you actually want installs a package, runs the test suite, reads the stack trace, and tries again. That one needs a computer, not a prompt.
On boxd every worker gets one. A full Linux machine, its own disk, its own shell. Claude Code, Codex, and OpenCode ship inside the image and are already logged in on every machine you own, so a worker is one exec call away from real work with nothing to install first. See Coding agents.
Machines boot in 4 to 6ms and cost near zero while idle. That number is most of the argument. At single-digit milliseconds, creating a machine stops feeling like provisioning and starts feeling like calling a function, and once it feels like calling a function you stop rationing workers.
The shape of a run
Every swarm has the same five steps.
- The coordinator defines the sub-tasks. The coordinator is your script, or an agent sitting on a boxd machine.
- It creates one machine per worker, fresh or forked from a warm baseline.
- Each worker runs a coding agent headless inside its machine, and the output comes back through
exec. - A lead step reads every report and writes the synthesis.
- The coordinator destroys the workers, and the fleet goes back to zero.
| Stage | What happens |
|---|---|
| Fan out | The coordinator creates one machine per lens |
| Work | A coding agent runs headless inside each worker |
| Collect | Each report comes back as the exec result |
| Synthesize | A lead machine reads all reports and writes one answer |
| Teardown | The coordinator destroys the workers, and the fleet is gone |
Three scouts and a lead
Here is the whole pattern, short enough to read in one sitting. Three scouts research one question through three different lenses. A lead agent then reads all three reports and writes a single recommendation.
from concurrent.futures import ThreadPoolExecutor
from boxd import Boxd
LENSES = {
"market": "Size the market for on-device speech models. Write a compact report.",
"tech": "Survey the strongest open-source on-device speech models. Write a compact report.",
"risks": "List the main risks of betting on on-device speech models. Write a compact report.",
}
boxd = Boxd() # reads BOXD_API_KEY; authenticates automatically inside a VM
def scout(name: str, prompt: str) -> str:
machine = boxd.machines.create(name)
boxd.machines.wait_until_ready(machine.id)
result = boxd.machines.exec(
machine.id,
f'claude -p "{prompt}" --dangerously-skip-permissions',
timeout=600,
)
boxd.machines.delete(machine.id)
return result.stdout
with ThreadPoolExecutor() as pool:
reports = list(pool.map(
lambda kv: scout(f"scout-{kv[0]}", kv[1]), LENSES.items()
))
# Lead agent: one more machine reads every report and merges them
lead = boxd.machines.create("lead")
boxd.machines.wait_until_ready(lead.id)
boxd.machines.files.upload(lead.id, "/home/boxd/reports.md", "\n\n---\n\n".join(reports))
final = boxd.machines.exec(
lead.id,
'claude -p "Read /home/boxd/reports.md and write one recommendation." '
"--dangerously-skip-permissions",
timeout=600,
)
print(final.stdout)
boxd.machines.delete(lead.id)Read scout twice, because it carries the whole idea. It creates a machine, runs an agent inside it, deletes the machine, and returns a string. A worker lives exactly as long as its task. The TypeScript SDK, @boxd-sh/sdk, has the same shape with waitUntilReady and Promise.all.
The lead is not a special kind of thing. It is a fourth machine with a different prompt, reading a file the way a person would. (If that feels anticlimactic, good. Most of what gets built at this layer turns out to be a file and a prompt.)
Notice the timeout on every exec. A worker that hangs hands back an ended call instead of holding the whole run open, which is the difference between a swarm you can put on a schedule and a swarm you have to sit and watch.
When workers need to talk
Reporting back at the end is the easy case. Some swarms need shared state while they run: a task queue, a scoreboard, a database every worker writes to.
Inside any of your machines, <vmname>.boxd resolves to that machine's private IP. Run the shared thing on one machine and let the others find it by name.
curl http://coordinator.boxd:8000/next-task
psql -h shared-db.boxd -U postgresName resolution is private to your account, and only machines you own resolve. Which means the shared queue is ordinary software on an ordinary host at a stable name. When it misbehaves you connect to that host and look, instead of reading someone's control plane logs.
See VM to VM.
The coordinator can be a machine too. Every boxd VM carries the in-VM boxd CLI and the SDKs, pre-authenticated as your account, so an agent inside one machine can spawn siblings, hand them work, and clean up after them. The script above runs unchanged on a boxd machine, where Boxd() needs neither a key nor any configuration.
Keep independent work independent
Two scouts that can read each other's notes have stopped being two independent attempts. And a worker running code it generated itself should not be able to reach its siblings at all.
Networks partition the swarm. Give the coordinator every job network, and give each worker only its own.
boxd machine new coordinator --networks=job-1,job-2,job-3
boxd machine new worker-1 --networks=job-1
boxd machine new worker-2 --networks=job-2
boxd machine new worker-3 --networks=job-3Each worker now reaches the coordinator and nothing else. For untrusted work, create workers with --isolated: they reach nothing of yours beyond networks you grant explicitly. See Sandboxes.
Warm starts and the bill
A fresh machine is generic, which is fine for a scout that needs a model and a shell. It is wrong for a worker that needs your repo, your dependencies, or a model already resident in memory.
Set that baseline up once, then call boxd.machines.fork("baseline", name) per worker. Each fork lands in 100 to 200ms with the baseline's disk and memory intact, so the worker wakes up already inside your world. For a baseline that outlives the machine and stays versioned, use a golden image. For identical starting states across many runs, see Reproducible RL environments.
Destroy workers when their task ends, because a removed machine costs nothing. Workers you keep for the next batch suspend and hibernate on their own, then wake on the next request.
One number to plan around: accounts start at 50 concurrent machines. The cap is extendable on request, and the coordinator counts toward it. See Resources and limits.
Where a swarm is the wrong tool
We would rather you skip this pattern than be disappointed by it, so here is the honest part. A swarm pays off only when the sub-tasks are genuinely independent. If worker two needs worker one's answer, you have a pipeline, and running a pipeline as a swarm buys you three copies of the same wrong guess.
The synthesis step is the real difficulty, and parallelism does nothing for it. Three confident reports that contradict each other still need someone to decide which one is right. Sharpening the lead prompt is almost always worth more than adding a fourth scout.
And you pay per worker. Ten agents thinking at once cost ten agents' worth of tokens, whatever the machines underneath cost. Parallel is faster. It is not cheaper.
Try it with three
Take a question you would normally hand to one agent. Split it into three lenses that do not depend on each other, drop your own prompts into the script above, and run it. If the three reports disagree somewhere you did not expect them to, the swarm has already earned its keep.



