On September 2, Nous Research gave Hermes Agent one standing goal: shrink its own codebase by at least 30 percent. About 19 active hours and 1,393 subagents later, non-test Python went from 1,063,826 lines to 698,363. The pull request title promised zero behavior change, and the test suite agreed: 51 failures on the branch, the same 51 on untouched main.
Then people read it. Reviewers caught about 30 public names the agents had deleted. A script Nous wrote afterward counted 1,703, in 18 seconds. That figure sits in Nous’s own forensic post-mortem, not in the launch post, and none of the coverage we read picked it up.
This issue reads the run through those receipts. The short version: the model did the refactor, but the checks and the harness decided what it missed and what it cost.
| item 01 | The job, as it actually ran status: closed · merged sept 4 |
The setup is a general contractor with 36 crews. The top agent measured the repo, cut it into 36 non-overlapping groups, and wrote each worker a brief: what to simplify, which interfaces to keep, which checks to pass before committing. Workers edited in separate git worktrees (independent checkouts of one repo) so they never overwrote each other, and some hired their own sub-crews, three levels deep.
| line | recorded |
| subagents by depth | 143 · 630 · 620 (1,393 total) |
| peak concurrency | 218 agents, one Python process, an i7 desktop with 64 GB |
| model | Claude Fable 5.1, called remotely |
| model calls | 93,284 |
| estimated spend | 19,302.59 dollars (about 25,000 with follow-up sessions) |
| commits on the branch | 4,271, one per verified step |
| non-test Python | 1,063,826 → 698,363 lines (−34.4%) |
| gateway/run.py | 34,847 → 5,512 lines |
| functions over 300 lines | 192 → 2 |
sources: nous launch post, post-mortem issue 103563, pull request 102117 page (commit count read sept 16)
The guardrails were real. A tool’s JSON schema had to stay identical, and a command’s help output was compared byte for byte. The worker briefs came partly from a Hermes skill the agent had built up from daily work with Teknium, who ran the job, including one habit that matters later: rerun a failing test on unchanged main to see whether you caused it.
| item 02 | The punch list: 1,703 against 30 status: closed · caught after the fact |
On a building site, the punch list is what the inspector finds after the builder says the job is done. Here is Nous’s own inspection of the pull request as first opened, from the post-mortem.
| dropped at open | count | human review | surface diff vs base |
| public names | 1,703 across 341 modules | about 30, by hand | all 1,703 |
| public methods | 951 across 156 classes | not reported | 951 (first count said 1,000; 49 were false hits) |
| test definitions | 126 across 52 files | 5 trimmed suites found | all 126 |
source: post-mortem issue 103563, accuracy table. the diff script is pull request 103541
The mechanism is simple. A worker saw a name with zero callers inside the repo and deleted it as dead code. But Hermes has external plugins, and their imports live in other people’s repos. Nothing inside the repo can see them, so nothing inside the repo, tests included, can object.
Review found other classes too. An automated rewrite around Python’s suppress() helper touched 1,580 sites, and a syntax-tree differential (comparing the parsed code before and after) found about 65 semantic mismatches: wider or narrower exception types, changed scope, one dropped log line. The first review round also found a packaged wheel missing 17 modules (two were already missing on main) and 3,272 lost comment blocks, all restored before merge.
Of the 72 fix commits the post-mortem classified, 16 restored dropped symbols or tests: exactly the class the new surface-diff script catches.
| item 03 | Why the tests said zero status: open · applies to every agent refactor |
The pull request’s verification section reads: 44,859 passed, 51 failed, the identical 51 failing on main, regressions attributable to this change, zero. That is a sound method with one hidden assumption: that both runs used the same test suite.
They did not, at first. The same agents that wrote the code had dropped 126 test definitions and trimmed five suites around behavior that was still live. Parity against a suite the agent is editing is like a contractor inspecting his own wiring with a meter he rewired. Nous’s later benchmark shows test lines up 0.1% on the final head, but that is after reviewers put the tests back.
| check | can see | cannot see | cost |
| test-suite parity | behavior the tests cover | names that outside code imports; tests the agent deleted | one full run |
| human review of 4,271 commits | some of everything | most of the 1,703 | 10 participants, two days |
| surface diff against base | every removed public name, method, test | changed behavior inside a kept name | 18 seconds |
rows 1 and 3 from the pull request and post-mortem; review cost from the pull request page (participant count)
| | the takeaway When agents write the code and edit the tests, a green test run stops being independent evidence. Diff the public surface against the base branch with a script that lives outside the agents’ reach, and review test changes as their own lane. |
| item 04 | Where the 19,302 dollars went status: estimate · not an invoice |
The post-mortem splits spend by bucket, using per-token rates that reproduce the run’s own recorded estimate. It says plainly that this checks the estimator, not a bill.
| cache writes | | 11,159.62 · 58% |
| output | | 4,554.90 · 24% |
| cache reads | | 3,586.55 · 19% |
| fresh input | | 1.52 · ~0% |
source: post-mortem issue 103563, section 3. average prompt 206k tokens; 62% of calls carried over 150k
Cache writes are the cost of re-sending context. Every request carried the one-hour cache tier from the operator config, so a worker that lived 20 minutes paid for an hour of retention. On the same loop, one-hour markers measured 20 dollars per million written tokens against 12.51 for five-minute markers; the fix drops subagents to five minutes. Depth-2 workers alone were 67% of spend.
Then there is what the harness lost on its own:
| what broke | observed on the run | fix |
| auth key never refreshed in the command-line process | 620 errors of type 401; parent died at 08:30; 196 children orphaned (1,193 dollars sunk), plus dips of 1.1k and 1.6k | refresh before expiry, every process |
| nested delegation under a 420-second tool limit | 332 timeouts in 234 orchestrators; 114 of 121 root summaries cut to 2,000 characters | delegation exempted |
| a dead wave looked like a slow one | every wave-1 child dead at 08:29, parent learned at 09:36: 66 minutes | failed child surfaced in 0.3 s |
| goal judge watched every agent’s processes | parked 3 h 22 min on a grandchild’s poller | own processes, 30-minute cap |
| tool friction | 546 false command blocks (~110 dollars), 454 timeout refusals, 661 whole-file rewrites (~155) | three separate fixes |
source: post-mortem issue 103563, section 4. the three auth dips sum to about 3,900 dollars, roughly a fifth of the estimate (our arithmetic)
To Nous’s credit, the post-mortem withdraws its own earlier cost-reduction headline and claims no total cost reduction. Each fix is reported as a before-and-after measurement, not a projected reduction.
| item 05 | The 1 percent line status: open · depends on the estimate you pick |
The blog closes on “1% of the cost and 1% of the time” against a manual estimate of 150,000 to 1.8 million dollars, and it notes that human review time is excluded. The estimate range is 12 times wide, so the ratio depends on which end you use.
| model spend, dollars | vs 150,000 | vs 1,800,000 |
| 19,302 (main run) | 12.9% | 1.1% |
| about 25,000 (with follow-ups) | 16.7% | 1.4% |
our arithmetic on figures from the nous launch post and post-mortem; review hours are in neither column
The size headline moved too. The pull request body reports 674,569 lines (−36.6%); the blog reports 698,363 (−34.4%). The 23,794-line gap is close to the size of the plugin compatibility layer added during review (25,958 lines, per Nous’s benchmark notes), which looks like the main cause, though Nous does not reconcile the two numbers.
That layer matters to anyone outside the repo. It keeps 2,091 old import paths working, including 290 public definitions the agents had deleted as unused and review restored verbatim. The manifest on main set the layer’s end at September 14, this past Monday: from that date an affected plugin is disabled unless the user sets plugins.allow_deprecated_imports: true. Plugin authors got ten days from merge.
| item 06 | What holds up status: closed · verified |
| mark | finding |
| holds | The refactor is on main. gateway/run.py is 5,601 lines there as of September 16. |
| holds | Nine source files were too large for a 128k-token context on main. After the split, none are. |
| holds | Average tokens per symbol lookup fell from 2,218 to 993 across 4,000 lookups. Nous flags that the median rose and that it did not measure task completion. |
| mixed | Nous’s own reading: the largest import cycle grew from 548 to 788 modules, and gateway.run import time rose from 154 to 196 ms. The coupling moved between files; it did not leave. |
| holds | Independent review of the harness fixes found three P1 defects (an approval bypass, a credential takeover, a lost final result). Nous published all three, fixed before shipping. |
sources: raw file on main (sept 16), nous benchmark notes, post-mortem sections 4 and 6
The transparency is the strongest part of this story. Most teams would ship the blog. Nous also shipped a ledger of its own misses, with counts precise enough to argue with.
| item 07 | What to copy before your own fan-out status: open · your repo |
| # | check | the receipt |
| 1 | Public-surface diff against base, in CI, before merge | 1,703 found in 18 s vs ~30 by hand |
| 2 | Review test-file changes as a separate lane | 126 test definitions dropped at open |
| 3 | Five-minute cache tier for short-lived subagents | 20 vs 12.51 dollars per million writes |
| 4 | Refresh credentials inside every worker process | about 3,900 dollars across three auth dips |
| 5 | Report a dead child the moment it dies | 66 minutes blind |
| 6 | Put a time cap on every wait | 3 h 22 min parked |
| 7 | Share one language server across worktrees | about 30 Pyright copies, 8.7 GB of memory |
receipts from the post-mortem and launch post; the ranking is ours
The coverage led with the cost ratio. The number worth carrying into your own pipeline is smaller: the least expensive check in the whole run took 18 seconds, and it was not a model.