Im Juli 2026 schrieb Robert C. Martin, dass er den von seinen Coding-Agents erzeugten Code nicht mehr liest.
Die Aussage erregte viel Aufmerksamkeit. Der Rest seines Beitrags ist für das Verständnis seiner Arbeitsweise wichtiger. Martin umgibt die Agents mit Unit-Tests, Gherkin-Akzeptanztests, QA-Verfahren, Mutation Testing, Coverage-Prüfungen und Qualitätsmetriken. Code verdient sich sein Vertrauen, indem er dieses System durchläuft.
Einen ähnlichen Punkt hatte er einige Monate zuvor gemacht. Statt die Implementierung zu inspizieren, sieht er sich Testabdeckung, Abhängigkeitsstruktur, zyklomatische Komplexität, Modulgröße und Ergebnisse des Mutation Testings an. Als das als vollständiger Verzicht auf Review gedeutet wurde, stellte er klar: „Ich reviewe eine Menge — nur nicht den Code."
Seine Anmerkungen beschreiben ein praktisches Problem in KI-lastiger Softwareentwicklung. Coding-Agents können Änderungen schneller produzieren, als Menschen sie lesen können. Sobald das Volumen des generierten Codes die Review-Kapazität des Teams übersteigt, kann eine zeilenweise Prüfung nicht die einzige Quelle von Vertrauen bleiben.
Mit demselben Problem beschäftigen wir uns bei vm0 seit acht Monaten. Der größte Teil der Implementierung in unserem Repository wird von Agents geschrieben — Vibe Coding, wie es umgangssprachlich heißt — während sechs Ingenieure dafür verantwortlich bleiben, was dieser Code in der Produktion tut.
Die Kurzfassung
vm0 ist eine vibe-coded Codebase: Agents schreiben den größten Teil der Implementierung, und sechs Ingenieure verantworten, was sie in der Produktion tut. Nach acht Monaten umfasst das Repository 1.329.170 Zeilen, und in einer einzigen Woche wurden 630 Pull Requests gemergt. Fünf Mechanismen tragen die Qualitätslast, die eine zeilenweise Review allein nicht mehr trägt.
- Angeglichene Umgebungen. Ingenieure und Agents arbeiten im selben Dev-Container, und jeder Pull Request kann seinen eigenen Datenbank-Branch bekommen. Ein Befehl, der beim Agent lief, läuft auch beim Menschen.
- Ausführbare Vorgaben. Striktes TypeScript, rund 135 typisierte API-Contract-Module, Oxlint, ESLint und Architekturregeln, und CI akzeptiert keine Warnungen. Was sich maschinell prüfen lässt, bleibt nicht der Review überlassen.
- Tests an Modulgrenzen. Eine Testing Trophy statt einer Testpyramide: Integrationstests über öffentliche Modulgrenzen, echtes PostgreSQL, echte Migrationen, Mocks nur an externen Systemen. Testcode macht etwa 36 Prozent des Repositories aus.
- Vollständige Feedback-Schleifen. Agents starten Anwendung und Datenbank, führen Migrationen aus und steuern einen echten Browser; danach berichten sie die ausgeführten Befehle, den getesteten Pfad und Screenshots. Der mittlere Pull Request wird in etwa 53 Minuten gemergt.
- Fortlaufendes Aufräumen. Knip entfernt toten Code deterministisch, tägliche Workflows beseitigen den AI Slop, den kein Linter benennen kann, und ein Muster, das oft genug wiederkehrt, wird zur Lint-Regel oder zum Typ.
Was Vibe Coding und Agentic Coding wirklich bedeuten
Vibe Coding heißt: ein LLM um Code bitten, ausführen, was dabei herauskommt, Änderungen verlangen und dem erzeugten Code selbst keine Aufmerksamkeit schenken. Martin Fowlers Definition ist bewusst eng, und er hebt die Formulierung hervor, man solle "vergessen, dass der Code überhaupt existiert". Das passt zu Prototypen, Wegwerf-Software und kleinen Werkzeugen mit geringen Folgen.
Agentic Coding, von Fowler agentische Programmierung genannt, ist das, was Teams tun, wenn sie das Ergebnis pflegen wollen. Ein Agent liest das Repository, ändert Dateien, führt Tests aus und arbeitet längere Zeit selbstständig, während Menschen Struktur und Verhalten verantworten und die Belege eines Laufs prüfen: Testergebnisse, Qualitätssignale, Previews und Produktionsverhalten.
Der Unterschied liegt nicht darin, wie viel Code das Modell schreibt, sondern darin, wohin die menschliche Aufmerksamkeit geht.
| Vibe Coding | Agentic Coding | |
|---|---|---|
| Autonomie des Agents | Prompten, ausführen, erneut prompten | Liest das Repository, ändert, testet, iteriert |
| Wer den Code liest | Niemand | Menschen lesen, was Risiko trägt |
| Was verifiziert wird | Ob das Ergebnis richtig aussieht | Typen, Contracts, Tests, Previews, Produktionssignale |
| Passt zu | Prototypen und Wegwerf-Werkzeugen | Software mit Wartungshorizont |
| Typisches Scheitern | Code, den niemand versteht | Verifikation zu schwach für die Menge |
Agents, die ein Repository bearbeiten, sind nur ein Teil einer größeren Verschiebung; die Seite für Nicht-Entwickler haben wir separat betrachtet.
Wir nennen vm0 oft ein vibe-coded Projekt, weil dieser Ausdruck zur gängigen Kurzform für überwiegend von KI geschriebene Software geworden ist. In Fowlers Begriffen liegt es näher an Agentic Coding. Unsere Ingenieure tippen weniger Implementierung als früher, verantworten aber weiterhin Architektur, Wartungskosten und Produktionsverhalten.
Je schneller die Codegenerierung wurde, desto mehr dieser Verantwortung wanderte in die Entwicklungsumgebung, das Typsystem, die Testsuite und automatisierte Wartungsworkflows.
Acht Monate Wachstum in einer vibe-coded Codebase
Das vm0-Repository wurde im November 2025 angelegt. Zum Zeitpunkt unseres jüngsten wöchentlichen Engineering-Scale-Reports war es rund achteinhalb Monate alt.
Das Repository enthielt:
| Kennzahl | Anzahl |
|---|---|
| Nicht-leere logische Zeilen | 1.329.170 |
| Produktionszeilen | 850.913 |
| Testzeilen | 478.257 |
| Quelldateien | 5.549 |
| Testdateien | 1.327 |
| Pakete | 44 |
| Commits auf dem Main-Branch | 14.005 |
Diese Zahlen stammen aus unserem wöchentlichen Engineering-Scale-Report für die Woche vom 20. bis 26. Juli 2026 und wurden direkt im Monorepo gemessen.
Testcode machte rund 36 Prozent der gemessenen Codebasis aus. Das ist ein Anteil am Codevolumen, keine Angabe zur Testabdeckung, vermittelt aber einen Eindruck davon, wie viel Implementierung sich rund um die Verifikation angesammelt hat.
Über drei jüngste volle Wochen hinweg machten sechs Engineers 541, 640 beziehungsweise 631 Commits. In der Woche vom 20. bis 26. Juli verzeichnete GitHub 630 gemergte Pull Requests. Sechs Engineers verfassten 556 davon, die restlichen 74 stammten von der Release-Automatisierung.
Die mediane Zeit vom Öffnen eines Pull Requests bis zum Merge lag bei etwa 53 Minuten. Das 90. Perzentil bei ungefähr 7,4 Stunden.
Bei dieser Änderungsrate bleibt menschliches Review nützlich, kann das gesamte Qualitätssystem aber nicht allein tragen. Wir brauchen unabhängige Signale an mehreren Punkten im Lebenszyklus einer Änderung.
Unser aktueller Ansatz hat fünf wiederkehrende Themen: konvergierende Umgebungen, ausführbare Vorgaben, grenzorientierte Tests, vollständige Feedback-Schleifen und kontinuierliches Aufräumen.
Die Entwicklungsumgebung mit Dev-Containern angleichen
Viele schwer reproduzierbare Fehler entstehen aus Zuständen, die nie in einem Pull Request auftauchen.
Eine Entwicklerin kann eine undokumentierte Umgebungsvariable haben, ein global installiertes Werkzeug, eine alte Konfigurationsdatei oder eine Datenbank, die seit Monaten läuft. Menschen gewöhnen sich an diese Details. Agents können sie in der Regel nicht sehen.
Wir haben die Host-Maschine schrittweise nicht mehr als Standard-Entwicklungsumgebung behandelt. Engineers und Agents arbeiten in einem Dev-Container. Das Entwicklungs-Image enthält die Projekt-Toolchain, PostgreSQL, pgvector, Chromium und Werkzeuge zur Browser-Automatisierung.
CI läuft auf versionierten Toolchain-Images, die aus derselben mehrstufigen Dockerfile-Familie gebaut werden. Entwicklungs- und CI-Images erfüllen unterschiedliche Zwecke, und die Produktion hat ihre eigene Deployment-Form. Die nützliche Eigenschaft ist Konvergenz: Tool-Versionen, Abhängigkeiten und Laufzeitannahmen sind explizit und versioniert.
Daraus ergibt sich eine klare Erwartung. Befehle, die ein Agent ausführt, sollten von einem Engineer im selben Entwicklungscontainer reproduzierbar sein. Prüfungen, die während der Entwicklung durchlaufen, sollten in CI unter einer eng verwandten Toolchain laufen.
Eine ähnliche Idee wenden wir auf Daten an. Jede Pull-Request-Vorschau kann einen eigenen Datenbank-Branch haben und echte Migrationen sowie Seed-Schritte ausführen. Ein Agent kann Daten anlegen, ändern und destruktive Tests wiederholen, ohne die bestehende Datenbank einer Entwicklerin zu leihen oder Zustand aus einem anderen Pull Request zu erben.
Änderungen an der Umgebung laufen über das Repository. Tool-Upgrades, Browser-Versionen und Datenbankerweiterungen werden genauso reviewt und verteilt wie Anwendungscode.
Engineering-Standards in Typen und Lint-Regeln ausführbar machen
Schriftliche Standards helfen Menschen, Designentscheidungen zu verstehen. Sie garantieren weit weniger, dass jede Änderung diesen Entscheidungen folgt, besonders während langer Agent-Sessions.
Stabile Regeln legen wir ins Typsystem, in Linter und in CI, wann immer sich die Regel zuverlässig ausdrücken lässt.
vm0 verwendet strikte TypeScript-Einstellungen, darunter strict und noUncheckedIndexedAccess. Einige Pakete aktivieren zusätzliche Prüfungen für ungenutzte Werte und implizite Rückgaben.
Die API nutzt eine schema-first typisierte REST-Vertragsschicht, gebaut mit der Typ-Maschinerie von tRPC und Zod-Schemata. Drizzle verbindet Datenbankzugriffe mit TypeScript-Typen. Zum Zeitpunkt dieser Bestandsaufnahme enthielt das Repository rund 135 Vertragsmodule.
Diese Entscheidungen fangen keine falschen Produktentscheidungen ab. Sie machen aber Schnittstellendrift früh sichtbar. Wenn sich ein Feld oder eine Response ändert, scheitern verwandte Aufrufer meist schon in der statischen Analyse. Der resultierende Fehler ist üblicherweise spezifisch genug, dass ein Agent ihn in seiner nächsten Iteration nutzen kann.
Linting deckt eine zweite Gruppe von Regeln ab. Die Plattform führt Oxlint, typbewusste Prüfungen und ESLint aus, dazu projektspezifische Architekturregeln. CI akzeptiert keine Warnungen. Warnungen, die unbegrenzt bestehen bleiben dürfen, werden zu Hintergrundrauschen, und Hintergrundrauschen lässt sich von Menschen wie Agents leicht ignorieren.
Wenn sich ein Problem wiederholt, überlegen wir, wohin die Prüfung gehört:
- Kann das Typsystem es ausdrücken?
- Kann ein Linter oder ein Strukturwerkzeug es zuverlässig erkennen?
- Erfordert es semantisches Urteilsvermögen über das Repository hinweg?
Die ersten beiden liefern schnelles, deterministisches Feedback bei jeder Änderung. Die dritte Gruppe behandeln wir mit wiederkehrenden Workflows, die später in diesem Artikel beschrieben werden.
Fehleranfällige Muster in AI-generiertem Code eingrenzen
Manche Sprachfeatures haben legitime Verwendungen und tauchen zugleich häufig in fragilem, agent-generiertem Code auf.
try/catch kann eine Fehlergrenze verwischen. Wenn ein Agent auf einen Fehlschlag stößt, ist ein Catch-Block mit Fallback ein einfacher Weg, den aktuellen Pfad am Laufen zu halten und dabei den ursprünglichen Fehler zu verlieren. Promise-.then() und .catch() mit async/await zu mischen, verteilt den Kontrollfluss über mehrere Stile.
Reacts useEffect erzeugt ein ähnliches Problem im State-Management. Es wird oft genutzt, um State zu kopieren, zwei Quellen der Wahrheit zu synchronisieren oder eine Reihenfolgeabhängigkeit zu kodieren, die aus dem Datenmodell schwer erkennbar ist.
Die zentrale Web-Plattform schränkt diese Muster standardmäßig ein. Eine begründete Ausnahme darf bestehen bleiben, mit einer expliziten Erklärung daneben.
Der Produktionscode der zentralen Web-Plattform enthält derzeit kein useEffect. Wir nutzen ccstate und andere effektfreie Muster, um Abhängigkeiten und Seiteneffekte expliziter zu modellieren. Eine kleine Zahl produktiver useEffect-Aufrufe existiert anderswo im Monorepo weiterhin, vor allem in geteiltem UI- und Desktop-Code — der Geltungsbereich der Aussage ist also relevant.
Diese Regeln sind aus wiederkehrenden Fehlern in diesem Repository entstanden. Wenn ein Muster wiederholt dasselbe Wartungsproblem erzeugt, überführen wir es von einer Review-Empfehlung in eine ausführbare Vorgabe.
Testen an Modulgrenzen: Testing Trophy statt Pyramide
vm0 folgt keiner klassischen Testpyramide. Unser Testleitfaden beschreibt eine Testing Trophy: statische Analyse als Basis, Integrationstests als dominante Schicht und eine kleine Zahl End-to-End-Tests für kritische User Journeys.
Unit-Tests sind relativ selten. Wir setzen sie gezielt für sicherheitskritische Logik, Algorithmen und Zustandsautomaten ein. Das meiste Geschäftsverhalten wird über die öffentliche Grenze eines Moduls getestet.
API-Tests rufen die echte Anwendung über ihre Verträge auf. Testdaten werden nach Möglichkeit über Produktions-Endpunkte vorbereitet, und Assertions erfolgen über öffentliches Verhalten. Tests greifen nicht direkt in einen internen Service und ändern keine Datenbanktabellen, weil sie sich damit an die aktuelle Implementierung koppeln würden.
Interne Infrastruktur bleibt echt, wo die Kosten vertretbar sind:
- PostgreSQL und pgvector
- Datenbankmigrationen
- das Dateisystem
- interne Services
- Mocks an den Grenzen zu externen Systemen
Diese Integrationstests laufen langsamer als stark isolierte Unit-Tests und brauchen eine vollständigere Umgebung. Dafür verkleinern sie den Abstand zwischen „der Test war grün" und „die Anwendung kann diese Operation mit einer echten Datenbank ausführen".
Grenztests lassen Raum für große interne Refactorings. Ein Agent kann Module umorganisieren, einen Service aufteilen oder die Datenzugriffsschicht ändern, während das öffentliche Verhalten geschützt bleibt.
Uncle Bob bevorzugt eine andere Mischung, mit starkem Einsatz von Unit-Tests, Gherkin und Mutation Testing. Das gemeinsame Prinzip ist unabhängige Verifikation. Der Prozess, der den Code erzeugt hat, sollte nicht die einzige Instanz sein, die behauptet, der Code funktioniere.
Coding-Agents eine vollständige Feedback-Schleife geben
Unsere frühen Coding-Agent-Läufe endeten oft mit einem vertrauten Bericht: Der Code wurde geändert und TypeScript ist grün; bitte starte die Anwendung und sieh dir die Seite an.
Damit bleibt die Hälfte der Entwicklungsschleife beim Engineer. Jemand muss noch immer eine Datenbank vorbereiten, die Services starten, einen Browser öffnen, Daten anlegen, den Fehler beobachten und ihn dem Agent zurückbeschreiben.
Agents haben inzwischen genug von der Entwicklungsumgebung, um mehr davon selbst zu erledigen. Sie können Anwendung und Datenbank starten, Migrationen ausführen, Testdaten anlegen, eine Pull-Request-Vorschau aufrufen und echte Browser-Interaktionen durchführen.
Browser-Verifikation fängt eine Klasse von Problemen ab, die Typprüfungen und API-Tests schlecht abdecken: kaputte Navigation, Ladezustände, die nie enden, Berechtigungsfehler, die nur in einem vollständigen Ablauf auftreten, und visuelle Regressionen.
Am Ende eines Laufs berichtet der Agent die ausgeführten Befehle, den getesteten Pfad und seine Beobachtungen. Bei Oberflächenänderungen kann er Screenshots beilegen. Ein Engineer kann diese Belege prüfen, bevor er entscheidet, ob er die Vorschau selbst öffnet.
Ein Screenshot ist kein Test und beweist nicht die Abwesenheit weiterer Fehler. Er senkt die Kosten, den Kontext des Agents zu rekonstruieren. Für eine kleine Oberflächenänderung sind reproduzierbare Schritte und ein abschließender Screenshot weit nützlicher als eine Nachricht, die Änderung „sollte behoben sein".
Die Qualität der Arbeit eines Agents hängt stark davon ab, welches Feedback er erhalten kann, ohne auf einen Menschen zu warten.
Branches kurz halten mit Trunk-based Development
Schnelle Codegenerierung kann einen großen Bestand an Branches erzeugen.
Langlebige Feature-Branches sammeln Merge-Konflikte, doppelte Arbeit und veralteten Kontext an. Je größer Pull Requests werden, desto schwerer und langsamer wird das Review. Wir setzen auf Trunk-based Development, halten Branches kurz und integrieren kontinuierlich rund um main.
Unsere Regeln für den Main-Branch verlangen:
- Pull Requests für Änderungen
- lineare Historie und Squash-Merges
- eine Merge Queue
- Turbo-, Rust- und Security-Checks
- kein routinemäßiges Umgehen erforderlicher Gates
Automatisierung folgt demselben Pfad. Ein Agent darf einen Pull Request erstellen, und manche risikoarmen Wartungsaufgaben dürfen Auto-Merge aktivieren, aber die Änderung läuft trotzdem durch CI und Merge Queue.
Größe und Lebensdauer von Pull Requests erklären zum Teil, wie 630 davon in einer Woche gemergt werden konnten. Eine kleine Änderung trägt weniger Kontext, lässt sich leichter verifizieren und kollidiert seltener mit Produktarbeit oder einer anderen automatisierten Reparatur.
Knip als Garbage Collection fürs Repository: toten Code entfernen
Codegenerierung fügt naturgemäß Dateien und Abstraktionen hinzu. Löschen braucht oft einen eigenen Prompt.
Nach einem Refactoring können alte Dateien im Repository zurückbleiben. Das Entfernen eines Features kann Exports, Abhängigkeiten und Entry Points hinterlassen. Diese Artefakte brechen selten Tests, machen die Codebasis mit der Zeit aber schwerer navigierbar.
Wir nutzen Knip, um ungenutzte Dateien, Exports, Abhängigkeiten und Entry Points zu finden. TypeScript kann bestätigen, dass der Code gültig ist; Knip fragt, ob er noch am System teilnimmt.
Der Rückstand hat für Coding-Agents zusätzliche Kosten. Das Repository ist eine ihrer wichtigsten Kontextquellen. Ein veralteter Helper oder eine aufgegebene Implementierung kann für den nächsten Agent, der sie liest, wie ein anerkanntes Muster aussehen.
Das Entfernen von totem Code verbessert also auch die Eingaben künftiger Läufe. Knip erledigt den deterministischen Teil dieser Arbeit schnell genug, um zu einer regelmäßigen Qualitätsprüfung zu werden.
Wiederkehrende Workflows zum Aufräumen von AI Slop
Knip und ESLint haben klare Grenzen. Viele Formen von Degradation brauchen Projektkontext und semantisches Urteilsvermögen.
„AI Slop" nutzen wir als praktisches Label für diesen Rückstand: unnötige Fallbacks, doppelte Abstraktionen, Tests, die eine öffentliche Grenze umgehen, oder defensive Zweige für unmögliche Zustände. Jeder Einzelfall mag harmlos wirken. In Summe machen sie das Repository schwerer verständlich und geben künftigen Agents schlechte Vorbilder.
Mehrere wiederkehrende Workflows auf vm0 suchen nach diesen Mustern.
Ein täglicher AI-Slop-Cleanup sucht nach neuem Rückstand und wählt eine kleine Menge risikoarmer Fixes mit hoher Konfidenz aus. Andere Workflows prüfen API-Tests, die in interne Services hineingreifen, React- und ccstate-Antipatterns sowie technische Schulden, die sich sicher abbauen lassen.
Jeder Workflow hält seine Änderungen eng. Er öffnet einen Pull Request und verlässt sich dann auf die normalen Typprüfungen, Lint-Regeln, Tests und die Merge Queue. Auch ein für Auto-Merge konfigurierter Pull Request muss dieselben Gates passieren.

Die Workflows versuchen nicht, jede technische Schuld in einem Durchgang zu tilgen. Ein kleiner täglicher Stapel ist leichter zu verifizieren und weniger störend als ein großes Aufräumen alle paar Monate.
Wenn ein wiederkehrender Workflow dasselbe Muster oft genug findet, erwägen wir, die Prüfung nach ESLint, Knip oder ins Typsystem zu verschieben. Der semantische Workflow dient als Ort, um die Regel zu beobachten und zu verfeinern, bevor sie zu einer günstigeren deterministischen Prüfung wird.
Diese wiederkehrenden vm0-Workflows laufen nach Zeitplan.
Flaky Tests in automatische Reparaturen verwandeln
Eine weitere Gruppe von Workflows startet bei Fehlschlägen in GitHub Actions.
Wenn ein Test auf dem Main-Branch oder in der Merge Queue fehlschlägt, liest ein Workflow die Logs, sucht nach Hinweisen auf Flakiness und betrachtet Retries, Timing und Umgebungsfaktoren. Stützt die Beweislage eine konkrete Reparatur, aktualisiert er Test oder Implementierung, öffnet einen Pull Request und lässt den vollständigen CI-Pfad erneut laufen.
Dass ein Retry grün wird, macht den ursprünglichen Fehlschlag nicht harmlos. Teams, die sich auf den Retry-Button verlassen, verlieren allmählich das Vertrauen in rote Builds. Sobald das passiert, werden fehlgeschlagene Checks zu einer weiteren Form von Hintergrundrauschen.
Ein automatisierter Reparatur-Workflow verwandelt einen sporadischen Fehlschlag in eine nachvollziehbare Codeänderung. Diagnose, Patch und Verifikation bleiben im Pull Request sichtbar. Engineers können risikoreichere Änderungen prüfen, während eng umrissene Fixes mit starker Beweislage die Merge Queue passieren dürfen.
Unser Qualitätssystem hat derzeit drei grobe Schichten:
| Phase | Mechanismen | Typische Anliegen |
|---|---|---|
| Beim Schreiben | TypeScript, Verträge, Drizzle, ESLint | Typfehler, Schnittstellendrift, bekannte Codemuster |
| Vor dem Merge | Knip, Integrationstests, echte Datenbanken, Vorschauen, Merge Queue | toter Code, Modulverhalten, vollständige Laufzeitergebnisse |
| Nach dem Merge | geplante und ereignisgesteuerte vm0-Workflows | AI Slop, semantische Antipatterns, flaky Tests, Architekturdrift |
Die Schichten speisen einander. Von Workflows gefundene Probleme können zu statischen Regeln werden. In CI oder Produktion gefundene Fehlschläge können zu Tests und neuen Engineering-Leitlinien werden.
Agents dauerhaft laufen zu lassen ist nicht kostenlos; wie sich diese Kosten senken lassen, haben wir separat beschrieben.
Wohin die menschliche Aufmerksamkeit beim Review von AI-generiertem Code geht
vm0-Engineers lesen weiterhin Code, besonders bei Architekturänderungen, sicherheitskritischer Arbeit, Zahlungen und Datenmigrationen. Wir haben „lies niemals den Code" nicht zur Teamregel gemacht.
Verändert hat sich die Verteilung der Aufmerksamkeit. Code-Lesen ist ein Signal unter Verträgen, Testgrenzen, Vorschauverhalten, Screenshots, Qualitätsmetriken und Workflow-Diagnosen.
Mehrere Entscheidungen brauchen weiterhin erfahrenes Urteilsvermögen:
- ob die Anforderung vollständig ist
- wo Modulgrenzen liegen sollten
- welche Fehlschläge behebbar sind
- wie viel Geschäftswirkung ein Fehler erzeugen könnte
- ob ein Sicherheitsmodell angemessen ist
- welches neue Fehlermuster die aktuellen Regeln nicht abdecken
Engineers pflegen außerdem die Umgebung rund um die Agents. Wenn sich ein Problem wiederholt, entscheiden wir, ob eine Typvorgabe, eine Lint-Regel, ein Test oder ein wiederkehrender Workflow dazukommt. Das Entwicklungssystem ist selbst zu einem wichtigen Engineering-Artefakt geworden.
Lesbarer Code zählt weiterhin. Die nächste Leserin kann eine Engineerin oder ein weiterer Agent sein. Verworrener Code verbraucht mehr Kontext, vergrößert den Umfang künftiger Änderungen und macht Verifikation unzuverlässiger.
Eine ähnliche Verschiebung gab es auf der Designseite, wo Design-as-Code visuelle Entscheidungen in dasselbe Repository und denselben Review-Pfad geholt hat.
Sicherheit und die Änderungen, die nicht schneller werden
Tempo verteilt sich nicht gleichmäßig. Bei vm0 gibt es eine kurze Liste von Änderungen, die ihr eigenes Tempo behalten: sicherheitskritische Arbeit, Zahlungen, Datenmigrationen und Architekturentscheidungen. Die liest ein Mensch Zeile für Zeile, unabhängig davon, wer oder was sie geschrieben hat.
Das Sicherheitsrisiko von KI-generiertem Code liegt nach unserer Erfahrung weniger in exotischen Schwachstellen als in plausibel wirkendem Code, für den sich niemand zuständig fühlt. Die Kontrollen, die zählen, sind gewöhnliche, wenn sie konsequent angewandt werden:
- Unit-Tests, die wir sonst sparsam einsetzen, verwenden wir gezielt für sicherheitskritische Logik, Algorithmen und Zustandsautomaten.
- Tests mocken nur an den Grenzen externer Systeme. Interne Infrastruktur bleibt echt, sodass eine gebrochene interne Zusage in CI auffällt statt in der Produktion.
- Agents arbeiten im Dev-Container gegen einen Datenbank-Branch pro Pull Request, nicht auf dem Rechner eines Entwicklers und nicht auf einer gemeinsamen Datenbank.
- Merge Queue und Pflichtchecks haben keine routinemäßige Umgehung, auch nicht für einen Pull Request, den ein Agent geöffnet und zum automatischen Merge markiert hat.
try/catchist standardmäßig eingeschränkt, damit ein Fehler nicht von einem Fallback verschluckt wird, den ein Agent eingefügt hat, um den aktuellen Pfad am Laufen zu halten.
Der Umgang mit Zugangsdaten ist ein eigenes Designproblem mit eigener Antwort: das Broker-Muster, das Tokens aus der Reichweite eines Agents hält, haben wir in einem eigenen Artikel beschrieben.
Nichts davon macht generierten Code für sich genommen sicher. Es verkleinert die Menge an Änderungen, bei denen eine menschliche Entscheidung die einzige Kontrolle ist, und macht diese Menge explizit.
Was diese Zahlen nicht zeigen
Der Wochenbericht belegt Repository-Umfang und Liefergeschwindigkeit. Er belegt für sich genommen keine Produktionszuverlässigkeit.
Die Wirkung auf Laufzeitqualität zu bewerten erfordert Verfügbarkeit, Produktionsfehlerraten, Incident-Zahlen, Change-Failure-Rate, Rollback-Häufigkeit und Mean Time to Recovery. Ein grüner CI-Lauf beschreibt einen Teil des Lieferprozesses.
Wir bauen diese Ergebniskennzahlen weiter auf. Engineering-Praktiken erklären, wie ein System Risiko steuert; Produktionsdaten zeigen, wie gut diese Steuerung funktioniert.
Häufige Fragen
Was ist Vibe Coding? Vibe Coding heißt, ein LLM um Code zu bitten, auszuführen, was zurückkommt, Änderungen zu verlangen und den erzeugten Code nicht zu lesen. Fowlers Definition ist bewusst eng: Man soll "vergessen, dass der Code überhaupt existiert". Das passt zu Prototypen, Wegwerf-Software und Werkzeugen mit geringen Folgen.
Was ist Agentic Coding? Agentic Coding ist eine länger laufende Form KI-gestützter Entwicklung, bei der ein Agent ein Repository liest, Dateien ändert, Tests ausführt und über längere Zeit selbstständig iteriert. Menschen verantworten weiterhin Architektur und Verhalten und prüfen die Belege eines Laufs statt jeder geschriebenen Zeile.
Was unterscheidet Vibe Coding von Agentic Coding? Die Aufmerksamkeit, nicht die Urheberschaft. Beim Vibe Coding wird der Code nie geprüft. Beim Agentic Coding arbeitet der Agent selbstständig, während Ingenieure die Belege drumherum prüfen: Testergebnisse, Qualitätssignale, Previews und Produktionsverhalten. vm0 wird meist als vibe-coded beschrieben; in Fowlers Begriffen ist es Agentic Coding.
Was ist AI Slop? AI Slop ist der Rückstand, den KI-generierter Code hinterlässt: unnötige Fallbacks, doppelte Abstraktionen, Tests, die eine öffentliche Grenze umgehen, defensive Zweige für unmögliche Zustände. Jeder einzelne Fall wirkt harmlos. In Summe machen sie ein Repository schwerer verständlich und geben dem nächsten Agenten schlechte Vorbilder.
Wie prüft man AI-generierten Code bei 630 Pull Requests pro Woche? Nicht Zeile für Zeile. Bei vm0 geht die menschliche Review dorthin, wo Urteilsvermögen nötig ist: Architektur, sicherheitskritische Arbeit, Zahlungen, Datenmigrationen. Alles andere tragen Mechanismen: strikte Typen und Contracts, Integrationstests an Modulgrenzen, echte Datenbanken in Previews pro Pull Request, Browser-Verifikation, Knip und eine Merge Queue ohne routinemäßige Umgehung.
Was sind Best Practices für Vibe Coding im großen Maßstab? Fünf haben sich bei vm0 über acht Monate gehalten: die Entwicklungsumgebung angleichen, damit Agents und Menschen dieselben Befehle ausführen; Standards in Typen, Lintern und CI ausführbar machen statt in Dokumenten; an Modulgrenzen gegen echte Infrastruktur testen; Agents eine vollständige Feedback-Schleife samt Browser geben; und fortlaufend aufräumen statt in seltenen großen Durchgängen.
Welche Sicherheitsrisiken hat KI-generierter Code?
Das übliche Risiko ist keine exotische Schwachstelle, sondern plausibler Code, für den niemand zuständig ist. vm0 hält sicherheitskritische Arbeit, Zahlungen und Datenmigrationen bei der menschlichen Review, nutzt Unit-Tests gezielt für diese Logik, hält interne Infrastruktur in Tests echt, schränkt Muster wie try/catch ein, die Fehler verschlucken, und erlaubt keine routinemäßige Umgehung von Pflichtchecks.
Erzeugt KI-generierter Code technische Schulden? Eine bestimmte Art davon: Code, der noch kompiliert und Tests besteht, aber nicht mehr am System teilnimmt, dazu semantische Rückstände, die kein Linter benennen kann. Knip entfernt den deterministischen Teil. Wiederkehrende Workflows erledigen den Rest in kleinen täglichen Chargen, und ein Muster, das oft genug auftritt, wird zur Lint-Regel oder zur Typvorgabe.
Wie viel der vm0-Codebase ist von KI geschrieben? Der größte Teil der Implementierung. In der Woche vom 20. bis 26. Juli 2026 stammten 556 der 630 gemergten Pull Requests von sechs Ingenieuren, den Rest übernahm die Release-Automatisierung, und den Großteil des Codes in diesen Pull Requests schrieben Agents. Was die Ingenieure verantworten, sind Architektur, Vorgaben und Produktionsverhalten.
Was ist eine Testing Trophy, und warum keine Testpyramide? Eine Testing Trophy setzt statische Analyse an die Basis, Integrationstests als dominante Schicht und wenige End-to-End-Tests darüber. vm0 nutzt sie, weil Tests über die öffentliche Grenze eines Moduls das Verhalten weiter schützen, während ein Agent die Implementierung darunter umbaut — was eine große Unit-Test-Schicht nicht leistet.
Wie findet man toten Code in einem von KI geschriebenen Repository? Codegenerierung fügt Dateien und Abstraktionen hinzu; Löschen braucht meist einen eigenen Auftrag. vm0 lässt Knip als regelmäßigen Check laufen, um ungenutzte Dateien, Exporte, Abhängigkeiten und Einstiegspunkte zu finden. TypeScript bestätigt, dass Code gültig ist; Knip fragt, ob er noch am System teilnimmt — und das ist die Frage, die bei totem Code zählt.
Ist vibe-coded Code sicher für den Produktivbetrieb? Das hängt davon ab, was ihn verifiziert, nicht davon, wer ihn getippt hat. Die Signale, die wir verlangen, haben sich nicht geändert: Typen und Contracts, Tests über öffentliche Grenzen, echte Infrastruktur und eine Pipeline, die grün sein muss. Die Zahlen in diesem Artikel beschreiben Repository-Größe und Liefergeschwindigkeit; Verfügbarkeit, Fehlerraten und Change-Failure-Rate beantworten die Produktionsfrage, und die stellen wir noch zusammen.
Nach acht Monaten
Acht Monate sind zu früh, um eine endgültige Methode auszurufen. Modelle, Agent-Werkzeuge und das Repository verändern sich weiter, und unsere Regeln und Workflows verändern sich mit ihnen.
Eine Verschiebung ist bereits deutlich. Mit schnellerer Codegenerierung haben Umgebung, Vorgaben, Tests und Feedback-System mehr von der Qualitätslast übernommen. Engineers verbringen weniger Zeit damit, Implementierung zu tippen, und mehr damit, Verhalten zu definieren, Grenzen zu entwerfen und Verifikation zu verbessern.
Die vm0-Codebasis wird weiter wachsen. Knip entfernt deterministischen Rückstand. Statische Regeln blockieren Fehlermuster, die wir bereits verstehen. Integrationstests schützen Modulverhalten. Wiederkehrende Workflows behandeln Degradation, die wir noch nicht mechanisch ausdrücken können.
Code zählt weiterhin. Wir nutzen jetzt mehr maschinell ausführbare Belege, um zu entscheiden, ob eine Änderung auf den Main-Branch gehört und ob ihre Implementierung im Repository bleiben sollte.



