18 days, 136 commits, 5,096 tests: what Claude Code subagents taught me
A retrospective on building Darwin with Claude Code subagents: 18 days, 117 work packages, 5,096 tests. What worked, what didn't, and what I'd change.
Darwin's build phase is done: 117 work packages, 136 commits and 5,096 passing tests in 18 days, written by Claude Code subagents and managed by one Claude Code orchestrator. Spec-first work packages, fakes and state kept on disk all paid off. What hurt was using a laptop as CI, questions I couldn't parse, and parallel agents fighting over one machine. None of it has met the real world yet.
At 00:50 this morning the last feature milestone was accepted. The full test suite had taken 3 hours 59 minutes: 5,096 passed, 8 failed. Seven of the failures were stale tests that hadn’t kept up with the code, fixed and re-run. One was a timing flake. The security suite passed 472 tests in each of four guardrail configurations.
The report ended with a request for me:
The four Python processes using high CPU are still running. End them in Task Manager when convenient; they slow test runs.
Sixteen days ago one of its subagents killed every Python process on this laptop and was banned from doing it again. Now it asks me. I’m counting that as growth.
This afternoon WP-601, the single-host production setup, was verified in test mode on Docker Desktop and committed. That ends the laptop phase of building Darwin with Claude Code. Next it has to run somewhere real, so this is a good moment to write down what 18 days of Claude Code subagents taught me.
The numbers behind building Darwin with Claude Code subagents
Darwin is my experiment in AI agents that must earn their own keep: a ledger, a metered model gateway, one container per agent, culls, an AI appeals judge and an owner console called Janus. The architecture tour has the full picture. In raw numbers, as of tonight:
| Calendar days, spec to WP-601 | 18 (16 Oct to 3 Nov) |
| Days with commits | 12 |
| Commits on main | 136 |
| Work packages done | 117 (2 still marked todo) |
| Python, including tests | about 343,000 lines |
| TypeScript (mostly Janus) | about 86,600 lines |
| Database migrations | 64 |
| Logged deviations from spec | over 900 |
| Full suite | 5,096 passing, about 4 hours on the laptop |
| Security suite | 472 tests, run under 4 guardrail profiles |
| Janus tests | 385 unit, 165 browser |
| Real money moved | none |
The two packages still marked todo are WP-405, which turned out to be covered by another package, and WP-701, for running 3,000 agents across many hosts. Nobody needs that yet.
The spec that drove all of it was written on day one: 128 markdown files, about 233,000 words, 87 work packages, plus 21 more added in a patch on 23 October.
Milestone by milestone:
| Milestone | What it added | Accepted | Suite at acceptance |
|---|---|---|---|
| M0 + M1 | Foundations, one agent end to end | 17 Oct | 2,477 |
| M1.5 | Earning probe (simulation only) | 17 Oct | n/a |
| M2 | Control plane and Janus | 18 Oct | 2,955 + 73 browser tests |
| M3 | Life, death, reproduction, culls, appeals | 19 Oct | 3,502 |
| M3.5 | Agent substrate: self-editing harness, mail, sub-agents, browser | 25 Oct | 4,313 |
| M4 | Money rails | 27 Oct | 4,623 |
| M4.5 | Compute broker | 31 Oct | 4,923 |
| M5 | Egress logs, flags, security suite, backups | 2 Nov | security 365 + 37 Linux |
| M5.5 | Owner toggles and guardrail switches | 3 Nov | 5,096; security 472 × 4 |
| M6 (WP-601) | Single-host production, test mode | 3 Nov | 51 deploy tests |
Darian pulled those per-day counts out of git, and they show the shape of the build better than any summary: bursts of 15 to 19 commits a day, then nothing. The first gap was a pause after M3, which ended with me deciding the agents weren’t capable enough and asking for the M3.5 patch. The second was the weekly usage limit.
What worked: spec first, then work packages a subagent can finish alone
The best decision was spending day one on the spec, with Claude arguing with me about it. Its review found that my first selection design would have bred lazy agents. That’s cheap to fix in a markdown file and expensive to fix in a database schema.
The spec was then cut into work packages that a coding agent could follow without the big picture: exact files, interfaces, tasks, tests and a “done when” list. Every subagent read the same short brief first (integer micro-dollars for money, an injected clock, no live keys, report back in 25 lines or fewer), then its own package. The post about the first night covers this in detail, including the 27 packages built while I wasn’t typing.
Before each milestone, read-only agents compared its packages with the code that already existed and wrote a gap review. Those reviews became the place where my decisions got batched. Instead of a stream of interruptions, I got one document per milestone with a handful of real choices in it. For the compute broker, for example: “Stop and freeze” for the kill switch, the platform builds every image, and brokered data and SaaS purchases cut entirely.
What worked: fakes first, and state on disk
Every integration was built as an interface, then a fake, then the real thing. Stripe, mail, cloud compute and model providers all have fakes, and the default configuration runs on fakes only. So the whole system could run end to end before a single real key existed.
The simulation runs 20 agents over 7 accelerated days through the real control-plane code. At M3 it produced 4 starvation deaths, 17 children, and one cull in which 6 idle agents were condemned and 3 reprieved on appeal. It also checks that money and VAT still balance after every new feature. Once it was made deterministic (same seed, byte-identical output), it became a proper regression test rather than a mood ring.
The orchestrator’s context ran out seven times. Each time a fresh session started from a summary and carried on, because nothing important lived only in the conversation:
- per-package status in
BUILD_LOG.md; - every departure from the spec, with its reason, in
DEVIATIONS.md(the subagent rule was to record the deviation and keep going, which is how that file passed 900 rows); - decisions in
docs/gaps/; - progress notes in Claude’s memory files.
Acceptance reports helped too. Each milestone has one, with exact counts, durations and a “not verified” section. The M5.5 one includes a sentence I’ve come to value: “Every exit code was written straight from the command.” That habit came from an earlier run where the orchestrator piped the output through tail, which hid a failing exit code.
What didn’t: one laptop doing everything
The full suite takes about four hours on my laptop, and that shaped everything. On 26 October, after a session died mid-acceptance and took 48 background shell tasks with it, the orchestrator proposed resuming a four-hour run. I said:
do we really need to do this set of tests now? 4 hours is a long time.
It agreed, cut the run to the checks the last full suite hadn’t covered, and started again. Two minutes later I typed “still running? just got a crash warning”, and then “crash was due to memory issues on this machine, should be sorted now”. After that, acceptance stopped being a job for an agent and became a 12-step script that logs each step and can resume from the one that was interrupted.
Docker Desktop doesn’t start on its own after a reboot, and twice an acceptance run failed every Docker step because of it. The security suite has only ever run on Windows, plus a 37-test Linux subset. A real Linux CI box from the start would have saved me days.
Parallel subagents are fast until they share something. They shared CPU (the ten-hour stall), processes (the taskkill) and files. When three parallel packages edited the same files, the orchestrator committed them as three commits split by file, and said plainly in the messages that only the last one would build on its own. Honest, but not what one commit per package was meant to give me.
What didn’t: questions I couldn’t answer
The orchestrator asks good questions in a format I sometimes couldn’t parse. On 1 November I copied one of them into a fresh Claude session with the note “don’t understand this question i’ve been asked”. It was about an AI classifier, the egress proxy and backups. The next day, a question about a per-agent dashboard kept framing the feature as something Janus would refuse or that might mislead. I replied: “What? I don’t understand… why is janus refusing?” Then: “why can’t we just build the intent?” It was built as a read-only page with scoped tokens.
Both times the AI was being careful, and both times the care cost more than it saved, because I couldn’t make the decision. A question for a human should say what’s being decided, what it recommends and what happens if I say no, in words I’d use myself.
The guardrails had a version of the same problem. On 31 October I asked it to “ease up on it”, and the guardrails post covers where that landed.
The orchestrator slipped in more ordinary ways too. Committing WP-601 this afternoon, its first sed edit to a settings contract damaged several rows it hadn’t meant to touch. It restored the file from git and redid the change with a script. In the same commit it ran a secret scan and the commit in one command, so when the scan matched three files the commit went ahead anyway. It told me straight away and checked the matches before anything was pushed. I’d rather have a colleague who reports that than one who doesn’t, but I’d also rather the commit had waited for the scan.
What I’d do differently, and what it cost
I can’t give you a token bill. The build ran on my Claude subscription and I didn’t record usage, which I regret for a post like this. The closest proxy is the limits: three session limits in the first two days, and a weekly limit that stalled the compute broker’s acceptance from 28 to 30 October. Some subagent reports show the scale per package. One population-management package used about 350,000 tokens and 169 tool calls on its own.
With hindsight, I’d:
- run CI on a real Linux machine from the first commit, with a short tier and a full tier defined in advance;
- make the simulation deterministic on day one;
- give each wave’s shared files a single owner, so every commit builds;
- ask for every question in plain English, with a recommendation first;
- log tokens per work package, so the next retrospective has a cost column.
Next: the first real spin-up
Everything above has been tested against fakes. As of tonight, Darwin has never made a model call through a real key, sent a real email, taken a real payment or started a real cloud machine. The M5.5 report is honest about what’s unverified: real Modal, Daytona and Vercel calls, a dashboard link through a real tunnel, the security workflow on GitHub.
The plan from day one was “probably aws, build for that”. The pieces I have to provide myself are a host, a domain for agents’ sites and another for Janus, model keys with hard monthly caps, Stripe in test mode, and a treasury float. No real money moves until I’ve ticked through a legal and accounting checklist called Gate G1.
A Hacker News thread about letting Claude Code loose to make money has a top comment I keep coming back to: “autonomous output is not the same thing as autonomous revenue”. That’s a fair description of the last 18 days. 343,000 lines of Python, 5,096 green tests, and a ledger whose real balance is still exactly zero micro-dollars.
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 →