Comment GitHub a réécrit le runtime Copilot en Rust en utilisant... Copilot ?
jeu, 24/09/2026 - 16:01
GitHub a publié un long post sur la migration du runtime GitHub Copilot en Rust, en utilisant Copilot. Cela représente plus de 800 000 lignes de code. Que ce soit la CLI, Copilot appl ou encore le SDK, ils reposent sur l'environnement d'exécution de l'agent Copilot. A l'origine, il était écrit en TypeScript sur Node.js et V8. Fondamentalement, l'architecture a peu évolué. Mais avec l'arrivée de l'app et de la CLI, les équipes ont décidé de migrer le code du runtime en Rust.
"La majeure partie du code a été écrite par des agents, soit 128 demandes de fusion intégrées à la branche principale et déployées progressivement, évitant ainsi une migration finale unique. Les quelques régressions inévitables ont été rapidement détectées et corrigées, tandis que les performances de l'environnement d'exécution ont été considérablement améliorées. Un projet qui aurait nécessité une équipe complète de développeurs pendant un an ou deux avant l'intégration des agents a été réalisé en grande partie par un seul développeur, en quelques mois seulement, tandis que le reste de l'équipe continuait d'étendre significativement les capacités et la portée de l'environnement d'exécution." explique le post.

Pourquoi cette migration ?
La multiplication des services et des outils Copilot pèse forcément sur le runtime. De nombreuses contraintes ont dicté le choix de Rust, par exemple : un langage ayant un minimum de dépendances, intégrer proprement des processus, avoir un niveau de performance, d'évolution et de fiabilité, un langage interopérable pour supporter facilement les différents SDK (C#, TypeScript, Python, Rust, Go et Java), une sécurité par défaut.
Rust fut donc choisi mais au départ, l'idée n'était pas de tout réécrire en Rust : "Nos exigences privilégiaient l'intégration via une ABI C, une faible surcharge au démarrage et en régime permanent, et une utilisation prévisible des ressources."
Deux tâches essentielles ont été menées :
Finalement, l'option 2 avec suppession progressive des composants TypeScript fut choisie pour plusieurs raisons dont :
- pas d'arrêt de production
- la branche principale est toujours prête à être déployée
- réécriture incrémentale
- des migrations par petits morceaux et relativement autonomes
- tests de bout en bout
Avant de lancer le chantier, un PoC limité a été réalisé : "Avant de nous lancer pleinement, nous avons gagné en confiance et validé nos hypothèses. Nous avons commencé par deux pull requests qui ont établi l'espace de travail Rust, la chaîne d'outils, les règles de lint, l'intégration continue, le pipeline de compilation et les instructions de codage. Nous avons ensuite introduit la bibliothèque d'exécution, la génération de code et les modèles d'interopérabilité, tout en portant une collection de primitives de logique pure, choisies précisément pour leur absence d'E/S et d'état partagé, et parce qu'elles bénéficiaient déjà de tests robustes. Ce n'est qu'après l'intégration de ces primitives que la première pull request de portage majeure a permis de porter trois utilitaires sans effets de bord tout au long du processus."
Interopérabilité : un point crucial
Cette migration devait assurer l'interopérabilité entre TypeScript, Rust et l'ensemble des SDK disponibles :
1 / s'assurer que durant la migration vers Rust, le module concerné TypeScript était toujours accessible et que les fonctions Rust puissent appeler du TypeScript en callback
2 / toutes les librairies des SDK doivent pouvoir s'appuyer sur le runtime et exposer les fonctionnalités.
Une migration d'un langage à un autre n'était pas uniquement une réécriture. Il a fallu remplacer les bibliothèques utilisées par le runtime. Elles ne dépendent pas de GitHub. Certaines étaient quasi identiques, d'autres nécessitaient plusieurs crates. La migration a permis de supprimer 60 dépendances npm.
Cette migration n'a pas échappé aux régressions. Il est quasi impossible d'avoir un comportement strictement identique sur une telle quantité de code. Les équipes rappellent un axiome simple : porter du code c'est facile, le corriger l'est beaucoup moins : "Au 14 septembre 2026, nous avions recensé des dizaines de régressions connues, toutes corrigées. La plupart étaient des bugs, avec un plus petit nombre de régressions de performance." Il n'y a pas 0 régression et toutes n'ont pas été détectées.
Au final...
Cette migration représente :
136 milliards de tokens
120 000 $ : c'est le coût estimé pour la partie agentique uniquement
Bien entendu, il a fallu toute une équipe : une dizaine de développeurs pour le cœur du projet, et un nombre non précisé d'autres intervenants pour les pull requests et les approbations. Les leçons tirées de cette expérience
Les leçons tirées de cette expience
1 / il faut un objectif clair et précis, ne pas avoir d'estimations approximatives
2 / des tests de bout en bout et tout le temps. C'EST INDISPENSABLE.
3 / prévenir et protéger de toute action de l'agent non prévue ou demandée
4 / traduire d'abord, redesigner après : il faut préserver le comportement, par exemple sur le code concurrent ou la gestion des droits. Chaque écart peut engrendrer des régressions et des comportements anormaux.
5 / transformer un échec en futur succès : un agent peut dévier, il faut en tirer des leçons.
Post complet : https://github.blog/ai-and-ml/generative-ai/migrating-the-github-copilot-runtime-to-rust-using-copilot/

