Warum repo-übergreifende Arbeit scheitert
Stellt euch ein Feature vor, das eine API, deren Client-Bibliothek und die Web-App betrifft. Gebt jedes Repo einem eigenen Agenten mit derselben vagen Beschreibung, und jeder tut etwas Vernünftiges. Der API-Agent benennt ein Feld um, der Client-Agent behält den alten Namen bei, der Web-Agent erfindet einen dritten. Jeder Agent hat in seinem eigenen Repo recht und zusammen falsch.
Zwei Dinge gehen schief: Der Vertrag zwischen den Repos driftet auseinander, und die Merge-Reihenfolge spielt eine Rolle. Mergt man den Consumer vor dem Producer, ist main kaputt, bis der andere PR landet.
Einmal planen, auf Architekturebene
Schreibt eine übergeordnete Story, die die gesamte Änderung beschreibt — die Mission, den neuen Vertrag, die Reihenfolge — und dann ein Sub-Issue pro Repository, jedes mit eigenen Abnahmekriterien. Linear unterstützt genau das mit übergeordneten Issues und Sub-Issues. [4] Das übergeordnete Issue hält die Architektur; jedes Sub-Issue ist klein genug für einen Agentenlauf. Wie man jedes einzelne schreibt, behandeln wir in unserem Guide zu Stories für Coding-Agenten.
Expand, migrate, contract
Der sicherste Weg, eine Schnittstelle zu ändern, von der mehrere Repos abhängen, ist eine alte. Martin Fowler nennt es parallel change:
"Parallel change, auch bekannt als expand and contract, ist ein Muster, um rückwärts-inkompatible Änderungen an einer Schnittstelle sicher umzusetzen, indem die Änderung in drei klar getrennte Phasen zerlegt wird: expand, migrate und contract." [1]
Expand
Der Producer akzeptiert und liefert sowohl die alte als auch die neue Form.
Migrate
Jeder Consumer wechselt zur neuen Form, ein Repo nach dem anderen.
Contract
Sobald jeder Consumer umgestellt hat, wird die alte Form entfernt.
Jeder Schritt ist für sich deploybar. Googles Buch über großangelegte Änderungen macht denselben Punkt in größerem Maßstab: "die größtmögliche atomare Änderung nimmt kontraintuitiv ab", je größer eine Codebasis wird, sodass große Änderungen in unabhängige Teile zerlegt werden. [2]
Die Reihenfolge als Abhängigkeiten kodieren
Behaltet die Reihenfolge nicht im Kopf. Markiert in Linear das Consumer-Sub-Issue als blockiert von dem Producer-Sub-Issue — blockierte Issues zeigen eine orangene Flagge unter "Blocked by" in der Issue-Seitenleiste. [5] Der Consumer-Teil startet erst, wenn der Producer-Teil gemergt wurde.
Parent: Show customers' chosen display name everywhere
├─ API-1 Expand: accept + return display_name alongside customer_name
├─ SDK-1 Use display_name in the typed client (blocked by API-1)
├─ WEB-1 Render display_name in account pages (blocked by SDK-1)
└─ API-2 Contract: remove customer_name (blocked by WEB-1)Blocked-by bedeutet gemergt — stellt also sicher, dass das Mergen des Producers ihn auch deployt oder veröffentlicht (bei einem SDK eine releaste Version), bevor der Consumer-Teil davon abhängt. Falls eure Deploys nicht beim Merge passieren, fügt der Producer-Story einen Release-Schritt hinzu.
Von oben nach unten gelesen ist das zugleich der Plan und die Merge-Reihenfolge — und jede Zeile lässt main deploybar. Dieselbe Idee steckt dahinter, parallele Arbeit nacheinander pro Branch zu mergen, was wir in unserem Guide zu parallelen Coding-Agenten behandeln.
Den Vertrag fixieren
Ein Vertrag, der nur in einer Story steht, kann trotzdem driften. Fixiert ihn im Code, damit ein Mismatch in CI fehlschlägt: ein geteilter typisierter Client, generiert aus einer Quelle, eine OpenAPI-Spec, gegen die beide Seiten validieren, oder consumer-driven Contract Tests. Pact beschreibt die Idee: Ein Vertrag besteht zwischen einem Consumer — "einem Client, der Daten empfangen möchte" — und einem Provider — "einer API auf einem Server, die die vom Client benötigten Daten liefert." [3] Die Tests des Consumers halten fest, was er erwartet; die CI des Providers prüft, dass er das weiterhin liefert.
Ein Agent über Repos hinweg oder einer pro Repo?
Cursors Cloud Agents können in Multi-Repo-Umgebungen laufen, wobei ein Agent mehrere Repositories in einem einzigen Lauf ändert und in jedem einen Pull Request öffnet. [6] Wann ist das das richtige Werkzeug?
Ein Agent über Repos hinweg
Eine kleine, eng gekoppelte Änderung, die sicher zusammen ausgeliefert werden kann — dieselben Leute besitzen jedes Repo, und ihr könnt sie gleichzeitig deployen.
Ein Agent pro Repo
Eine größere Änderung, unterschiedliche Owner oder etwas, das gestaffelte Deploys braucht. Getrennte Teile mit blocked-by-Reihenfolge halten jeden Schritt überprüfbar und deploybar.
Wo Aerunit hilft
Dieser Guide verlangt zwei Dinge: einen Plan für die gesamte Änderung und eine explizite Reihenfolge, die main deploybar hält. Aerunit liefert beides. Der Story-Writer liest jedes Repository, das die Änderung betrifft, und schlägt ein übergeordnetes Issue plus ein Sub-Issue pro betroffenem Repo vor, jedes mit Scope, Abnahmekriterien und Nicht-Zielen.
Aerunit folgt Linears blocks / blocked-by-Relationen, sodass beim Mergen des Producer-Teil-PRs die davon blockierten Sub-Issues automatisch für Cursor Cloud Agents eingereiht werden — der nächste Teil startet auf gemergtem Code, ohne dass ihr manuell verteilen müsst.
Ein Plan
Ein übergeordnetes Issue plus ein Sub-Issue pro Repo, geschrieben aus eurem tatsächlichen Code.
Explizite Reihenfolge
Blocked-by-Relationen machen die Merge-Reihenfolge in Linear sichtbar.
Ein Review pro Repo
Jeder Teil ist sein eigener PR, geprüft gegen sein eigenes Sub-Issue.
Häufige Fragen
Sollten wir für Agenten zu einem Monorepo wechseln?
Nicht nur wegen der Agenten. Ein Monorepo lässt eine Änderung atomar landen, aber selbst Google, mit einem der größten Monorepos, vermeidet große atomare Änderungen in diesem Umfang und teilt sie in kleinere, unabhängige Teile auf. Die Gewohnheiten in diesem Guide — einmal planen, expand-migrate-contract, explizite Reihenfolge — funktionieren in beiden Setups. [2]
Wie verhindere ich, dass Agenten in zwei Repos unterschiedliche Feldnamen erfinden?
Legt den Vertrag fest, bevor ein Agent startet, schreibt ihn in die übergeordnete Story und fixiert ihn im Code: ein geteilter typisierter Client, eine OpenAPI-Spec oder consumer-driven Contract Tests. Dann schlägt ein Mismatch in CI fehl statt in Produktion. [3]
Was, wenn ein nachgelagerter Teil fehlschlägt, nachdem der vorgelagerte gemergt wurde?
Genau dafür ist expand-migrate-contract da: Die vorgelagerte Änderung akzeptiert sowohl die alte als auch die neue Form, sodass nichts kaputtgeht, während der nachgelagerte Teil repariert oder erneut versucht wird. Entfernt die alte Form erst, wenn jeder Consumer umgestellt hat. [1]