Wie Anthropic groß angelegte Code-Migrationen mit Claude Code durchführt

@ClaudeDevs
ENGLISCHvor 2 Tagen · 21. Juli 2026
460K
3.7K
331
84
4.7K

TL;DR

Anthropic erläutert ein Sechs-Schritte-Framework für den Einsatz von Claude Code zur Automatisierung groß angelegter Sprachmigrationen, demonstriert am Beispiel der Portierung der eine Million Zeilen umfassenden Codebasis von Bun auf Rust.

Code-Migrationen, also Projekte, die eine Produktionscodebasis in eine neue Sprache portieren, waren bis vor Kurzem mehrjährige Unternehmungen.

In den letzten Monaten haben einzelne Entwickler bei Anthropic 10 Codepakete mit Zehntausenden bis Hunderttausenden von Codezeilen mithilfe von Claude Fable 5, Claude Opus 4.8 und dynamischen Workflows migriert.

Jarred Sumner (@jarredsumner), Mitbegründer von Bun und Mitglied des technischen Stabs bei Anthropic, hat Claude Code verwendet, um Bun von Zig nach Rust zu migrieren. Eine Million Codezeilen wurden in weniger als zwei Wochen produziert, wobei 100 % der bestehenden Testsuite von Bun in CI vor dem Merge bestanden. Nach dem Merge traten neun Regressionen auf, die alle behoben wurden. Der Rust-Port wurde im Juni innerhalb von Claude Code ausgeliefert.

Mike Krieger (@mikeyk), Co-Leiter von Anthropic Labs, hat eine Python-Codebasis über ein Wochenende in 165.000 Zeilen TypeScript migriert. Dies umfasste hunderte Agents, acht Phasengates, drei Adversarial-Review-Runden und eine finale Paritätsprüfung, die die Ausgabe jedes Befehls mit dem Python-Original verglich.

Die neuen Fähigkeiten von Claude Code verändern die Rechnung für diese lange aufgeschobenen Projekte. Im Folgenden wird der Sechs-Schritte-Prozess beschrieben, den wir jetzt verwenden, basierend auf dem, was uns diese Migrationen gelehrt haben.

Die Kernidee ist, dass man nicht den Code repariert. Man repariert den Prozess (die Schleife), der den Code produziert hat.

Warum und wann man Sprachen migriert

Teams starten Migrationen aufgrund von Veränderungen in der Landschaft zwischen ihrem ursprünglichen Build und dem aktuellen Projekt. Entweder ist ein bekannter Kompromiss zu einer Einschränkung geworden, ein besserer Ansatz ist aufgetaucht oder das ursprüngliche Ökosystem schrumpft.

Jarred hat sich beispielsweise ursprünglich für Zig entschieden, weil es C-Level-Leistung mit radikaler Einfachheit bot, ideal für einen Solo-Gründer, der "Bun in 1 Jahr in einer engen Oakland-Wohnung vor LLM schreibt". Diese Einfachheit brachte bekannte Kompromisse mit sich, über die er hier schreibt.

Das Bun-CLI wird über 10 Millionen Mal monatlich heruntergeladen und intensiv innerhalb von Claude Code genutzt.

Noch im letzten Quartal hätten diese Kompromisse nicht ausgereicht, um den Fahrplan einzufrieren und Ressourcen für ein Multi-Quartal-Projekt zu binden. Man konnte zwei parallele Codebasen über Quartale oder Jahre hinweg pflegen, und wenn das Endergebnis bei 90 % Parität lag, hatte man ein größeres Problem als zu Beginn.

Jetzt ist das Worst-Case-Szenario, dass man den Branch löscht und es erneut versucht.

Es muss immer noch einen vertretbaren Geschäftsfall geben. Während Migrationen mit Millionen von Zeilen nicht mehr 3 bis 4 Millionen Dollar an Entwicklungsressourcen über die Dauer eines Vier-Jahres-Projekts kosten, erfordern sie immer noch Zehntausende bis Hunderttausende Dollar oder mehr für die Ausführung. Die Bun-Migration beispielsweise verbrauchte 5,9 Milliarden ungecachte Eingabe-Tokens und 690 Millionen Ausgabe-Tokens – etwa 165.000 Dollar zu API-Preisen. Der Hauptteil von Mikes Port umfasste 27 Millionen Tokens.

ClaudeDevs - inline image

Jarreds PR mit einer Million Zeilen.

Allerdings muss der Migrationsfall nicht mehr existenziell sein. Ein Jahr von Memory-Bug-Patches im Changelog oder ein chronischer Engpass können ihn jetzt rechtfertigen.

Der Compile-Schritt war der Anstoß für Mikes Projekt. Das interne Tool, an dem sein Team arbeitet, wird als einzelnes Binary an die Benutzer ausgeliefert. Die Erstellung dieses Binarys mit der Python-Toolchain dauerte etwa acht Minuten pro Plattform, insgesamt eine 30-minütige Wartezeit über die Build-Matrix bei jedem Release. Nach dem Port dauert der gleiche Compile jetzt etwa zwei Sekunden, das Binary startet 6x schneller, und das Team konnte eine separate Deployment-Pipeline einstellen.

Warum KI die Mathematik der Code-Migration verändert

Fable und Opus 4.8 sind besonders gut darin, parallele Arbeitsströme mit Subagents zu delegieren, zu lenken und zu verifizieren, während sie mehrere Wege zu den angegebenen Zielen finden.

Große Code-Migrationen sind ein besonders effektiver Anwendungsfall für diese fortschrittlichen Modelle, weil:

  • Die Arbeit ist parallel. Die Arbeit kann über Tausende unabhängiger Einheiten wie Dateien und Crates ausgeführt werden, sodass Agents gleichzeitig arbeiten können, anstatt dass einer auf den anderen warten muss.
  • Der Kontext ist klar und umfassend. Der alte Code dient als hervorragende Spezifikation für das Modell.
  • Es gibt einen eingebauten Schiedsrichter. Viele große Codebasen enthalten eine Testsuite, die Agents zur Überprüfung ihrer Arbeit verwenden können.
  • Die Warteschlange schreibt sich selbst. Wenn ein Compiler- oder Testlauf fehlschlägt, wird dies zum nächsten Punkt für einen Agenten, der es repariert.
  • Sie erfordern Konsistenz und Edge-Case-Handling: Reviewer zitieren die Regel hinter jedem Befund, sodass ein Verstoß zu einem Warteschlangeneintrag wird, anstatt zu einer stillen Abweichung.

Sechs Schritte für große Code-Migrationen

Weitere Details finden Sie in [Jarreds Blog](https://bun.com/blog/bun-in-rust).

Voraussetzungen

Eine Voraussetzung vor dem Start Ihres Migrationsprojekts ist ein starker Prüfer (Judge), sonst haben Sie keine Exit-Bedingung oder ein Maß für den Erfolg.

Um diesen Prüfer zu bauen:

  • Kategorisieren Sie vorhandene Tests. Verwenden Sie Claude, um zu identifizieren, welche Tests als externe Aufrufe ausdrückbar sind und welche von Interna abhängen, die nicht portiert werden.
  • Für Portabilität umschreiben. Konvertieren Sie die externen Tests in Assertions, die sowohl gegen das Original als auch gegen den Port laufen können. Verwenden Sie Adversarial-Agents, um zu überprüfen, dass die umgeschriebenen Tests die Assertions nicht abschwächen.
  • Validieren Sie den Prüfer. Führen Sie ihn gegen den Originalcode aus, um zu bestätigen, dass er besteht. Führen Sie ihn dann gegen absichtlich kaputten Code aus, um zu bestätigen, dass er fehlschlägt – ein Prüfer, der Fehler nicht erkennt, ist kein Prüfer.

Dies folgt weitgehend Jarreds Methodik, mit Reviews und Gates in jeder Phase. Mike folgte einer ähnlichen Gesamtstruktur mit ähnlichen Loop-Workflows, aber er führte die gesamte Migration von Anfang bis Ende durch, überarbeitete die Regeln und den Workflow basierend auf den Ergebnissen und führte sie erneut durch – wobei er die Ausgabe jedes Mal verwarf, bis zum dritten Durchlauf.

ClaudeDevs - inline image

Schritt 1 – Erstellen des Regelbuchs, der Abhängigkeitskarte und der Lückeninventur

Die Reihenfolge ist wichtig: Das Regelbuch muss vor der Lückeninventur kommen. Die Lückeninventur wird durch das definiert, was die Standardeinstellungen des Regelbuchs nicht abdecken, und beide werden in einem gemeinsamen Audit getestet.

Regelbuch

Die genaue Form des Regelbuchs hängt von wichtigen architektonischen Entscheidungen ab, die Sie zu Beginn treffen müssen. Die wichtigste ist, ob der neue Code derselben Struktur folgt oder komplett neu gestaltet wird.

Wenn es ersteres ist (Jarred), wird das Regelbuch hauptsächlich aus Nachschlagetabellen bestehen, die Typen und Redewendungen zwischen Sprachen übersetzen, während es auf die Lückeninventur für die schwieriger zu übersetzenden Komponenten verweist. Wenn es letzteres ist (Mike), wird es ein Designdokument sein.

Jarred erstellte sein Regelbuch durch Gespräche mit Claude und formulierte eine Richtlinie für jeden Bereich der Mehrdeutigkeit. Er verwendete auch acht Subagents, die speziell dafür entwickelt wurden, auf 8 verschiedene Kategorien häufiger Fehlermodi basierend auf seiner eigenen Intuition zu prüfen.

Abhängigkeitskarte

Sie müssen Dateiabhängigkeiten verstehen, um Arbeitsströme für eine parallele Migration effektiv aufzuteilen, damit Sie wissen, welche Dateien zuerst migriert werden sollen und welche Dateien im selben Batch enthalten sein sollen. Claude Code kann Agents einsetzen, um ein deterministisches Skript zu erstellen und auszuführen, das diese Karte erstellt.

Lückeninventur und skeptische Reviewer

Die neue Sprache hat andere Anforderungen als die alte Sprache, die erfüllt werden müssen. Bei Zig zu Rust war der Unterschied die manuelle Speicherverwaltung (C und C++ funktionieren auf die gleiche Weise). Zum Beispiel:

markdown
1// Zig
2
3fn readConfig(allocator: std.mem.Allocator) ![]u8 {
4 const buf = try allocator.alloc(u8, 1024);
5 // ...buf füllen...
6 return buf; // Der Aufrufer muss dies freigeben – aber nur der Kommentar sagt das
7}
8
9// Ein Aufrufer, der 'defer allocator.free(buf)' vergisst, kompiliert trotzdem – das Leck tritt nur zur Laufzeit auf.
rust
1fn read_config() -> Vec<u8> {
2 let buf = vec![0u8; 1024];
3 // ...buf füllen...
4 buf // Das Eigentum geht an den Aufrufer über; Speicher wird automatisch freigegeben
5}
6
7// Nach dem Verschieben verwenden? Zweimal freigeben? Beides kompiliert nicht.
8// Vergessen, es freizugeben? Es gibt keinen free-Aufruf zum Vergessen — drop ist automatisch.

Bei Python zu TypeScript war die Lücke Interfaces und Verträge. Python erfordert keinen Vertrag, der angibt, welche Form von Objekt es akzeptiert oder was es zurückgibt, aber TypeScript tut es.

Sowohl Jarred als auch Mike erstellten Lückeninventurdateien, die dieses implizite Wissen erfassen. Jarred inventarisierte diese Lücken im Voraus, was wir hier tun, während Mike sich dafür entschied, zuerst zu übersetzen und dann die Lückeninventur durch anschließende Prüfung zu erstellen. Möglicherweise müssen Sie beides tun.

Hier ist ein Beispiel für einen Claude Code Prompt zum Erstellen einer Lückeninventurdatei.

Schritt 2 – Die Regeln einem Stresstest unterziehen

ClaudeDevs - inline image

In diesem Schritt verwendete Jarred einen Agenten, um drei Dateien mit dem Regelbuch zu übersetzen, einen Agenten, um drei Dateien "wie ein erfahrener Rust-Ingenieur" zu übersetzen, und einen Agenten, um mit dem Diff neue Übersetzungsregeln zu erstellen. In dieser Phase entdeckte er zwei kritische Probleme, die zahlreiche Probleme verursacht hätten, wenn sie auf alle 1.448 Dateien ausgeweitet worden wären.

Diese Art von Stresstest funktioniert nur bei strukturerhaltenden Migrationen, bei denen zwei Übersetzungen derselben Datei Zeile für Zeile vergleichbar sind. Wenn Ihr Regelbuch ein Redesign ist – wie bei Mike – besteht der äquivalente Test darin, das Designdokument direkt mit adversarischen Reviewern anzugreifen und es dann mit einem einmaligen End-to-End-Lauf zu validieren.

Unabhängig davon werfen Sie alle übersetzten Dateien weg. Das Ziel ist es, die Regeln zu verfeinern, nicht inkrementelle Fortschritte zu machen.

Schritt 3 – Alles übersetzen

ClaudeDevs - inline image

Für die verbleibenden Schritte führen Sie dieselbe Multi-Agent-Loop-Architektur aus: Implementieren, Reviewen, Reparieren.

Sie können die Implementierungsarbeit an kleinere Modelle auslagern und die Reviewer auf größeren Modellen belassen. Mike verwendete zum Beispiel Claude Sonnet, als er 12 Subagents für die Hauptmigration verteilte.

Die Arbeitswarteschlange sollte mechanisch sein. Ein Batch-Skript entscheidet, was erledigt ist, indem es prüft, ob die übersetzte Datei auf der Festplatte existiert, und dann die ausstehenden Dateien in Batches für die Implementierungs-Agents aufteilt. Da die Warteschlange jedes Mal von der Festplatte neu aufgebaut wird, ist die Migration von Natur aus fortsetzbar.

Alles, was der Übersetzer nicht sicher ausführen kann, wird mit "// TODO(port): <reason>" markiert, um in Schritt 4 behandelt zu werden.

Zwei adversarische Reviewer bewerten die Arbeit der Implementierer mit separaten Kontexten, und Uneinigkeit zwischen den Reviewern geht an einen dritten Agenten. Wenn ein Reviewer immer wieder denselben Fehler in verschiedenen Dateien findet, ist die Lösung nicht dateiweise. Sie fügen einen Satz zum Regelbuch hinzu und generieren den betroffenen Batch neu. Das Regelbuch wächst in diesem Schritt ständig; der Code wird nie manuell dagegen gepatcht.

Eine wichtige Designentscheidung, die in diesem Schritt zu beachten ist, ist, wo der Compiler sitzt. Mike ließ den TypeScript-Compiler in jeder Schleife laufen, weil er eine Einheit in Sekunden prüft. Jarred verbot den Compiler komplett aus der Schleife und verschob ihn auf den nächsten Schritt, weil Cargo Minuten dauert.

Schritte 4, 5, 6 – Kompilieren, Ausführen und Verhalten abgleichen

ClaudeDevs - inline image

Diese drei Schritte teilen sich dieselbe Loop-Architektur und benötigen zunehmend weniger menschliches Urteilsvermögen, daher behandeln wir sie gemeinsam.

Jarred führte dies mit einem Orchestrator-Skript aus, das den Compiler einmal über den gesamten Workspace aufrief. "Fixer-Agents" durchliefen dann die Fehlerliste parallel mit adversarischem Review. Der Build läuft erneut, und das wiederholt sich.

Die Überprüfung der Fehlerliste ist hilfreich, um systemische Probleme zu erkennen, die Anpassungen erfordern können. Jarred stieß zum Beispiel auf Tausende von Rust-Modulfehlern, die nach der Behebung zyklischer Importe auftauchten, die Zigs verzögerte Kompilierung tolerierte. Er reparierte die Schleife, indem er eine Logik codierte, um zu klassifizieren, welche Abhängigkeit gelöscht, verschoben oder die Grenze umstrukturiert werden sollte.

Schritt 5 hat auch eine mechanische Wahrheitsquelle, ähnlich der Compiler-Fehlerliste: Abstürze aus dem Smoke-Test. Auch hier bestand die Schleifenlösung darin, Probleme in Kategorien zu gruppieren, in diesem Fall die Ursachen nach Ursache zu gruppieren, die von adversarischen Subagents überprüft wurden.

Schritt 6 und das Ende unserer Geschichte ist der Vergleich des Programmverhaltens zwischen den beiden Codebasen.

Unsere Dateien wurden nun übersetzt, kompiliert und einem Smoke-Test unterzogen.

Jetzt ist es an der Zeit, sie zu sharden und die Testsuite (aus der Voraussetzungsphase) gegen sie laufen zu lassen. Gehen Sie Fehlschläge mit "Fixer-Agents" an, die die fehlgeschlagenen Tests gegen beide Codebasen überprüfen. Adversarische Reviewer prüfen ihre Korrekturen.

Die nächste Stufe in dieser Schleife ist ein Build-Daemon, der einzige Prozess, der das Binary neu erstellen darf. Fixer schreiben Patches; der Daemon bündelt sie, baut einmal neu, führt die betroffenen Tests erneut aus und gibt die Ergebnisse zurück. Dies serialisiert die teuerste Operation, anstatt mehrere Agents sie unabhängig auslösen zu lassen.

Mikes Ansatz ist hier wichtig, weil viele Entwickler keine ausgebaute oder portierte Testsuite haben werden. Mike ließ Claude ein kleines Skript erstellen, um 7 reale Szenarien sowohl gegen den neuen Port als auch gegen die ursprüngliche Python-Codebasis laufen zu lassen, und verglich die Ergebnisse. Jedes fehlschlagende Szenario bekam seinen eigenen Fix-Agenten, und die Schleife lief, bis alle sieben bestanden.

Dann ging er noch einen Schritt weiter. Claude entwarf seine eigene End-to-End-Testsuite und führte sie autonom über Nacht aus, reparierte, was kaputt ging, und wiederholte dies vier Nächte hintereinander. Dadurch wurden die Papierschnitte erfasst, die keine Szenarioliste vorhergesagt hätte.

Die Lektion ist, dass eine fehlende Testsuite diesen Schritt nicht blockiert. Wenn Sie keinen Schiedsrichter erben können, lassen Sie Claude einen bauen. Ihre ursprüngliche Codebasis ist in beiden Fällen die Ground Truth.

Best Practices für Code-Migrationen

Jeder Durchlauf hat uns etwas gelehrt, was der vorherige nicht tat. Aber einige Praktiken haben sich in allen Projekten bewährt:

  • Befolgen Sie diese Anleitung nicht blind. Jede Migration ist anders. Behandeln Sie dies als Ausgangspunkt und planen Sie Ihre spezifische Migration mit Claude, bevor Sie sich darauf festlegen.
  • Konzentrieren Sie sich nicht auf einzelne Fehler. Einzelne Fehler sind die Aufgabe der Schleife. Ihre Aufmerksamkeit gehört den Mustern.
  • Machen Sie Reviews adversarial und die Verifikation mechanisch. Lassen Sie Skripte – einen Compiler, einen Diff, eine Testsuite – den Schiedsrichter sein.
  • Verwenden Sie nicht das größte Modell für alles. Kleinere Modelle bewältigen die Implementierung im großen Maßstab gut; heben Sie sich Ihr größtes Modell für Reviewer und für alles auf, was Regeln schreibt, die andere Agents befolgen werden.
  • Verlagern Sie die menschlichen Stunden nach vorne. Das Regelbuch und der Stresstest sind am zeitaufwändigsten. Alles danach sind hauptsächlich Warteschlangen, die abgebaut werden.

Reviewen Sie Schleifenergebnisse, nicht Code

Jarreds Bun-Migration ist jetzt in Produktion, obwohl jede Migration Kompromisse mit sich bringt. Zum Beispiel befinden sich etwa 4 % des Rust-Codes in "unsafe"-Blöcken, meist einzeilige Pointer-Operationen an C/C++-Grenzen.

Aber die neue Codebasis ist messbar besser. Jedes Speicherleck, das die Tooling des Teams erkennen kann, wurde behoben: Ein Benchmark mit 2.000 wiederholten Builds fiel von 6.745 MB Speicher auf 609. Das Binary ist auf Linux und Windows 19 % kleiner. Und sprachübergreifende Optimierung machte es 2–5 % schneller bei HTTP-Serving und realen Workloads wie Next-Build und TSC.

Wählen Sie die Codebasis, die Sie bisher toleriert haben, und fragen Sie Claude, wie der Migrationsprozess dafür aussieht.

Mit einem Klick speichern

Virale Artikel mit YouMind per KI tief lesen

Speichere die Quelle, stelle gezielte Fragen, fasse die Argumentation zusammen und verwandle einen viralen Artikel in wiederverwendbare Notizen in einem einzigen KI-Arbeitsbereich.

YouMind entdecken
Für Creator

Verwandle dein Markdown in einen sauberen 𝕏-Artikel

Wenn du eigene Langtexte veröffentlichst, wird die 𝕏-Formatierung von Bildern, Tabellen und Codeblöcken mühsam. YouMind macht aus einem ganzen Markdown-Entwurf einen sauberen, sofort postbaren 𝕏-Artikel.

Markdown zu 𝕏 testen

Mehr Muster zum Entschlüsseln

Aktuelle virale Artikel

Mehr virale Artikel entdecken