How GitHub ported Copilot's runtime to Rust with agents and kept shipping
GitHub's agent-driven rewrite of 800,000+ lines into Rust, decoded as a playbook for teams planning an incremental, behavior-preserving port.
Picture a platform engineer at a mid-size SaaS shop. Her team's core service is a large Node.js codebase, and it has become a cost problem: slow startup, heavy memory per instance, and a process boundary that every integration has to cross. Leadership wants it in a compiled language, and someone suggests letting coding agents do the port. She's seen how that goes. A long-lived feature branch falls behind main every week. An agent produces a giant PR nobody can review. The code compiles, and three weeks after cutover a retry path behaves differently and nobody can say why.
GitHub just published a detailed account of doing this at scale and avoiding most of that. In a post on the GitHub Blog, Microsoft Distinguished Engineer Stephen Toub describes rewriting the Copilot agent runtime from TypeScript into more than 800,000 lines of production Rust. Agents wrote most of it, across 128 pull requests that landed in main and shipped incrementally. The useful part for the rest of us isn't the line count. It's the method that kept the port behavior-preserving while dozens of other developers kept merging.
What it is
The Copilot agent runtime backs the Copilot CLI, the Copilot app and the Copilot SDK, and, per GitHub, products including VS Code, Visual Studio, Copilot Code Review and Office apps. It ran on Node.js and V8, and SDK clients reached it by spawning a CLI process and talking JSON-RPC. GitHub says that cost every SDK consumer "on the order of 100 MB of working set minimum" per client, plus a second process to supervise.
The new runtime is a native binary exposing a C ABI for in-process use, with a stdin/stdout or socket server kept for out-of-process cases. Byteiota reports the C ABI is 19 exported functions in front of 364 JSON-RPC dispatch routes, so new APIs don't need a binary interface change.
The method maps directly to the lede's failure points:
- No long-lived branch. GitHub weighed big-bang rewrites (stop-the-world or parallel branch) against in-place porting, and chose atomic in-place replacement: each PR swaps a TypeScript component for a thin shim that calls into Rust and deletes the old code in the same change. Main stays shippable.
- Reviewable slices. Byteiota reports the PRs were ordered from pure utility functions inward to the most coupled file, session.ts at roughly 30,000 lines.
- Old tests check new code. InfoQ reports a temporary N-API interop layer let existing end-to-end tests exercise Rust while other components were still TypeScript. It peaked at 2,019 internal exports and 3,356 TypeScript call sites before being removed.
- Real exposure, limited blast radius. GitHub shipped 135 releases during the work, 35 stable and 100 prerelease, per InfoQ. Byteiota says prereleases took 10.5% of download volume.
GitHub's reported results, per InfoQ: a measured client startup, session creation and single-turn scenario fell from 5.25 seconds to 292 ms with the Rust runtime embedded in-process. Byteiota's follow-up adds 10-client memory falling from 1,383 MB to 126 MB and throughput rising from 7.55 to 120 session lifecycles per second. Byteiota notes GitHub flags these as workload-specific and the product of language, process model and architecture changes together.
Alternatives, with what the sources actually support:
- Microsoft's native TypeScript 7 compiler in Go. Rustify treats it as the shipping baseline for native TypeScript tooling. The sources here don't describe how that port was done, so it's a target-language comparison, not a method comparison.
- Theo Browne's tsc-rs. An agent-driven Rust port of the TypeScript 7 compiler. Rustify reports earlier attempts burned over $420,000 in API-priced tokens to reach about 84% compatibility before a later run worked for about $24,047. Trade-off: a compiler has a built-in oracle (run upstream on the same input and diff), which most application runtimes don't.
- Prime Intellect's Prime Agent rewrite. Per SourceTrail, a from-scratch Rust rewrite by more than 2,000 agents over two weeks, checked with side-by-side TUI, transcript and protocol diffs. Trade-off: a greenfield rewrite gets a cleaner architecture but leans entirely on parity harnesses rather than shipping in place.
Who it's for
Pick this up if you're a Copilot SDK consumer: Byteiota and iMasters both say the TypeScript, Python, Go, .NET, Java and Rust SDKs work against the new runtime without application code changes, with an in-process option for latency-sensitive tools.
Pick it up as a playbook if you're planning a large agent-assisted port of a shared, high-concurrency component and you already have end-to-end tests worth trusting.
Skip the rewrite itself if your Node service's startup and memory are fine. Toub is explicit: "This is in no way a claim that every large TypeScript program should become Rust." Byteiota summarizes GitHub's own advice as: measure your bottleneck first, migrate incrementally, build compatibility tests first.
Before and after
The old way, for a large port:
- Estimate the codebase and open a rewrite branch.
- Port in isolation while main keeps moving.
- Rebase repeatedly; the gap grows.
- Big-bang cutover; behavior bugs surface all at once in production.
GitHub's way:
- Separate layers first (TUI from runtime), so the port target is a library.
- Build an interop bridge so ported pieces run inside the existing system.
- Port leaves first; each PR replaces one component with a Rust shim and deletes the TypeScript.
- Run existing end-to-end tests plus compile checks on every change. InfoQ reports 4,478 direct cargo check runs, 87.1% clean.
- Ship continuously, with prereleases soaking up early exposure.
- Remove the bridge when nothing calls it.
The human role changed too. Byteiota reports the lead engineer's 2,639 interactions broke down as 31% reviewing results and running CI, 17% challenging agent decisions and 15% pushing agents past intermediate stopping points, with only about 40 session starts. The engineer described the job as "operate the control loop." The hardest piece, session.ts, took a 25-hour run with 15 parallel child sessions and a custom "agentic mutex" to serialize CPU-heavy builds, per Byteiota.
One finding worth noting before crediting Rust's safety model: Byteiota reports compiler errors were 37% name resolution, 22% missing methods, 14% type mismatches and 11% trait bounds, with ownership, borrow and lifetime errors at 1.7%. The feedback came mostly from static typing.
Try it
If you use the Copilot SDK, the sources say there's nothing to change; the entry point stays the same. GitHub's post shows it like this (the comment describes the old, out-of-process behavior):
const client = new CopilotClient();
await client.start(); // spawns the CLI as a subprocess
const session = await client.createSession({
/* ... */
});
The sources don't give SDK version numbers, install commands, or the switch for choosing in-process versus out-of-process mode, so check the SDK's own docs for those.
If you want to apply the method, the smallest first step the sources support is not writing Rust. It's picking one leaf module with no dependencies, putting an interop shim in front of it, and confirming your existing end-to-end tests pass through the shim. If they can't, you've learned your test suite isn't ready to be the oracle.
Where it breaks
- Regressions weren't rare in review. GitHub's post calls them "few." Byteiota and explainx report dozens surfaced:
42.0versus42type ambiguity, timezone and environment variable handling, thread-blocking calls across the N-API boundary, lifecycle ownership mismatches and wrong test oracles. No source gives a count of regressions that reached users. - Agents overstep. Byteiota reports a subagent pulled in changes from a parallel session after that session had refused the merge four times; human review caught it. Byteiota's follow-up quotes consultant Lisa Crossman: "Rust stops the agent writing memory unsafe code; it does not stop the agent writing the wrong program correctly."
- Boundary behavior is unproven publicly. InfoQ commenters flagged cancellation, retries and backpressure as needing validation beyond compilation. iMasters notes there's no public parity data on those, and no migration guide for subtle old-versus-new behavior differences. The sources don't confirm differential or golden-trace testing beyond unit tests and the side-by-side N-API approach.
- Cost is reported, not confirmed. Byteiota's follow-up puts token spend at roughly $120,000; we didn't find that figure in GitHub's post text.
- Some headline numbers don't line up. The post on X that surfaced this claims a greater-than-90% CPU and memory reduction; the sources give memory, startup and throughput figures, not a CPU number. Byteiota's first piece lists startup as 55.3 ms, while InfoQ and others report 292 ms.
- Unsafe code exists. Explainx reports 158 unsafe blocks across 36 files, concentrated at FFI, OS and SQLite boundaries, with GitHub claiming zero known regressions traced to them.
- Unfinished layering. GitHub says the CLI still calls runtime internals directly in places; moving it fully onto the SDK surface is ongoing.
Who picks this method: teams with a measured bottleneck, solid end-to-end tests and someone willing to run the control loop full time. Who skips it: anyone hoping agents replace the review, or whose port has no oracle to diff against.
Sources
- Migrating the GitHub Copilot runtime to Rust, using Copilot · The GitHub Blog
- GitHub Rewrote Copilot in Rust: 800K Lines, AI Did It | byteiota · Byteiota
- GitHub Rewrote Copilot in Rust Using Copilot: What Actually Happened · Byteiota
- GitHub Copilot Rust Migration: 832K Lines (2026) | explainx.ai Blog · explainx.ai
- GitHub Copilot: runtime moves from Node.js to Rust · Imasters
- Github Migrates Copilot Runtime to Rust with AI-Assisted Rewrite · InfoQ
- Rust Wave: AI Rewrites, Benchmarks, and Malware · SourceTrail
- Theo's tsc-rs: TypeScript Compiler in Rust (2026) · Rustify
- @bibryam: Migrating the GitHub Copilot runtime to Rust · @bibryam