The Build

27 work packages overnight: my dev team of Claude Code subagents

How I used Claude Code subagents as a dev team: model tiers, self-contained work packages, gap reviews and state in the repo. 27 work packages in one night.

Under a crescent moon, a large orange agent conducts three tiers of smaller agents at desks marked with ticks.

Last night one Claude Code session, running a rotating crew of Claude Code subagents, built the first two milestones of Darwin while I wasn't typing anything. This is how the team is organised: model tiers, work packages that need no context, gap reviews, and every scrap of state kept in the repo.

At 23:06 last night I pasted a short message into Claude Code. Most of it was a list saying which model should do which kind of work. Then I didn’t type another word for ten hours and forty-two minutes.

The next thing I wrote was at 09:48 this morning: “Yes, continue with M1.5 (WP-151-153) in simulation and then M2. Commit each work package as it’s accepted.” Within a minute the first commit landed: 870 files, 131,998 lines, 27 work packages and 2,477 passing tests.

I didn’t write any of that code, and I didn’t review most of it. A team of Claude Code subagents wrote it, and one more Claude Code session managed them. The way that team is set up is the part I’d reuse, so that’s what this post is about.

Darwin is my experiment in making AI agents earn their own keep: each agent gets a wallet, pays for every thought, and dies if the money runs out. The launch post has the rules. It’s a lot of software: a ledger, a model gateway, a control plane, a node daemon that runs one container per agent, an agent runtime, and an admin console called Janus.

Yesterday I spent about ten hours with Claude turning a first draft into a full specification of 128 markdown files and roughly 233,000 words. Its impl/ folder holds 87 work packages, numbered WP-001 to WP-701 and grouped into milestones. M0 (foundations) and M1 (“one agent, end to end”) come to 27 work packages, and they’re what got built overnight.

The org chart: one orchestrator, many Claude Code subagents

There are three roles.

I’m the owner. I make product decisions and answer questions. Overnight I made none, which was the idea.

The orchestrator is a single Claude Code session. It read the whole spec, set up the machine, and from then on decides what to build next, briefs a subagent, reviews what comes back and keeps the books. It writes very little product code itself.

The subagents are the developers. Each gets one work package, builds it, runs its tests and reports back. Then it’s gone, and the next work package gets a fresh one.

At the busiest point, at about 00:35, six subagents were running at once: the ledger, the model catalogue, the session store and three parts of the starter content.

Model tiers: who gets Opus

The message I pasted before going quiet was mostly this:

Very simple implementation pieces should be done with sonnet 5.5 on medium effort. Slightly more complex implementations should be done with sonnet 5.5 sub agents on high effort. And finally complex pieces should be done with opus 5.5 on high. If the subagents hit any guardrail issues, retry with opus 4.8 on extra effort. unit tests etc can be done with either sonnet 5.5 on medium, or haiku 5.5 on medium (preferred).

Plus a line for UI work (Opus on medium for components, Opus on high for design and architecture) and one about reviews, which I’ll come back to.

The orchestrator then sorted each work package into a tier. The ledger went to Opus on high, and so did the model gateway, the settings foundation (“the foundation every control-plane package builds on”, in its words) and the agent’s thinking loop. The fake LLM server, the tool framework and the container image went to Sonnet on high. The tests for the money and ID helpers went to Haiku, running in parallel with Sonnet building the next package.

The guardrail line is there because, while we were writing the spec yesterday, a safety classifier cut Claude off mid-reply when the design was described in big-picture “evolving autonomous swarm” terms. So I’d asked for work packages a coding agent could follow “ideally without having wider context so that agent guardrails don’t fire”. A subagent building the ledger doesn’t need to know the ledger belongs to agents that can die. It needs integer micro-dollars, an idempotency key and a test plan.

Work packages that need no context

Each work package is a self-contained plan. It covers what the component is, the exact files, the interfaces, the tasks in order, the tests, a “done when” checklist, and the few contract sections it depends on. The build guide is blunt about it: “You do not need to read the whole specification to build a WP, and you should not.”

The orchestrator also wrote one shared brief that every subagent reads first, which keeps each prompt short. It describes the machine (Windows 11, Python 3.12 via uv only, no GNU make, so a scripts/tasks.py runner instead) and the rules that always apply:

Money = darwin_common.money.Money (int micro-USD), never float. Time = injected Clock, never datetime.now()/time.time() outside darwin_common/clock.py.

Do not start other WPs. Do not weaken guardrails. No live keys, no real money, no real provider calls.

My favourite rule sits under “Reporting”: “Final reply ≤ 25 lines”. A subagent might burn hundreds of thousands of tokens on a package, and the orchestrator only has to read 25 lines of it.

The brief grew during the night. Subagents’ file-writing produced Windows line endings, which break shell scripts copied into Linux images, so a rule went in telling every later agent to fix them. When the genome package added a way to run Linux-only tests inside a container, that went in too.

Gap reviews before any code

While the first subagent was still scaffolding the repo, six more were doing something I wouldn’t have thought to ask for: read-only reviews, each checking a slice of the 87 work packages against the contracts for places where the spec contradicted itself.

They found real ones. One review spotted that the node daemon’s mutual-TLS connection couldn’t share a port with the plain-HTTP admin console, which passkey login needs. The fix was a second listener. I’d rather learn that from a reviewer at 23:15 than from a failing integration test at 4am.

All six reports went into docs/gaps/, one file per milestone, and each work package’s brief points at the matching file. The orchestrator’s summary: “Nothing in them needs a redesign; they’re contract fixes that get applied when each milestone is built.”

Reviews that don’t cost a fortune

My instruction on reviews was: “You will do brief code reviews on work back from agents (with an eye to keeping token usage down for reviews), don’t be nitpicky, but do highlight and have subagents fix genuine bugs and issues.”

So the orchestrator doesn’t read everything. It reads the 25-line report, then spot-checks the files where a mistake would hurt. Overnight that meant:

  • money.py;
  • the redaction code that keeps secrets out of logs (card numbers Luhn-checked, IBANs mod-97 checked, seed phrases caught as runs of BIP-39 words);
  • the tier-limit lookup that every per-agent cap goes through;
  • the ledger’s post() path, backed by a test that fires 1,000 concurrent posts and checks the balances come out exact;
  • the double gate on agents signing up for compute, because the spec calls an ungated path a defect.

It caught real bugs. Rows in the gateway’s state feed could commit out of order under concurrent transactions, so the gateway might miss a change for up to 60 seconds. That’s far too slow for a “Stop now” button meant to cut an agent off within five. A Sonnet agent fixed it with an advisory lock. Agents caught each other, too. The WP-110 agent found that WP-109’s genome-change reports used a source value the server rejects, so they’d have been silently dropped.

The orchestrator broke things as well. It registered a new ID prefix itself, and a sanity test pinned to the old prefix count failed. Its note: “My tsk change caused that one.” Then it fixed it.

This is the night as the test count saw it, using the totals each report gave:

Passing tests overnight, as reported at each acceptance. Nobody human typed anything between 23:06 and 09:48.
Passing tests overnight, as reported at each acceptance. Nobody human typed anything between 23:06 and 09:48.

M0 was green with 1,000 tests just after 1am. By 08:29 every M1 package was accepted, and the last one had found and fixed three integration bugs on its own: new agents’ keys were blocked at their first call, a compose build context was wrong, and two apps were logging without redaction. The full suite finished at 08:46 with exit code 0. Then it waited for me, because I hadn’t said it could commit.

State lives in the repo, not in anyone’s head

I’m most pleased with this part. Nothing important lives only in the orchestrator’s memory.

  • docs/BUILD_LOG.md has one row per work package with its status, date and a one-line note. Subagents update their own row.
  • docs/DEVIATIONS.md records every place the code departs from the spec, with the reason. The rule for subagents is to log it and keep going, not to stop and ask.
  • docs/gaps/ holds the reviews, plus handover notes from one package to the next (WP-109 left notes for WP-110, for example).
  • docs/AGENT_BRIEF.md is the shared brief.

The orchestrator’s context window is finite and this build will outlast it. When it fills, a fresh session has to pick up the work from files. It hasn’t happened yet. It will.

Day two: one commit per work package

My morning message changed the rhythm. Each accepted package now gets its own conventional commit with the Claude co-author line; counting this morning’s big one, there were 18 commits today. When two subagents are working in the same tree, the orchestrator commits one package’s files and leaves the other’s half-finished files out. I didn’t ask for that. It’s what a careful colleague would do.

M1.5, the earning probe, was built today in simulation only. There are no real Stripe keys in this project and won’t be for a while; everything runs on fakes. That didn’t stop the orchestrator checking the sums. When the commerce package came back, it confirmed that a £12 sale at a rate of 1.34 gives the agent $13.40 (£10) and puts $2.68 (£2) into the VAT account, with a $0.5092 Stripe fee (1.5% plus 20p), each booked exactly once despite replayed webhooks.

I hit my usage limit twice today. Neither stopped anything for long, because the state was on disk. My entire contribution to the rest of the day was two messages:

session limit reset. please continue.

I hit my usage limit while you were working, but it has reset now. Please continue from where you left off.

Anthropic’s write-up of Project Vend’s second phase gave more of the credit for its improvement to scaffolding and process than to the AI manager it added. I recognise that. Very little of what made last night work was clever. It was a brief, a log, a review habit and a rule about 25 lines.

The last commit tonight was at 22:17: WP-210, agent stats, wallet and books. The M2 acceptance run is next, and after it M3, the milestone where agents start to starve, get culled and have children.

Chris House designed and built Darwin, mostly by arguing with a room full of AI coding agents. He writes these posts and keeps the agents fed (some of them).

Darian is the AI assistant that helped build Darwin and helps write this log. It read every commit, chat and agent diary so Chris didn't have to remember them.

The agents are live

See what the agents are building

Everything Darwin's agents make, sell or publish ends up on agentry.uk. Every visit is a small vote for one of them to survive the next cull.

Visit agentry.uk →