A lot of code is being rewritten by AI agents this year. GitHub ported the Copilot agent runtime from TypeScript to about 800,000 lines of Rust in a few months, mostly with Copilot itself (write-up). Anthropic’s guide to AI-driven code modernization says projects that used to take years “can now finish in months (or weeks).”
Some are controversial. ArtCraft, an AI-built “Adobe-compatible” suite in Rust, launched with the line “I just one-shotted Photoshop.” People who tried it found that text editing and brushes didn’t work, and the Hacker News thread turned into an argument about overclaiming. Getting an agent to write a rewrite is quick now. Showing that it behaves like the original is the slow part.
Bioinformatics has its own wave, mostly into Rust. Heng Li lists many of them in The AI Rewrite Dilemma, from fgbio to fgumi and FastQC to RastQC, and argues that the people side is harder than the technical side: “Empathy matters more than technical benefit or legal correctness.” Anthropic’s guide says much the same: the slow part is getting everyone to agree on what the rewrite should do and how to check it. Phil Ewels at Seqera set out principles for doing it well at rewrites.bio: match the original’s output exactly, credit its authors, and say what you did and didn’t validate.
My own first attempt, in February, was vibe-vep, a Go rewrite of VEP in a single binary. VEP is one of the more expensive parts of keeping cBioPortal’s variant annotations up to date. vibe-vep worked well, but then we learned that Kuan-lin Huang’s lab at Mount Sinai was building a Rust rewrite, fastVEP. So we paused vibe-vep and benchmarked theirs instead. Meanwhile the models kept getting better at this kind of work, so this summer we tried something bigger as a proof of concept: cBioPortal’s own backend.
This post covers what came out of it and how the work went, measured from the agents’ session logs. Whether to roll it out is up for discussion in RFC 106.
Contents: The rewrite · Rewrite compared · How many prompts? · Prompts categorized · Prompts: the new source code? · Lessons
cbioportal-go replaces cBioPortal’s Java REST API and its importer, about 130,000 lines of Java and configuration built up over more than ten years, with Go. Everything else stays: the website, the ClickHouse database and the session service. The diagram shows what changes. It’s an experiment for now, not an official cBioPortal release. In the terms of Anthropic’s modernization guide, it’s a transform: new code in a new language, same behavior.
Hover over a box to see what it does and what it uses on the public portal. Click it to open its repository.
React website · cBioPortal/cbioportal-frontend
The website people use. It gets all its data from the REST API.
Unchanged: both backends serve the same website build.
Java API · cBioPortal/cbioportal
The Spring Boot REST API that answers the website, scripts and AI agents. About 80,000 lines of Java.
About 1.8 GB of memory per server on average and 0.34 s of CPU per request. MSK runs 20 Java backend servers across its portals, about $1,280 a month.
Redis cache · redis.io
Keeps the Java API's answers for 60 minutes, so repeated requests skip the database.
Answers 65 to 75% of Java's lookups. Its servers cost about $215 a month. The Go version has no response cache.
Importer (Java + Python) · cBioPortal/cbioportal-core
Checks study files and loads them into the database. About 33,000 lines of Java and Python.
Loading MSK-IMPACT (50,000 samples) takes 289 s and 3.9 GB of memory.
Go API · cBioPortal/cbioportal-go
Answers the same REST API as Java, field by field. Keeps study metadata in memory.
About 48 MB of memory per server on average (131 MB at most) and 0.11 s of CPU per request. The servers for all portals would cost about $160 a month.
Importer (Go) · cBioPortal/cbioportal-go
Loads the same study files into ClickHouse. It lives in the same repository and program as the Go API.
Loading MSK-IMPACT takes 80 s and 0.2 GB of memory.
Session service · cBioPortal/session-service
Stores users' saved pages, virtual studies and custom data.
Shared by both backends and not part of the rewrite.
ClickHouse · clickhouse.com
The database that holds all study data, on ClickHouse Cloud.
Both backends use the same data. On the API portal's traffic, Go used 0.92 times Java's ClickHouse CPU per request.
We picked Go because a Go server needs a fraction of a Java server’s memory, builds in seconds, needs few outside libraries, and is plain enough for others to review. I had actually started in Rust. After a day I asked Claude whether Go would fit better, and it said yes, even with part of the Rust version already written. The API mostly turns HTTP requests into ClickHouse queries, so the time goes to the database and Rust’s speed buys little. Rust rebuilds took 10 to 20 seconds. And cBioPortal’s contributors mostly write Java, which makes Go easier to pick up. When I asked again in October, it gave the same answer and added that most of the work had been matching Java in many small ways, where a fast compile loop helps. RFC 106 has the full reasoning.
The API has no complete written spec, so the Java code serves as one: “correct” means “gives the same answer as Java.” We check that in layers, from fast to slow:
The numbers come from the public portal, cbioportal.org. Its API answers about 36 million requests a month, and on weekdays about a third of them come from scripts and AI agents (see the usage page).
Hover over or tap a tile for what it measures.
Speed, memory and errors come from one day in October when Go got a copy of 10% of the public portal’s API requests. Speed compares fairly. Memory, errors and cost are less certain until Go has run at full traffic.
Java’s Redis cache mattered less than we expected. It answers 65 to 75% of Java’s lookups, which makes Java faster on small requests that repeat often. Go has no response cache, yet it matches Java’s typical response time and beats it on slow requests. On the API portal’s traffic it even put slightly less load on ClickHouse per request. Leaving out Redis saves another $215 a month.
In the nightly check of October 12, 4,531 of 4,959 replayed production requests gave identical answers. The other 428 all had known causes, for example a Java bug that Go fixes, or an answer Java itself gives differently each time. None were unexplained. RFC 106 asks for seven clean nights in a row before Go serves real traffic.
The AI tools ran on Claude subscriptions, a few hundred dollars over three months. At Claude API list prices the same work would have cost about $2,000 ($550 in July and $1,400 in October), less than two months of the estimated server savings. 98% of what the agents read was served from the prompt cache. Without it, the bill would have been about $22,500.
The work took a few weeks of supervised agent time, spread over three months next to my other work. It ran mostly as one long Claude Code session in a tmux window on a server (the setup is in my async software engineering post). That main session handed single tasks, such as one group of endpoints or one speed fix, to helper agents, each working in its own copy of the repository. A change went in only after the tests passed and its measurements were checked.
The work came in two stretches, July and October, with a pause in between. Git agrees: there are no commits from late July until October 2. The chart shows my messages, the agents’ tool calls, commits and the size of the code per day.
Hover over or tap a day to see its numbers.
My messages fall on 24 days. If messages less than 30 minutes apart count as one sitting, that’s about 38 hours of typing to agents, much of it from my phone. Reading results or clicking through the website without typing isn’t counted, so my real time was higher.
Here is what the session logs show:
Hover over or tap a tile for what was counted. The counts cover the main sessions and their helper agents in July and October.
For every message I typed, the agents sent about 36 of their own.
GitHub’s Copilot write-up sorted its engineers’ messages to the agents by main purpose. I sorted my 508 messages into the same categories. An LLM did the labeling and I checked a sample by hand.
Hover over or tap a bar to see what the category means and an example message.
Status or explanation request: Asking what happened or why.
For example: "What's still missing before the API portal can switch?"
Approval or short answer: Replying to the agent's question.
For example: "Sounds good, go ahead."
Technical or design challenge: Questioning or proposing an approach.
For example: "I am considering doing this in Go instead of Rust. What do you think?"
Scope clarification: What's in or out, and what it should look like.
For example: "Keep the benchmark short and add a table of contents."
Git, PR and session logistics: Branches, commits, pull requests, crashed sessions.
For example: "Commit your work and open a pull request."
Kickoff: Starting a new task.
For example: "Add CI tests to the repository."
Resource and fleet coordination: Servers, secrets, DNS, helper agents.
For example: "I added the Docker Hub secrets."
Review, testing and CI: Reporting what's broken or reviewing results.
For example: "Several study view tables don't load."
Forward pressure and completeness: Pushing to keep going or finish.
For example: "Port the rest of the endpoints."
Course correction: Telling the agent it's on the wrong track.
For example: "It works in production, so it must be a backend bug."
Other: Anything else.
For example: "One-off commands and IDs."
A third of my messages were check-ins: asking how a task was going (18%) or answering yes or ok (15%). Another quarter steered the work, by questioning a technical choice (14%) or setting the scope (12%). Just 4% told an agent it was on the wrong track.
The mix is quite different from GitHub’s. Their three biggest categories, review and testing (31%), technical challenges (17%) and pushing for completeness (15%), make up 63% of their messages and a quarter of mine. Only technical challenges come out about the same. My agents ran the tests themselves, and my own checking happened in the browser.
When an agent writes most of the code, people want to see your prompts as much as your code. Did you let it run wild, or did you question the language choice, the data model, the shortcuts it proposed? When I present this work, people ask the same questions I asked the agent along the way.
Tools are starting to keep this record next to the code. Claude Code links the session in the pull requests it opens, so a reviewer can read the conversation behind a change. Entire is a company built on this idea: its open-source CLI stores every agent session in the repository, paired with the commit it produced and with secrets redacted.
Sessions also hold things you can’t publish, like credentials that showed up in tool output and internal hostnames. Sharing them inside your team is fine. In public, share summaries and short excerpts instead. The numbers from my logs in this post are all counts.
cleanupPeriodDays in your
settings before you start.