anthropic
Claude writes 80% of Anthropic's code, and CI buckled
Promtime
anthropicThree fixes to the same service, in order: a bigger machine bought 70 days, sharding bought 29 days, a daily restart bought less than a day. That is what happens to a test selection service, according to Anthropic's engineering write-up on Claude's blog, when CI jobs grow 25x in six months.
At a glance
- Claude authors 80% of the code Anthropic engineers ship, and they ship 8x as much per quarter as in 2021–2025; the test suite grew 10x with only a nominal number of new engineers.
- A listener records results from every CI run and a selector reads that history to pick which tests run on each PR; twenty minutes of listener lag can strand tens of thousands of test updates.
- The rebuilt sharded design costs more to run, and the restarts that preceded it left the listener so far behind that the selector chose tests from stale result history.
If you have not met test impact analysis: instead of running every test on every change, a service picks the tests a change can plausibly break. The technique goes back to regression-test optimization research in the 1990s, according to Minware, and modern versions mix dependency analysis with coverage data. Anthropic built its own deterministic version, keyed on past results and package relevance, and notes that a vendor category sells the same thing.
Why did 8x more code turn into 25x more CI jobs?
Because the tests multiplied too. Anthropic engineers now ship 8x as much code per quarter as they did from 2021 to 2025, Claude writes 80% of it, and Claude also does a large share of reviewing and approving PRs. Meanwhile the test count across the codebase grew 10x, headcount barely moved, and CI jobs rose 25x over six months.
The multiples do not line up because not every test runs on every PR. The shape of the work changed as well: Claude prefers smaller, more granular PRs, so the same work arrives as more pull requests. Agents push overnight and on weekends, which raises the floor, and the load stays bursty because humans still drive and approve a lot of changes.
Patch one doubled the cores, patch two gave each package its own worker
By October of last year the service was straining and the team got paged two days running. The first fix was to double the cores, and they knew it would not last. Ownership was murky at the time: nobody wanted another piece of infrastructure, and the CI team had bigger problems.
To keep the pressure on, the author ran a long-lived session in an internal version of Claude Tag dedicated to watching the service. Whenever listener lag passed 50,000 jobs behind, Claude pinged him and picked the conversation back up. That went on for months. Claude often argued for a full overhaul; they usually settled on another patch.
February brought patch two. The listener never needed one global writer, only one writer per package, so results for each section of the codebase stay in order. Claude generated the code to split each package's state into its own shard with its own worker. That bought 29 days.
In March the process hit its memory limit by mid-afternoon
On most weekdays the singleton ran out of memory before the afternoon was over. The team went looking for quick wins and found four bugs. Swapping the memory allocator changed nothing, and they did not want to risk memory profiling a single instance already under heavy load. Restarting it bought less than a day.
Daily restarts had a second effect: the service drifted further behind each time. On several occasions it fell behind by more than an hour, and a large batch of job results never reached the listener. CI still ran on those PRs and untested code did not reach production; what happened instead is that the selector decided from stale data, mostly re-running tests that were already flaky or failing everywhere.
The redesign gave the listener a journal instead of memory
The v0 design kept a running history per test inside the process, which is why a single writer had to apply every result and why it could not be sharded horizontally. The rebuild hands that job to an in-memory data store. Any listener worker appends a result to a journal and moves on holding nothing, so workers are stateless; a small separate consumer rolls the journal up into per-test history every few seconds, and the selector reads from that.
Think of one clerk memorising every record card versus a shared inbox that a second clerk files on a timer. The rebuilt setup is more expensive to run and much easier to scale and profile. It took one engineer three weeks, where a year ago it would have been closer to a quarter, and Claude handled most of the tuning of journal size and worker count. The queued-events chart shows a backlog growing week over week before, flat after cutover.
The write-up trades in multiples rather than absolutes: 25x is growth on a base it never states, and "more expensive to run" arrives without a figure. Oddly, the advice to design v0 for 10–20x the perceived scale comes with the condition that your budget allows it, next to a cost the post does not quantify.
Whether the journal holds
The author expects horizontally scaled test selection to become industry standard as teams running agents produce both more PRs and more tests, and tells other teams to assume their architecture will be at 25x load within two quarters. His own service has been stable since cutover. What the post does not name is the next checkpoint: no figure for how long this design is expected to absorb growth, and no date for the next rebuild.
Comments
No comments yet. Be the first.
Join the conversation
Sign in with Google to leave a comment. Your name and avatar come from your Google profile, and the comment appears after moderation.
We only use your name and avatar from Google. We never store your email address.
