Legacy-Analyse mit KI-Agenten: Fallstudie rtask
Drei Markdown-Personas als Staffel analysieren eine fremde Go-Codebase. Was die Staffel findet, was sie übersieht, und wo der Autor widerspricht.
Ich öffne ein fremdes Repo. Go-Code, knapp tausend Zeilen, geschrieben von einem Freund, den ich seit Jahren kenne. Ich habe nie eine Zeile davon gesehen. Jetzt soll ich beurteilen, wie gut der Code ist.
Normaler Weg: Claude aufmachen, Code reinwerfen, fragen. Drei Absätze später habe ich eine Antwort. Struktur sauber erklärt, ein paar Risiken genannt, ein paar Vorschläge. Klingt vernünftig.
Und ich habe keine Ahnung, ob das stimmt.
Das Problem ist bekannt, Gegenmittel sind diskutiert: Multi-Agent-Setups, gegenseitige Kritik, Rollenverteilung. Was seltener passiert: den Autor des Codes hinterher fragen, was die Analyse tatsächlich trifft und was nicht. Bei eigenem Code fällt die Lücke nicht so auf. Ich korrigiere mit, weil ich den Code kenne. Bei fremdem Code fällt sie hart auf: ich korrigiere nichts, weil ich nichts weiß.
Dieser Artikel beschreibt ein Setup, das ich auf den erwähnten Go-Code losgelassen habe. Nicht ein Agent, sondern drei. Nicht parallel mit Abstimmung, sondern als Staffel. Einer liest den Code, der nächste baut auf dessen Ergebnis auf, der dritte fügt zusammen. 17 Minuten Tool-Laufzeit. Danach habe ich den Autor gefragt, was stimmt.
Diese Rückkopplung ist der eigentliche Test. Ohne sie wäre der Artikel nur eine weitere “KI findet Bugs”-Geschichte.
1. Warum ein Agent allein bei fremdem Code nicht reicht
Der blinde Fleck beim Single-Agent-Lauf ist nicht fehlendes Wissen. Es ist Gleichförmigkeit. Ich frage einen Agenten nach einer Einschätzung. Er liefert eine. Mein Gehirn liest die Einschätzung und nickt. Was plausibel formuliert ist, glaube ich erst mal. Das ist menschlich und das Gegenteil von Analyse.
Bei eigenem Code ist das nicht so schlimm. Ich weiß, wo die Leichen liegen. Wenn der Agent sie übersieht, fällt es mir auf, und ich frage nach. Bei fremdem Code habe ich diesen Abgleich nicht. Der Agent sagt “sauber strukturiert”, und ich nicke, obwohl ich nichts weiß.
Was fehlt, ist organisierte Uneinigkeit. Nicht ein Kopf, sondern mehrere. Nicht ein Blickwinkel, sondern drei. Nicht Allrounder, sondern Spezialisten, die sich die Arbeit teilen.
rtask eignet sich als Fallstudie, weil es die typischen Merkmale eines echten Kundenfalls hat, aber klein genug ist, um den Lauf zügig durchzuziehen: fremdes Projekt, fremde Sprache (Go), rund tausend Zeilen Produktivcode, etwa ebenso viel Tests. Der Autor ist ein Freund, erreichbar. Er liest die Analyse gegen und sagt mir, was daneben liegt. Genau dieser letzte Schritt fehlt in den meisten “KI analysiert Code”-Posts. Ohne ihn bleibt jede Analyse nur ein weiteres plausibel klingendes Dokument.
2. Setup: Drei Reviewer als Staffel
Das Werkzeug, das ich einsetze, heißt claude-plugin-legacy-analyse. Es ist aktuell nicht öffentlich. In diesem Artikel geht es auch nicht um den Plugin-Code, sondern um das Setup dahinter. Denn das Setup ist das, was man in die eigene Arbeit übernehmen kann.
Drei Rollen, drei Reviewer, drei Ziel-Formate:
- Martin Fowler liest den Code. Er liefert eine Prosa-Beschreibung der Struktur und UML-Diagramme.
- Chris Rupp liest das Ergebnis von Fowler. Sie zieht daraus das Fachvokabular, die Geschäftsregeln und Anforderungen in Satzschablonen.
- Gernot Starke liest Fowler und Rupp. Er baut daraus ein arc42-Dokument, das Standardformat für Architekturdokumentation im deutschsprachigen Raum.
Die Rollen sind reine Markdown-Persona-Prompts. Kein Custom-Training, kein Fine-Tuning. Jede Persona beschreibt, wie der jeweilige Reviewer denkt, welche Fragen er stellt und in welches Format sein Ergebnis fließen soll. Das klingt banal. Es ist banal. Und es reicht.
Wichtig: Das ist keine parallele Diskussion mit Abstimmung am Ende. Das ist eine Staffel. Jeder Reviewer bekommt den Output des Vorgängers als Eingabe. Sie sprechen nicht miteinander, sie bauen aufeinander auf.
Was ich als Mensch tue, bevor der Lauf startet: den Scope festlegen (welches Repo, welche Dateien), das Plugin installieren, den Lauf starten. Danach nichts. Kein Zwischen-Prompt, kein Steuerversuch, keine Nachbesserung. 17 Minuten später ist der Lauf durch. Was ich danach tue: lesen.
3. Wie die drei aufeinander aufbauen
Die Reihenfolge ist nicht willkürlich. Sie spiegelt die Schichten, in denen man über Code spricht.
Fowler steht unten. Er liest den Quelltext. Seine Aufgabe ist reine Struktur: welche Pakete, welche Typen, welche Beziehungen, welche Abhängigkeiten. Er schreibt eine Prosa-Beschreibung und Sequenz- sowie Komponenten-Diagramme in PlantUML. Er fällt kein Architektur-Urteil. Er beschreibt, was da ist.
Rupp steht eine Ebene höher. Sie bekommt Fowlers Ergebnis, nicht den Quellcode. Das ist eine bewusste Einschränkung: Sie soll sich auf die fachliche Seite konzentrieren, nicht auf Implementierungsdetails. Sie extrahiert das Vokabular, das im Code vorkommt (bei rtask: TaskRun, API Key, Stored Key, Key Verifier, Webhook), legt ein Fachglossar an und formuliert Anforderungen in den Satzschablonen nach Rupp.
Starke steht ganz oben. Er bekommt die Ergebnisse von Fowler und Rupp. Er fügt sie zu einem arc42-Dokument zusammen: Einführung, Randbedingungen, Kontextabgrenzung, Bausteinsicht, Laufzeitsicht, Lösungsstrategie, Querschnittliches, Qualitätsanforderungen, Risiken, Glossar. Am Schluss ruft ein make arc42 einen Docker-Container auf, der die AsciiDoc-Quellen zu HTML und PDF baut.
Das funktioniert, weil jede Stufe eine Schicht höher abstrahiert. Code wird zu Struktur, Struktur wird zu Architektur. Jeder Reviewer bleibt bei seinem Thema und verliert sich nicht in den Details der Nachbar-Ebene.
Das Setup hat eine Grenze: Es gibt keine Kreuz-Validierung. Rupp und Starke lesen nicht den Code. Wenn Fowler eine Entscheidung falsch einordnet oder gar nicht aufnimmt, kann keine der nächsten Stufen das korrigieren. Das ist ein bewusster Kompromiss für Geschwindigkeit und klare Zuständigkeiten, aber er hat Folgen. Auf eine davon komme ich in Abschnitt 5 zurück.
4. Fallstudie rtask: 17 Minuten Tool-Lauf
rtask ist ein kleiner HTTP-Task-Runner in Go. Er stellt System-Befehle als authentifizierte HTTP-Endpunkte bereit. Man POSTet an einen Endpunkt, der Server führt den zugehörigen Befehl aus, man bekommt das Ergebnis zurück. 953 Zeilen Produktivcode, neun Go-Dateien, rund 1.300 Zeilen Tests. Chi als Router, urfave/cli als CLI-Framework, Prometheus für Metriken, Argon2id für Key-Hashing, CBOR für Serialisierung, TOML für Konfiguration.
Der Lauf: 17 Minuten Tool-Zeit. Die rund sechs Minuten dazwischen, die mit dem Lauf auf 23 zusammenkommen, sind menschliche Vorbereitung: Repo klonen, Scope prüfen, Briefing prüfen, Lauf starten. Keine Interaktion im Lauf.
Was dabei herauskam, nach Schichten sortiert:
- Fowler liefert eine Code-Analyse mit Paket-Struktur, Typ-Beziehungen, PlantUML-Diagrammen pro Modul, identifizierten Patterns (Aggregate Root
APIKeyStore, Value Objects, Dual-Path Authentication) und einer Einschätzung der Testabdeckung. - Rupp liefert ein Fachglossar (TaskRun, API Key, Stored Key, Key Verifier, Webhook, Async Result Retention), rund 30 Anforderungen in Satzschablonen und eine Liste der Geschäftsregeln, die im Code sichtbar sind.
- Starke liefert ein arc42-Dokument mit zwölf Kapiteln, inklusive Risiken-Sektion und einem über Docker gebauten PDF.
Ein konkreter Befund. In der Risiken-Sektion steht unter R-02: Fehlende Fehlerbehandlung bei save(). In AddKey wird der Rückgabewert ignoriert. Ein fehlgeschlagener Speichervorgang führt zu einem inkonsistenten Zustand, der Schlüssel existiert im Speicher, aber nicht auf der Festplatte.
Die Stelle im Code:
// AddKey generates a new key and adds it to the store
func (s *APIKeyStore) AddKey(name string) (string, error) {
uk := newUserKey(s.freeID(), 40)
sk := uk.hash()
storedString, err := encodeKey(sk)
if err != nil {
return "", fmt.Errorf("failed to encode stored key: %w", err)
}
s.encodedKeys[name] = storedString
s.storedKeys[sk.ID] = sk
s.keyIDs[name] = sk.ID
s.save() // <- Rückgabewert ignoriert
return encodeKey(uk)
}
Zwei Zeilen vorher gibt es sauberes Error-Handling für encodeKey. Der Aufruf s.save() direkt danach hat das nicht. Schlägt das Schreiben auf Platte fehl, etwa bei vollem Datenträger oder Berechtigungsfehler, hat der Server den Schlüssel im RAM, der Nutzer hat den Schlüssel in der Hand, nur die persistente Ablage fehlt. Beim nächsten Neustart ist der Schlüssel weg. Fowler hat die Stelle in seiner Code-Analyse aufgenommen; Starke hat sie in die Risiken-Sektion des arc42-Dokuments übernommen, als mittelschweres Risiko eingestuft und eine konkrete Abhilfe ergänzt.
Abbildung: Bausteinsicht Ebene 1 aus dem von der Staffel erzeugten arc42-Dokument. Nicht handgezeichnet, nicht nachbearbeitet, direkt aus dem Lauf.
Das Urteil des Autors nach dem Lesen: “Er hat den Code gut verstanden.” Die Risiken-Sektion sei die stärkste, “alles richtig erkannt”. Die meisten Punkte ordne er als Kleinigkeiten ein, nicht als Substanz. Was genau diese Einschätzung wert ist und was sie nicht deckt, dazu der nächste Abschnitt.
5. Ehrlich: was funktioniert, was nicht
Was die Staffel gut macht: Sie beschreibt fremden Code mit einer Tiefe, die ich in 20 Minuten ohne Werkzeug nicht erreiche. Das Fachvokabular wird sauber aus dem Code gezogen, die Struktur ist nachvollziehbar dokumentiert, die Risiken-Sektion hat den Finger an realen Schwachstellen (R-02 oben ist ein Beispiel). Das arc42-Format liegt als HTML und PDF vor, direkt an ein Team weitergebbar. Ohne Autor-Wissen. In unter einer halben Stunde.
Was sie nicht findet: bewusste Design-Entscheidungen, die aus dem Kontext des Autors kommen. Ein konkretes Beispiel.
Die übersehene Entscheidung: Argon2 für API-Keys
rtask nutzt Argon2id, um API-Keys zu hashen. Die Staffel ordnet das als solide Wahl ein. Fowlers Analyse schreibt, die Parametrisierung sei “für API-Key-Hashing angemessen”, Argon2 als Memory-Hard-Funktion sei “konservativ gewählt”. Das arc42-Dokument verstärkt das in der Lösungsstrategie: Argon2id werde “eingesetzt, um auch bei zukünftiger Hardware-Entwicklung sicher zu bleiben”.
Der Autor sieht das anders. Argon2 ist absichtlich langsam. Entworfen für Passwort-Hashing, also für den Fall, dass ein Angreifer versucht, schwache Nutzer-Passwörter durchzuraten. Bei rtask ist das nicht das Problem. Die API-Keys sind 40 zufällige Bytes, 320 Bit Entropie. Gegen solche Keys lässt sich nicht sinnvoll Brute-Force fahren. Es gibt nichts zu bremsen. SHA256 hätte gereicht und wäre schneller. Der Autor plant den Wechsel selbst.
Die Staffel hat das nicht gesehen. Warum nicht, liegt am Aufbau: Fowler prüft, ob eine Sicherheits-Entscheidung korrekt implementiert ist. Das ist sie. Rupp und Starke lesen Fowlers Ergebnis, nicht den Code. Sie können die Einschätzung nicht gegenprüfen, sie übernehmen sie und verstärken sie sogar. Und keiner der drei kann die Frage stellen, die die Staffel strukturell nie stellen wird: “War diese Entscheidung bewusst, oder Default aus Gewohnheit?”
Das ist der Kern. Die Staffel erkennt gängige Muster als korrekt. Sie erkennt nicht, wenn ein korrektes Muster am falschen Problem hängt. Das liegt bei diesem Setup nicht an einer prinzipiellen Grenze, sondern an der Rollenverteilung: Fowler prüft Code-Struktur, Rupp Fachsprache, Starke Architektur-Dokumentation. Keiner der drei hat den Auftrag, Sicherheitsmechanismen auf Angemessenheit zu prüfen. Ein vierter Reviewer mit einem generischen Auftrag in diese Richtung, etwa “prüfe für jeden verwendeten Sicherheitsmechanismus, gegen welche Bedrohung er schützen soll, und ob er dafür angemessen dimensioniert ist”, hätte eine reale Chance, die Argon2-Stelle zu finden. Ob er sie tatsächlich findet, habe ich nicht getestet.
Eigenständig wird die Staffel dadurch nicht. Jede zusätzliche Rolle kostet Lauf-Zeit und schafft neue Schnittstellen, an denen Reviewer einander widersprechen können. Was ein Historiker-Reviewer lesen kann, hängt davon ab, was das Projekt an Spuren hinterlässt: Welche Alternativen hat der Autor verworfen, und warum? Welche nicht-funktionalen Anforderungen waren ihm wichtig? Welche Features hat er bewusst weggelassen?
Bei einem Projekt wie rtask, das klassisch entstanden ist, stehen solche Begründungen weder im Code noch in Commit-Messages. Sie existieren im Kopf des Autors, bis jemand fragt. Anders wird es, wenn der Code selbst im Dialog mit einer KI entstanden ist und der Agent während der Entwicklung Entscheidungen mitdokumentiert hat. Dann hinterlässt der Dialog Spuren, die eine spätere Analyse lesen kann. Das wird sich in den nächsten Jahren verschieben. Für Legacy-Analyse heute gilt es noch: die wichtigsten Begründungen sind nicht dokumentiert, sie sind erinnert.
Was heißt das für den Einsatz? Die Staffel liefert eine gute erste Fassung und ein Dokument, auf das man mit dem Autor zeigen kann. Mehr auch nicht. Die Prüfung, ob die Analyse trägt, passiert zwischen Mensch und Mensch, nicht innerhalb des Werkzeugs.
6. Wie ein Kunde das in die eigene Codebase bekommt
Das Plugin, das ich hier eingesetzt habe, ist auf Anfrage zu haben. Es ist kein Geheimnis. Aber es ist nicht das, was ein Kunde für seine Codebase braucht. Generische Plugins liefern generische Ergebnisse. Wer mit KI-gestützter Analyse ernsthaft weiterkommen will, kommt mit einem Werkzeug von der Stange nur so weit, wie das Werkzeug zufällig zur eigenen Situation passt. Was die Arbeit trägt, sind Rollen, die zugeschnitten sind: welches Vokabular zählt in dieser Domäne, welche Sicherheits-Anforderungen liegen an, welche Architektur-Standards gelten im Haus, welches Ziel-Format braucht das Team am Ende.
Übertragbar aus diesem Artikel ist das Muster: drei Rollen, Markdown-Personas, Staffel-Reihenfolge vom Code zur Architektur, ein Ziel-Format am Ende. Damit lässt sich in einer beliebigen Coding-Umgebung ein Setup bauen, das zur eigenen Codebase passt. Die Arbeit liegt nicht im Installieren eines Tools, sondern im Schneiden der Rollen.
Was vorher geklärt sein muss, damit der Lauf sich lohnt:
- Scope. Reale Codebases haben 50.000 oder 500.000 Zeilen, nicht tausend. Das macht sie nicht ungeeignet, es ändert das Vorgehen: Ein erstes Team erkennt die grobe Struktur, also Module, fachliche Grenzen, Schnittstellen, und gleicht diese Landkarte mit jemandem ab, der das Haus kennt. Nachgelagerte Teams nehmen einzelne Kontexte vor, prüfen Schnittstellen, klären Detailfragen. Das ist mehr Arbeit als ein einzelner Lauf. Und der Weg, auf dem die Methode bei realen Codebases überhaupt greift. Der rtask-Lauf in diesem Artikel ist der einfachste Fall: eine Codebase, die klein genug ist, um sie in einem Staffellauf zu erfassen. Bei größeren Codebases wird aus einem Lauf eine Abfolge von Läufen mit Zwischenergebnissen und ggf. menschlicher Prüfung an den Übergabestellen.
- Verhältnismäßigkeit. Ein großes Team auf eine 500k-Zeilen-Codebase loszulassen, das viel analysiert und viel dokumentiert, ist technisch einfach. Nur: Wenn am Ende kein Mensch die Ergebnisse prüfen, bewerten oder lesen kann, ist die Arbeit verschwendet, im Datacenter und im Team. Iterative Läufe schonen Rechenzeit, Kosten und Aufmerksamkeit. KI-Einsatz ist derzeit verlockend günstig. Das ist kein Grund, mit Kanonen auf Spatzen zu schießen. Es gibt Situationen, in denen ein großes Team die richtige Wahl ist. Default ist es nicht. Die Kunst liegt darin, Reviewer, Laufzeit und Detailgrad so zuzuschneiden, dass herauskommt, was das Projekt wirklich braucht.
- Zielgruppe des Outputs. Hier setzt ein ehrlicher Einwand des rtask-Autors an: “Wenn ich überlege, was ich eher verstehen werde, 2k Code-Zeilen oder die 9-seitige Architektur, würde ich wahrscheinlich den Code bevorzugen.” Das stimmt für den Autor. Er kennt sein Projekt. Es stimmt nicht für neue Teammitglieder, für Audits, für Übergaben, für externe Dienstleister, die einspringen. Für die ist die arc42-Doku der schnellere Einstieg, nicht der Code.
- Wer liest das Ergebnis? Danach richtet sich, welcher der drei Outputs am meisten Aufmerksamkeit beim Lektorat verdient. Rupps Fachglossar für den Product Owner. Fowlers Prosa-Beschreibung für den neuen Entwickler. Starkes arc42 für die Architektur-Runde.
Ein pragmatischer Einstieg: klein anfangen. Einen Ausschnitt wählen, zuerst nur Fowler laufen lassen, den Output mit dem Fach-Autor durchgehen. Erst wenn Fowler belastbar wirkt, die komplette Staffel durchlaufen lassen und mit dem Team besprechen. So merkt man früh, wo die Reviewer die eigene Domäne nicht treffen, ohne dass man drei Stunden später vor einer 40-seitigen Doku sitzt, die in den falschen Bahnen läuft.
Wann das Werkzeug nicht passt: Greenfield-Entwicklung, da gibt es wenig zu analysieren, weil wenig da ist. Ein-Personen-Projekt mit aktivem Autor, der den Code im Kopf hat, für ihn ist der Zeitgewinn klein. Reine Performance-Optimierung, die braucht Profiling-Daten, nicht Struktur-Beschreibung.
Wofür es passt: fremde Codebase, Team-Übergabe, Audit-Vorbereitung, Onboarding in ein Legacy-System, Einschätzung einer Akquisition. Überall dort, wo jemand gefragt ist: “Was genau haben wir hier eigentlich?“
7. Fazit
Drei Markdown-Personas, nacheinander ausgeführt, liefern in unter einer halben Stunde eine brauchbare erste Fassung einer fremden Codebase: Code-Struktur, Fachvokabular, arc42-Dokument inklusive Risiken-Sektion. Für eine Übergabe, ein Audit oder ein Onboarding ist das eine bessere Ausgangslage als ein leeres Blatt.
Die Grenze ist ebenso konkret. Die Staffel prüft, ob Entscheidungen sauber umgesetzt sind. Sie prüft nicht, ob sie zum Problem passen. Dafür hat keiner in der Kette den Auftrag. Argon2 für 320-Bit-Keys ist ein Beispiel. Wenn der Autor erreichbar ist, bleibt das Gespräch mit ihm der Prüfstein, den das Werkzeug nicht ersetzt. Wenn er nicht erreichbar ist, der typische Legacy-Fall, ist die Staffel das Beste, was man bekommt, bevor jemand ins Blaue arbeitet.
Was übertragbar ist, ist das Muster: Rollen, die zur eigenen Domäne passen, in eine Staffel vom Code bis zur Architektur, mit einem Ziel-Format am Ende. Die Zeit geht ins Zuschneiden der Rollen und ins Nachprüfen der Ergebnisse, nicht ins Installieren eines Plugins.
Wer ein Legacy-System übernimmt, hat danach keine fertige Dokumentation. Aber ein Team, das weiß, welche Fragen es stellen muss.