Ein Produktions-Harness für Claude Code: Sechs Schichten von Slack bis zur zusammengeführten MR.
Wie ein sechsschichtiger Harness Slack-Tickets in zusammengeführten Code umwandelt: Eingang von Ereignissen, geschützte Agentenschleifen, dauerhafter Zustand, Selbstheilung, Überwachbarkeit und Steuerung durch den Operator.
Quellen: Building a Production Agent Harness: Turning Claude Code Into a Multi-Agent Engineering Pipeline
Setzt man ein KI-Modell allein ein, erhält man im Grunde einen „Kopf in einem Glas“. Es kann Code schreiben und Funktionen aufrufen – doch es wird weder Ihre privaten Slack-Nachrichten um 3 Uhr morgens lesen, noch einen fehlgeschlagenen CI-Job erneut ausführen, noch Konflikte in offenen Merge Requests lösen oder daran erinnern, dass ein Reviewer gestern eine Frage gestellt hat und niemand geantwortet hat.
Was das Modell zu etwas Nützlichem macht, ist das zugrundeliegende Framework: die Laufzeitarchitektur, die „Sinne“, „Hände“ und „Gedächtnis“ bereitstellt. Zu ihren Bestandteilen gehören die Aufnahme von Ereignissen, die Orchestrierung von Agenten, dauerhafte Zustandsverwaltung, selbstheilende Schleifen, Überwachungsfunktionen sowie Möglichkeiten für den menschlichen Operator, das System zu steuern. Das unten beschriebene System ist ein Produktivsystem – keine Forschungsdemo. Es überwacht einen Slack-Kanal, erstellt Merge Requests für fünf interne Repositorien, beantwortet über Nacht die Kommentare der Reviewer und repariert fehlgeschlagene CI-Ausführungen ohne Aufforderung.
Es handelt sich um einen internen, mehragentigen Pipeline-System, das auf Claude Code basiert. Es läuft bereits seit mehreren Monaten ununterbrochen, übernimmt Aufgaben von Slack und leitet echte Ingenieurarbeiten weiter. Im Folgenden wird ein Überblick gegeben: Was es tut, wie die einzelnen Komponenten miteinander verbunden sind sowie die Entwicklungsprobleme, die das Design geprägt haben.
Die Abschnitte werden in dieser Reihenfolge behandelt: Warum überhaupt ein solches System nötig ist, was dieses System leistet, die drei Lücken, die es schließt, sechs Ebenen (Ereignisverarbeitung, Agent-Orchestrierung mit näherer Betrachtung des autonomen Schleifenmechanismus und der Selbstverbesserungs-Ebene, persistenter Zustand, Selbstheilungsfunktionen, Überwachbarkeit sowie menschliche Steuerung), einige zusätzliche Aspekte außerhalb der Ebenen, eine Schritt-für-Schritt-Anleitung sowie ein Vergleich mit anderen ähnlichen Systemen.
Warum eine Chat-Window und einige Tools nicht ausreichen
Als im Jahr 2023 Plugins für Chat-Assistenten auftauchten, versuchten viele Teams den offensichtlichen Kurzweg. Sie setzten eine Chat-Oberfläche vor ein LLM, gaben ihm einige Tools zur Ausführung von Funktionen und bezeichneten das Ergebnis als „den Engineering-Agenten“. Diese Konfiguration funktioniert fast in einer Demo, überlebt aber nie in der Produktion. Bereits innerhalb einer Woche treten drei Fehlermuster auf.
- Der Kontext verschwindet, wenn der Benutzer das Tab schließt. Das Gedächtnis muss länger bestehen als eine einzelne Chat-Sitzung. Eine echte Ingenieurstaufgabe dauert Tage: Ticket erstellen, neue Branch anlegen, Entwurf verfassen, Überprüfung abwarten, Kommentare beantworten, auf grünes CI warten und schließlich fusionieren. Kein einzelner Modellaufruf kann all das speichern.
- Nichts reagiert auf äußere Veränderungen. Ein Überprüfer kommentiert um 16 Uhr. Das CI bricht beim dritten Commit zusammen. Ein Teamkollege antwortet im Thread. Der Agent muss auf diese Ereignisse reagieren, anstatt endlos zu prüfen oder darauf zu warten, dass jemand ihn erneut anweist.
Die Behebung dieser Probleme ist die Aufgabe des Harness. Genau das unterscheidet auch eine einfache Chat-Tab-Option von Claude Code selbst, von Cursors Hintergrundagenten, von Devin oder vom hier beschriebenen System. Das zugrunde liegende Modell ist bei allen nahezu austauschbar. Was sich unterscheidet, ist der Harness, der um dieses Modell herumgebaut ist.
Das Modell erreicht die Außenwelt nur über den Harness, und der Harness übernimmt fast die gesamte Ingenieurarbeit, die dafür sorgt, dass ein LLM sich wie ein System verhält.
Die Aufgabe, für die das Tool entwickelt wurde
Das ursprüngliche Problem war konkret. Ein Slack-Kanal, nennen wir ihn #support, sammelt etwa 30 Tickets pro Woche. Jedes Ticket erfordert eine Untersuchung und in der Regel anschließende Codeänderungen in einem von fünf Repositories. Ein Ticket kann sich über mehrere Tage hinziehen. Reviewer kommentieren Pull Requests, CI-Tests scheitern manchmal, und einige Untersuchungen erweisen sich als Wiederholungen von denen des Vormonats. Das Team, das diese Last tragen musste, wurde ständig abends und an Wochenenden angerufen, und es verbesserte sich nichts, da immer wieder die gleichen Ticketmuster auftauchten.
Das Tool hat drei Aufgabenbereiche, geordnet nach dem Grad der Einmischung:
- Untersuchen. Wenn ein neues Ticket in
#supportankommt, verfolgt es den Thread, sammelt Kontext aus verschiedenen Repositories und veröffentlicht eine strukturierte Analyse in diesemselben Thread.
Diese dritte Aufgabe unterscheidet dieses System von einfachen Ticketing-Bots. Die Rohstoffe des Systems sind sein eigener Quellcode, und das LLM kann durch Pull-Requests, die einer menschlichen Prüfung unterliegen, darauf schreiben.
Das System besteht aus sechs logischen Schichten, von denen jede unten in eigenen Abschnitten behandelt wird.
Die drei Lücken, die ein reines Modell nicht schließen kann
Hinter der gesamten Konstruktion steht eine Idee: Ein zustandsloser, rein reaktiver LLM ist kein Produktivsystem. Die sechs Schichten dienen dazu, drei Lücken zu schließen, die das Modell allein nicht überbrücken kann.
Die erste Lücke ist die Reaktivität. Ein Modell kann sich nicht selbst aktivieren. Schicht 1 (Ereignisverarbeitung) kümmert sich darum, da Slack-Meldungen, GitLab CI-Ergebnisse und PagerDuty-Seiten alle in eine einzige Dispatch-Queue fließen. Das LLM prüft niemals selbst nach neuen Daten – es wird einfach aufgerufen.
Persistenz ist die zweite Lücke. Modelle vergessen alles zwischen den Sitzungen und verlieren den Kontext, wenn die Arbeit zwischen Maschinen verschoben wird. Zudem können sie nicht unterscheiden, ob etwas bereits bearbeitet wurde oder ob eine Änderung tatsächlich im Quellsystem angekommen ist. Schicht 3 (persistenter Zustand) behebt dieses Problem: In-Memory-Strukturen entfernen Duplikate innerhalb eines Prozesses, lokale JSON-Dateien speichern die operativen Informationen, und durch git-synchronisierte Arbeitsräume wird ein dauerhafter Zustand der Fälle gewährleistet. Die Sitzungskontinuität zwischen Maschinen, die später beschrieben wird, basiert auf derselben Idee – nämlich dass der Zustand im git-System liegen sollte und niemals innerhalb eines laufenden Prozesses.
Die dritte Lücke ist die Qualität. Wenn sie unstrukturiert bleibt, zieht ein Reasoning-Loop eines LLM zuversichtliche Schlussfolgerungen aus dürftigen Beweisen, beendet Untersuchungen, bevor alle erreichbaren Quellen überprüft wurden, und erstellt MR-Beschreibungen, die von Anfang an wie maschinengeschrieben wirken. Layer 2 (Agent-Orchestrierung) sowie der Untersuchungsloop begegnen diesem Problem durch strukturierte Ausgabeverträge, eine Qualitätskontrolle bei jeder Iteration, eine gegenseitige Überprüfung nach Abschluss des Loops sowie selbstheilende Schleifen innerhalb des externen Zyklus aus Codeänderungen, CI-Tests und Merges.
Die Kumulation ist es, die die Schichten miteinander verbindet, denn jeder abgeschlossene Fall beschleunigt den nächsten. Genehmigte Untersuchungen werden zu Einträgen in der Wissensdatenbank. Genehmigte MRs verwandeln sich in Muster, auf die der Lückenanalyse-Tool verweisen kann. Ein abgeschlossener Fall führt zu einem Verbesserungs-MR, das sich auf den Harness selbst richtet. Mit jedem Zyklus werden weniger Ticketarten schlecht bearbeitet.
Ebene 1: Wie Ereignisse das System aktivieren
Drei externe Signalquellen können das Harness aktivieren:
- Slack-Nachrichten, also Kanalverweise, Antworten in Threads sowie Admin-Befehle, die als Privatnachricht an sich selbst gesendet werden.
- Aktivitäten in GitLab, d.h. Kommentare zu Pull-Request-Überprüfungen, Ergebnisse von Pipelines sowie Pipeline-Fehler.
- PagerDuty-Alarme, die verwendet werden, wenn eine On-Call-Seite auf ein Ticket verweist, das das Harness bereits gesehen hat, damit der frühere Kontext wieder sichtbar wird.
Die drei Quellen unterscheiden sich in Latenz und Zuverlässigkeit, weshalb jede ihre eigene Eingangsroute hat.
Zwei praktische Details kommen in der standardmäßigen Version dieses Diagramms nie vor.
Eventuelle Konsistenz. Der Endpoint conversations.history von Slack kann um 1 bis 30 Sekunden im Rückstand sein. Ein Abfrageskript, das ein leeres Ergebnis sieht und naiv seinen Cursor voranschreibt, überspringt dauerhaft alle Nachrichten, deren ts-Wert in diesem Zeitraum liegt. Dadurch bleibt der Cursor bei leeren Abfragen „eingefroren“ und der nächste Versuch beginnt wieder mit dem gleichen ältesten Zeitstempel, bis zumindest eine Nachricht zurückkommt. Ein nach Nachrichten-ts sortiertes Deduplikationsset filtert die durch diese Wiederholungsversuche entstehenden Duplikate heraus.
Socket Mode zusammen mit einem Poller – das perfekte Duo. Socket Mode liefert Antworten der Threads mit einer Latenz von unter einer Sekunde, doch WebSocket-Verbindungen können abbrechen. Der Poller fungiert als Sicherheitsnetz und fängt alles auf, was Socket Mode übersehen hat. Beide Methoden teilen sich eine socket-dedup-Datei, damit keine Nachricht zweimal versandt wird. Entfernt man diesen Schutz, verschwinden alle während eines abgebrochenen Verbindungszeitraums eingehenden Nachrichten stillschweigend, ohne dass der Betreiber erfährt, dass sie übersehen wurden.
Der MR-Monitor-Cron-Loop verhält sich anders. GitLab schickt keine Überprüfungskommentare in den Pipeline, wodurch das Abfragen die einzige Option ist – und das Skalieren des Abfragens selbst erwies sich als schwierig. Jeder zusätzliche, lange laufende MR, den das System übernimmt, verlängert den 10-minütigen Loop, wodurch sich für tote Threads Cursor anhäufen, und jeder davon kostet pro Zyklus einen Slack-API-Aufruf. Ohne Eingreifen führten sie zu anhaltenden 429-Rate-Limit-Problemen, die das wichtige Abfragen behinderten. Die Lösung löscht einen Cursor automatisch, wenn die übergeordnete API thread_not_found antwortet, sodass er aus dem Loop des nächsten Zyklus entfernt wird. Vor der Lösung führte ein Zyklus stundenlang 12 Wiederholungsversuche durch; danach keine mehr.
Layer 2: Wie Agenten orchestriert werden
Der LLM läuft tatsächlich hier. Das Harness startet Arbeitsprozesse als vorübergehende systemd-Einheiten, und jeder davon erhält eine JSON-Datei mit Angaben zum zu ausführenden Workflow, dem zu verwendenden case_dir sowie der ihm zugeordneten Thread-Nummer.
Jeder Pipeline entspricht einem einzigen langen Claude Code-Ausführungsvorgang (dem „Gehirn“), der eine sorgfältig ausgewählte Anfrage sowie einen schreibbaren case_dir erhält. Dieser Ordner dient als Arbeitsfläche des Agenten und enthält das TASK.md des Falls, eine wachsende Anzahl von Transkripten in der Form followup_transcript_*.md, alle von den Agenten erstellten gap_report*.md-Berichte sowie Zwischenergebnisse im JSON-Format.
Die Reihenfolge, in der die Agenten arbeiten, ist Teil des Designs. Anstelle eines einzigen Agenten, der alles erledigt, sind mehrere spezialisierte Agenten miteinander verbunden, wobei jeder an einer festgelegten Stelle die Aufgabe weitergibt:
oncall_runführt die erste Untersuchung durch – bis zu 20 Überlegungsschleifen mit einer Qualitätsprüfung – und endet mit einer ausdrücklichen Selbstkritik. Sein Ausgabeformat besteht aus einerANALYSIS.md-Datei, die beschreibt, was falsch ist, sowie einerTASK.md-Datei, die angibt, was zu tun ist.case_followupist der langzeitige Chat-Agent. Ein Operator kann tagelang per privater Nachricht in einem Fallthread antworten, und jede Antwort ruftcase_followuperneut mit dem gesamten bisherigen Gespräch auf. Zudem ruft er alle N Antworten einmalgap_analyzerals Unteragent auf; dieser Kreislauf erzeugt diegap_report*.md-Dateien, die auf den eigenen Code des Systems verweisen (der Selbstverbesserungskreislauf wird weiter unten erläutert).
finalize_case ist der Konsolidator. Sobald ein Fall vier Stunden lang inaktiv war oder ein Operator admin: finalize <case> ausführt, sammelt es alle Lückenberichte ein, entfernt die Falschpositiven und eröffnet einen einzigen MR mit den überlebenden Korrekturen. Dieser MR bezieht sich auf die Harness-Codebasis und nicht auf das ursprüngliche Repo des Tickets – das ist der Selbstverbesserungskreislauf in konkreter Form.dev-agent ist das Element, das die praktische Arbeit erledigt. In seinem eigenen git-Worktree pro Fall bearbeitet es den Code, führt Push-Aktionen durch, überwacht den CI-Prozess, behebt Störungen im CI und antwortet auf Kommentare der Prüfer. Es arbeitet in drei Modi: address_review, fix_ci und task (die ursprüngliche Implementierung).In diesem Diagramm gibt es zwei Details, die leicht übersehen werden können.
Zunächst berührt nichts den Haupt-Checkout, da alle Arbeiten in Worktrees durchgeführt werden. Dadurch können mehrere Fälle gleichzeitig ablaufen, ohne miteinander in Konflikt zu geraten. Der Poller sowie der Dev-Agent-Dispatcher fügen den Pfad des Worktrees zum Payload hinzu, sodass die LLM den Haupt-Checkout überhaupt nicht zu Gesicht bekommt.
Zweitens dient case_dir als Ankerpunkt für alles. Zustandsdateien in ~/.harness/ (siehe Abschnitt zur Persistenz) verknüpfen jeden Slack-Thread mit einem case_dir, und der Agent interpretiert alle Pfade relativ dazu. Dadurch wird alles Weitere einfacher: Man verschiebt den Ordner, aktualisiert die Karte, und jeder Workflow folgt automatisch.
Das Diagramm zeigt an, was ausgeführt wird. Der nächste Abschnitt erklärt, wie dies funktioniert – also die Mechanismen, durch die ein Slack-Befehl zu einer abgeschlossenen Untersuchung führt.
Der autonome Kreislauf, Schritt für Schritt
Falls jemand fragt, was dieses System eigentlich tut, lautet die kürzeste ehrliche Antwort: Ein Operator gibt einen Slack-Befehl ein, und anschließend läuft ein geschlossener Kreislauf aus wiederholtem Denken, Selbstkritik und Werkzeugnutzung unbeaufsichtigt weiter, bis die Arbeit abgeschlossen ist oder das System zugibt, nicht weitermachen zu können. Fast jede interessante Gestaltungsentscheidung verbirgt sich in diesem Satz, und der Rest dieses Abschnitts erläutert sie genauer.
In dem System befinden sich vier unterschiedliche Agentenkreisläufe, wobei jeder für eine bestimmte Art von Problem konzipiert ist:
Die Abbildung zeigt die Strukturen. Danach folgt der Inhalt, wobei jeder Mechanismus in der Reihenfolge seines Ablaufs beschrieben wird. Das Diagramm bezieht sich auf alle diese Mechanismen, und seine Knoten werden nach dem Lesen der folgenden Abschnitte verständlich. Die von ihm verwendeten Torcodes sind G1 bis G4, N1 bis N3, N5, A1 bis A3 sowie D1 bis D15.
Vor dem Kreislauf: Der Vorab-Verpflichtungs-Sperre
Zwei Schutzmaßnahmen werden vor dem ersten Claude-Aufruf getroffen, wobei die erste struktureller Natur ist. Bevor eine Untersuchungsrunde stattfindet, muss Claude im on-call-Pipeline zu einer hypothesis_slate übergehen. In dieser Liste sind mindestens sechs mögliche Erklärungen sowie vier oder fünf Kriterien zur Auswahl daraus aufgeführt, und sie wird in kickoff_precommitment.json gespeichert, wodurch danach nichts mehr geändert werden darf.
Von allem im System ist dieses Schloss der Schutzmechanismus mit dem größten methodischen Gewicht und der geringsten Sichtbarkeit. Ein unbeschränkter Schlussfolgerungszyklus von KI-Modellen neigt dazu, sich für das zu entscheiden, was durch den ersten Beweis unterstützt wird, und alle späteren Beweise als Bestätigung zu werten. Das Schloss kann diesen Trend nicht aufhalten. Stattdessen zwingt es jede Untersuchung dazu, von dem gesamten Hypothesenraum aus zu beginnen und aufzuzeichnen, wie sie von dort zu ihrem Schluss gelangt ist. Der gegnerische Prüfer (Phase B) stellt anschließend eine schwierigere Frage als die nach interner Konsistenz: Ist dies der Schluss, den das ursprüngliche Modell angesichts der Beweise vorhergesagt hätte?
Der zweite Schutzmechanismus ist die empirische Grundlage (Phase C). Erst in der ersten Iteration werden einige Befehle auf Betriebssystemebene ohne Einbeziehung eines LLM ausgeführt: Fehlerauszüge von journalctl, Snapshots von Festplatte und Speicher sowie eine Suche nach Log-Dateien. Die Ergebnisse werden als Rohdaten in die anfängliche Untersuchungsanfrage aufgenommen, wodurch Claude ein faktisches Bild der Maschine erhält, noch bevor irgendwelche Hypothesen bestehen. Dieser Schritt blockiert nie, ignoriert Fehler stillschweigend und dauert weniger als eine Sekunde. Er ist notwendig, weil der nächste Überlegungsschritt anschließend von den tatsächlichen Gegebenheiten ausgeht und nicht nur von der Problembeschreibung.
Gestrahlte Ausgabe: das Abschlussbericht
Jede Iteration endet mit einem parsierbaren JSON-Dokument, dem completion_report, und das Steuerungsprogramm liest dieses, um zu entscheiden, was als Nächstes geschieht. Seine Struktur ist festgelegt:
{
"status": "IN_PROGRESS" | "BLOCKED" | "COMPLETE",
"confidence": 78,
"open_questions": ["..."],
"unchecked_sources": [{"name": "...", "access_status": "..."}],
"contradiction_register": ["..."],
"assumption_register": ["..."],
"adjacent_problems": [{"summary": "...", "status": "...", "blocker": "..."}],
"draft_response": "the user-facing Slack message"
}
Freier Prosa-Text kann den Block umgeben, doch die Prüfmechanismen bewerten den analysierten Bericht und die Zustandsdateien speichern ihn. Der größte Hebel, um die Ausgaben von LLMs innerhalb eines Pipelines nutzbar zu halten, bestand darin, etwas Freiheit in der Prosa gegen einen analysierbaren Vertrag einzutauschen. Wird das Schema weggelassen, muss jeder folgende Schritt die Fakten aus dem Prosa-Text wieder herausfiltern. Behält man das Schema bei, werden die Prüfmechanismen zu gewöhnlichem, deterministischem Python.
Qualitätsprüfmechanismen, die Vertrauen eine Bedeutung geben
Ein Vertrauenswert wäre reiner Marketing-Lärm, wenn Claude einfach confidence: 95 eingeben und fortfahren könnte. Deshalb durchlaufen die Ausgaben jeder Iteration Qualitätsprüfmechanismen, die es nicht zulassen, dass die Untersuchung weitergeht, sofern die Beweise und der angegebene Vertrauenswert nicht übereinstimmen.
Nach jeder Aktion von Claude laufen drei Arten von Prüfmechanismen:
- G-Türen überprüfen die logische Konsistenz, damit das Denken zwischen den Runden nicht mit sich selbst im Widerspruch steht. Der klarste Fall ist G1, der ausgelöst wird, wenn
open_questionswährend der Runde zugenommen hat, währendconfidencegestiegen ist – denn ein zunehmender Nenner hebelt jede Aufwärtsbewegung wieder aus. Die Familie prüft außerdem, ob angespannte Formulierungen im Text als Widerspruch erkannt werden und ob benachbarte Probleme als gültige Statusobjekte statt als Platzhalterzeichen erfasst werden. Es gibt vier solcher Türen. - N-Türen überprüfen die strukturelle Vollständigkeit, indem sie sicherstellen, dass Artefakte vollständig ausgebildet sind und keine unvollendeten Strukturen darstellen. N1 verlangt, dass jede ausführbare Korrekturmaßnahme mit einer
verify_actionkombiniert wird, die eine Beschreibung, ein erwartetes Ergebnis sowie einen Zeitrahmen liefert. Eine vorgeschlagene Korrektur ohne Möglichkeit zur Überprüfung gilt als unvollendete Arbeit. Es gibt drei solcher Türen.
COMPLETE, solange benachbarte Probleme offen bleiben, verlangen ein nicht leeres Annahmeregister und stellen sicher, dass mindestens eine vorgeschlagene Maßnahme direkt auf die Ursache verweist. Es gibt insgesamt sieben solcher Tore.Zwei zusätzliche Kontrollen kommen obendrauf. EQ1 verlangt, dass Ursachenknoten harte Beweise anführen (etwas anderes als INFERRED) oder eine Obergrenze von 60 % akzeptieren, während P7 die Obergrenze um 7 % senkt, je nachdem, wie viele feindliche Dimensionen als FAIL markiert sind – bis zu einem Mindestwert von 40 %.
Insgesamt umfasst das Framework 19 Funktionen. Eine praktische Erinnerungshilfe: G-Tore reagieren auf das, was Claude schreibt, N-Tore auf das, was es weglässt, und A-Tore auf das, was es behauptet.
Eine Verletzung wird zu einem Eintrag pending_guard_notes, der an den Anfang des Prompts der nächsten Iteration unter dem Titel ## SYSTEM QUALITY GUARD NOTES (aus der vorherigen Iteration) gesetzt wird, wobei eine ausdrückliche Anweisung gibt, zunächst alle Notizen zu bearbeiten. Das ist das Zwangsmittel. Die Schutzmechanismen blockieren das Modell nicht; sie sorgen dafür, dass seine früheren Verstöße als Erstes in der nächsten Runde gelesen werden. Höflichkeit seitens des Modells spielt keine Rolle – es ist die strukturelle Durchsetzung, die die Untersuchung vorantreibt.
Ein Schritt zur Kontextfixierung (A7) wird ebenfalls am Ende jedes Prompt-Bauers ausgeführt, unabhängig davon, ob Fehler aufgetreten sind oder nicht. Dabei werden die ungelösten Widersprüche sowie unüberprüften Annahmen aus dem aktuellen Bericht Wort für Wort am Ende des nächsten Prompts wieder eingefügt. Dies kompensiert das bekannte Problem des Aufmerksamkeitsverlusts, bei dem ein Modell in Runde 3 auf eine Komplikation stößt und diese bis zur Runde 7 stillschweigend ignoriert.
Vertrauensgrad als konkrete Zahl
Die bedeutendste Gestaltungsentscheidung besteht darin, dass der Agent in der strukturierten Ausgabe jeder Iteration einem confidence: <int>-Wert auf einer Skala von 0 bis 100 zuweist. Diese Zahl dient nicht nur der Dekoration, sondern steuert tatsächliches Verhalten:
- Unter 70 darf der Schleifenprozess nicht beendet werden. Der Pipeline erzwingt bis zu drei weitere Runden und fügt eine Hinweismeldung ein, in der angegeben wird, dass der Agent behauptet hat, fertig zu sein, obwohl der Wert unter dem Schwellenwert lag.
status: COMPLETE und ohne open_questions wird der Übergang in die gegenseitige Überprüfungsphase (Red Team gegen Blue Team) ermöglicht.degrading. Da der Agent rückwärts entwickelt, stoppt er und informiert den Operator.Die vollständige Zuverlässigkeitsentwicklung jedes Falls wird in ANALYSIS.md als Sparkline aufgeführt, z. B. 45% → 62% → 78% → 80%. Operator schauen kurz darauf, um zu beurteilen, ob das Ergebnis vertrauenswürdig ist, und der eigene Selbstverbesserungszyklus des Systems liest sie, um zu entscheiden, welche früheren Fälle mit einer anderen Anweisung erneut ausgeführt werden sollen.
Drei Gründe, warum die Schleife nicht frühzeitig endet
In der Darstellung erreichen drei Pfade ready_for_adversarial oder blocked, ohne dass die Schleife endet. Jeder dieser Pfade stellt eine Regel zur Fortsetzung der Ausführung dar: Das System ignoriert das Beendigungssignal und ersetzt es durch eine Schutzmaßnahme.
- CONFIDENCE_FORCE wird angewendet, wenn
status=COMPLETEundopen_questions=[]gelten, aber derconfidence-Wert unter 70 liegt. Das Modell erklärt einen Sieg, signalisiert jedoch durch die Zahl Zweifel. Es werden bis zu 3 weitere Iterationen erzwungen, die zum 20-Iterationen-Budget hinzugerechnet werden statt davon abgezogen.
status=COMPLETE gilt und der Wert von confidence mindestens 70 beträgt, aber causal_chain_complete nicht wahr ist. Es handelt sich dabei um eine feststellung auf Symptomebene ohne nachvollziehbare Ursache. Dadurch werden bis zu 3 weitere Iterationen erzwungen, ebenfalls innerhalb des 20-Iterationen-Budgets.status=BLOCKED ist, obwohl erreichbare technische Quellen übersprungen oder aufgrund von Schlussfolgerungen als nicht verfügbar deklariert wurden – und nicht aufgrund eines tatsächlichen Fehlers. Eine Untersuchung kann nicht als blockiert beendet werden, solange nicht wirklich alles ausgeschöpft wurde. Es werden bis zu 3 weitere Fortsetzungen erlaubt, die ebenfalls innerhalb desselben Budgets gezählt werden.Zusammen verhindern diese Mechanismen die drei häufigsten vorzeitigen Beendigungen: unsicherheit mit scheinbar hoher Zuverlässigkeit, Abschluss auf Symptomebene sowie vorgetäuschte Unverfügbarkeit.
Der feindliche Prüfer
Sobald der On-Call-Pipeline mit einer Zuverlässigkeit von 70 oder mehr angibt, fertig zu sein, geht die Steuerung an eine separate Claude-Aufrufung über, die einen adversarialen Prüfer einsetzt. Dieser Prüfer sieht den Prompt des Untersuchers nicht. Er erhält den Analysetext sowie eine Checkliste mit 15 Bewertungskriterien, von D1 bis D15, die die Gültigkeit der Annahmen, die Beweiskette, das kausale Denken, alternative Hypothesen und weitere Aspekte abdecken. Er gibt ein strukturiertes Urteil zurück:
Es gibt drei Möglichkeiten, die Überprüfung abzuschließen:
- Kritische Probleme werden an den Untersucher zurückgegeben. Seine Notizen werden in die folgende Iteration als
pending_guard_noteseingefügt und der Kreislauf beginnt erneut, wobei der Untersucher nun explizit erfährt, dass der Prüfer glaubt, etwas übersehen worden zu sein. - Falls bei der ersten Überprüfung nur geringfügige Probleme vorliegen, wird der Kreislauf noch einmal durchlaufen, wobei die geringfügigen Kritiken mitübernommen werden.
complete, und die Untersuchung wird veröffentlicht.Dass der feindliche Schritt als separate Aufrufung mit einem anderen Prompt durchgeführt wird, geschieht absichtlich. Derselbe Modell in einer anderen Rolle erkennt einen bedeutenden Anteil an Selbstschmeichelei, der bei einer Iteration mit einem einzigen Prompt durchkommt. In einem Fall sank die Selbstsicherheitsanspruch zwischen der Untersuchung und ihrer Überprüfung von 90 auf 65, wobei der Prüfer genau auf die Annahme hinwies, die der Untersucher übersehen hatte.
Eine zweite Überprüfung findet parallel dazu statt und ist anders aufgebaut: die Red-Team-Überprüfung (G5). Der adversäre Prüfer liest den gesamten Untersuchungsbericht, während dem Red-Team-Prüfer nur die ursprüngliche Problemstellung sowie das endgültige Fazit vorgelegt werden. Er erhält weder Zwischenschlussfolgerungen noch Beweismittelketten noch frühere Überprüfungsrunden. Anhand dieser beiden Informationen bildet er eine eigene Hypothese und weist darauf hin, wo die Ergebnisse der Untersuchung von dem abweichen, was ein Außenstehender vermutet hätte.
Ziel ist die kognitive Isolation, nicht eine zusätzliche Abdeckung. Die adversäre Überprüfung fragt danach, ob die Untersuchung strukturell vollständig ist (D1 bis D15). Das Red Team fragt, ob zu dem Schluss auch ohne die Ausrichtung der Untersuchung gelangt werden könnte: Ist die Begründung tatsächlich am Problem ausgerichtet, oder stützte sich die Untersuchung auf eine frühe Erkenntnis und ließ den Schluss dieser Erkenntnis statt den Beweisen folgen? Beide Verfahren laufen als separate Claude-Aufrufe ab, und beide müssen bestanden werden, bevor ein Fall als COMPLETE markiert wird.
Fünf ehrliche Wege zum Ende
Der Untersuchungslauf kann aus fünf Gründen beendet werden. Der jeweilige Grund wird protokolliert und dem Operator angezeigt, wie in Zeilen wie diesen:
exit=complete confidence=89% iterations=12 elapsed=13min
exit=blocked confidence=62% iterations=4 elapsed=4min (cannot proceed without info)
exit=stalled confidence=58% iterations=7 elapsed=22min (two rounds, zero new facts)
exit=degrading confidence=42% iterations=5 elapsed=8min (dropped >15% twice)
exit=timeout confidence=73% iterations=18 elapsed=50min
Von den fünf ist blocked der Zustand, auf den ein Operator am direktesten eingreifen kann. Der Agent hat explizite Blockierungen in unchecked_sources oder adjacent_problems erfasst, und ein Mensch muss anrufen, um sie zu beseitigen. Die anderen vier sind technische Fehlerarten, die vom System erkannt werden, ohne dass es blind erneut versucht.
Was Claude von innen aus erreichen kann
Die Grenzen der Tools spielen hier eine Rolle, denn die Zuverlässigkeitsregeln hängen teilweise davon ab, worauf Claude tatsächlich zugreifen kann. Eine Anweisung an den Agenten, seine unüberprüften Quellen zu prüfen, bedeutet nichts, solange die Tools zur Überprüfung nicht vorhanden sind. Jeder Pipeline startet einen Claude Code-Unterprozess mit --permission-mode bypassPermissions. In der Anfrage erscheint keine eingebettete Tool-Allowlist. Die Grenze ist das, was im Model Context Protocol (MCP)-Katalog definiert ist, und umfasst fünf externe Systeme:
Mehrere Einschränkungen verdienen Erwähnung, da sie das Verhalten stärker beeinflussen als alles andere auf der Modellkarte:
- Der Untersuchungspipeline ist ausdrücklich
Bashverboten (--disallowedTools Bash), um git-Beziehungsprobleme zu vermeiden, da zwei Claude-Prozesse, die gleichzeitig an derselben Arbeitsbaumstruktur arbeiten, den Zustand beschädigen könnten. Die dev-agent-Pipeline verwendet zwar Bash, doch sie läuft in einem isolierten Arbeitsbaum. - Slack-Schreibwerkzeuge sind bei jeder Pipeline-Aufrufung blockiert.
send_message_to_selfundedit_message_to_selfsind nicht zulässig, sodass Claude nicht selbst in Slack posten kann. Alle Ausgangskommunikationen erfolgen über dasdraft_response-Feld des strukturierten Kompletterungsberichts, den das System erst nach Überprüfung der Abbruchbedingungen veröffentlicht.
bypassPermissions bedeutet in der Praxis nicht uneingeschränkt. Der Framing-Prompt jedes Pipelines enthält feste Regeln. ANALYSIS.md kann bearbeitet werden, während message.json das nicht kann. Schreibvorgänge außerhalb von case_dir werden nach der Ausführung automatisch über git diff rückgängig gemacht. Schreibvorgänge in der Produktionsdatenbank erfordern gemäß der Anweisung die ausdrückliche Bestätigung des Operators. Die Sicherheit beruht auf der Framing-Schicht sowie einer Nachprüfung nach der Ausführung und nicht auf der Tool-Aufruf-Schicht.search_datadog_services mit einer Berechtigungsverweigerung zurückkommt, weist der Prompt den Agenten an, auf mcp__glean_default__search umzusteigen, wobei Jira-Schlüsselwörter als Ersatz verwendet werden. Die Fallback-Kette ist Teil der Umsetzung der SOP und hat keinen Platz im Laufzeitbetrieb.tool_use-Ereignisse, sobald sie eintreffen, und leitet bis zu 10 gleichzeitige Lesevorgänge (Datadog-Anfragen, Glean-Suchen, Dateiabrufe) aus. Alle Schreibvorgänge – egal ob mit Nebeneffekten in Bash, Bearbeitungen, MR-Kommentaren oder Datenbankschreibvorgängen – erfolgen nacheinander. Eine einzige Untersuchungsrunde kann daher sechs parallele Protokollanfragen auslösen und dennoch die Schreibvorgänge geordnet halten.Ein Skelett, vier Größen
Jeder Pipeline im Harness verwendet eine Variante desselben Skeletts:
Der Auftragsuntersuchungsprozess durchläuft bis zu 20 Iterationen. Die Analysephase umfasst bis zu 8 Schritte. In der Implementierungsphase wird das Skelett einmal ausgeführt, wobei der Build-Schritt dreimal wiederholt wird. Der Dev-Agent verfügt über keine innere Schleife und wird bei jedem Neustart einmal ausgeführt, doch mr-monitor verschiebt die Iteration effektiv nach außen: Jedes Mal, wenn der CI-Prozess bis zu drei Mal in Folge fehlschlägt, wird ein neuer Dev-Agent erstellt, bevor der Fall an einen Menschen weitergeleitet wird.
Diese Gleichförmigkeit ist beabsichtigt. Die vier Schleifen existieren, weil die Probleme unterschiedlich sind, doch sie verwenden dieselbe Sprache: Das Vertrauensniveau wird als Zahl dargestellt, ein Ausstieg erhält einen Namen, die Selbstkritik erfolgt durch einen separaten Claude-Aufruf und eine Eskalation bedeutet eine DM in Slack im Thread, der den Fall auslöste. Ein Operator lernt diese Struktur einmal kennen und erkennt sie danach überall wieder.
Die Selbstverbesserungsschicht
Dies schließt den zuvor skizzierten Kreislauf ab, bei dem das Tool unter menschlicher Überwachung sein eigenes Substrat anpasst. Zwei Kreisläufe erledigen die Arbeit in unterschiedlichen Zeitskalen.
Kreislauf 1 repariert die Strukturen Fall für Fall, von Lücken bis hin zu Pull Requests. Nach Abschluss einer Untersuchung sucht gap_analyzer nach Stellen, an denen das Tool schlecht abgeschnitten hat: übersprungenen Datensätzen, falschen Werkzeugauswahlen, Fehlern in der Pipeline, fehlenden Tests sowie schlecht formatierten Beschreibungen der Pull Requests. Kategorien- und Zuverlässigkeitsfilter reduzieren die Lücken, bevor finalize_case sie erhält. Wenn ein Fall vier Stunden lang unberührt bleibt, startet finalize_case patch_suggester in einem speziellen Arbeitsbaum und erstellt einen Pull Request gegen die eigene Codebasis des Tools, wobei Code-Dateien, Prompt-Vorlagen oder SOP-Abschnitte verändert werden. Die Fusion dieses Pull Requests erfordert einen Menschen – seine Erstellung nicht.
Loop 2 stärkt das Verhalten in verschiedenen Fällen – von Fehlerrichtungen bis hin zu Vorschlägen für Standardprozesse. Am Ende jedes Falls erfasst der Schritt auto_retrospective, welche Fehlerrichtungen aufgetreten sind, und ordnet sie in drei Kategorien ein: Fehler bei der Datenerhebung (Wurden erreichbare Quellen übersprungen?), Verstöße gegen Qualitätskriterien (Kam eine Zuverlässigkeitsbehauptung im Widerspruch zu den Beweisen?) sowie Fehler bei der Vollständigkeit der Analyse (Hörte die Ursachenforschung vorzeitig auf?). Die Aufzeichnungen werden pro Projekt im Fallregister gesammelt. Jede Woche zählt ein Cron-Job mit dem Namen knowledge-updater die letzten zehn Fälle und erstellt bei Überschreiten eines Schwellenwerts einen Vorschlag für einen Standardprozess: 3 von 10 Fällen führen zu einem Vorschlag, 6 zu einer Warnung. Die Vorschläge sind konkret. Beispielsweise wurde „Überspringen der direkten DB-Anfrage“ diesen Monat 3 Mal registriert, weshalb der Standardprozess nun eine direkte Tabellensuche vor jeder Schema-Infereenz vorschreibt. Menschen prüfen diese Vorschläge und wenden sie an.
Em – und hier wird aus Designgründen nichts automatisch angewendet, da automatisierte Entscheidungen, die ihre eigenen Fehler verstärken, ein bekanntes Risiko in selbstmodifizierenden Systemen darstellen.
Daraus ergibt sich die Personalisierung. Die SOP enthält das Bild des Teams darüber, wie es Ermittlungen durchführt, und beginnt zunächst als allgemeines Muster. Im Laufe der Zeit erstellt der kb-Updater ein Profil der Fehlermuster eines Projekts anhand der Fälle und Wiederholungen. Bei 20 bis 30 Fällen ähnelt die SOP dieses Projekts nicht mehr dem allgemeinen Muster: Sie dokumentiert, welche Datensätze ständig übersprungen werden, welche Tools falsch verwendet werden und welche Ermittlungsansätze in dieser spezifischen Codebasis regelmäßig fehlschlagen. Die Projekte behalten separate SOPs bei, sodass die Fehler von Team A nur die Regeln von Team A beeinflussen und niemals Team B kontaminieren.
Eine weitere Vorteil ist die Langlebigkeit. Ein Kontextfenster hält nur eine Sitzung lang, während eine zusammengeführte Codeänderung versioniert, überprüft, getestet und dauerhaft gespeichert wird. Ein SOP-Update, sobald es von einem Bediener genehmigt wurde, erscheint in allen nachfolgenden Untersuchungen. Das Substrat verbessert sich ständig, sodass jede neue Anwendung auf einer besseren Infrastruktur läuft als ihre Vorgängerin.
Schicht 3: Zustand, der nach Neustarts erhalten bleibt
Orchestrierung ist das, was bei jedem Ereignis abläuft. Ein persistenter Zustand hingegen bleibt bestehen, wenn ein Prozess neu gestartet wird, eine Maschine neu gebootet wird oder der Bediener von einem Laptop auf eine Cloud-VM wechselt. Die Infrastruktur bewahrt ihren Zustand in drei Schichten mit deutlich unterschiedlichen Eigenschaften auf:
In-Memory-Caches sind klein und können neu erstellt werden. Sie befinden sich im Poller- sowie Keepalive-Prozess und werden nach einem Neustart aus dem lokalen Zustand wieder aufgebaut.
Lokaler Zustand in ~/.harness/*.json ist die Betriebskarte. Die wichtigsten Dateien sind:
task-thread-map.jsonverknüpft einen Slack-Thread_ts mit einer JIRA-ID sowie einem absolutentask_dir-Pfad.oncall_thread_map.jsonhat die gleiche Struktur für Fälle von On-Call-Ermittlungen.monitored-mrs.jsonlistet die MRs auf, die von Harness geöffnet wurden, zusammen mit ihrem CI-Zustand.patch-pr-state.jsonspeichert den Endzustand pro Fall (merged,no_gaps,failedusw.).oncall-state.jsonenthält das Kill-Switch-Flag, das unter Schicht 6 behandelt wird.socket-dedupenthält die Zeitstempel der kürzlich von Socket Mode verarbeiteten Nachrichten.
Diese Schicht gehört zu einem einzigen Rechner und wird nicht geteilt. Sie bleibt nach einem Neustart erhalten, verschwindet jedoch, wenn der Rechner ausfällt.
Git-synchronisierter Zustand ist die dauerhafte Schicht. Fallarbeitsräume unter case-workspaces// werden bei jeder bedeutenden Zustandsänderung gespeichert und in ein privates Git-Repository hochgeladen. Ein zweiter Rechner, der dieses Repository kloniert, kann denselben Gesprächskontext übernehmen, was die Kontinuität der Sitzung zwischen den Rechnern gewährleistet. Ein Operator kann über ein Laptop oder eine entfernte Entwicklungs-VM mit dem System chatten, ohne etwas zu verlieren.
Die Speicherkonsolidierung wurde später zu einer dritten Aufgabe für den git-synchronisierten Zustand. Ein langes Gespräch erzeugt Dutzende von followup_transcript_*.md-Dateien. Wenn genügend Aktivität anfällt, liest ein Unteragent alle davon, schreibt TASK.md neu, um den zusammengefassten Zustand zu speichern, und der Workflow hört auf, rohe Transkripte für weitere Schritte einzuspeisen. Das Überspringen der Konsolidierung kann dazu führen, dass die Prompts den Kontextbereich des Modells überschreiten. Dabei besteht das Risiko, die Informationen durch zu starke Komprimierung zu verlieren – und das ist tatsächlich passiert: Ein 14KB großes Dokument schrumpfte auf 587 Bytes. Aus diesem Vorfall entstanden drei Schutzmaßnahmen: ein Prompt-Muster, das „UPDATE statt Umschreiben“ vorschreibt, eine Schutzfunktion für die Ausgabegröße, die Schreibvorgänge unter 50 Prozent der Eingabegröße verweigert, sowie ein Fallbezogener Lockfile, damit zwei Konsolidierungsabläufe nicht gleichzeitig stattfinden.
Der Suchpfad von einem einzelnen Slack-Thread zu TASK.md des jeweiligen Falls ist kurz, aber es lohnt sich, ihn darzustellen:
Sowohl die State-Dateien enthalten denselben Wert, nämlich einen absoluten Pfad zum Case-Arbeitsbereich. Jeder Workflow kommt früher oder später auf einen case_dir und arbeitet anschließend relativ dazu. Als der Wurzelordner des Arbeitsbereichs mitten im Projekt umbenannt wurde, handelte ein Migrationsskript dies dadurch ab, dass es die absoluten Pfade in beiden Karten umschrieb, während gleichzeitig der Ordner verschoben wurde.
Eine dauerhafte State ist die Grundlage. Die nächste Frage lautet, was passiert, wenn darauf aufbauende Operationen fehlschlagen – die Antwort ist, dass das System daraus wiederherstellt und die Fehler nicht an den Operator weiterleitet.
Schicht 4: sich selbst reparierende Schleifen
Das ist die Schicht, in der das System nicht mehr nur als Benachrichtiger fungiert, sondern autonom wird. Sie enthält drei Schleifen, die jeweils ohne Beteiligung eines Operators abgeschlossen werden.
Die ersten beiden sind vollständig autonom. Der dritte ist absichtlich nicht autonom. Um die Session des Identitätsanbieters aufzuladen, ist ein hardwaregebundener MFA-Anfragen erforderlich; daher stoppt der Agent und bittet um menschliches Eingreifen, wodurch eine 30-sekündige Ablaufanweisung in der privaten Nachricht übermittelt wird. Das ist durch Design ein menschlicher Eingriff und es besteht kein Funktionsdefizit.
Diese Schleifen weisen eine subtile Eigenschaft auf: Jede verfügt über einen Wiederholungsbudget und kann erkennen, was sie bereits getan hat. Die automatische Korrektur in CI ist pro MR begrenzt, sodass drei aufeinanderfolgende Fehler an den Operator weitergeleitet werden. Die automatische Antwort der Überprüfer entfernt Duplikate nach Autor – das bedeutet, wenn die neueste Notiz des Bots in einer Diskussion jünger ist als die des Überprüfers, bleibt die Schleife still, da bereits eine Antwort existiert. Der Hilfsmechanismus des Identitätsanbieters ermöglicht ein 15-minütiges Genehmigungsfenster. Entfernt man diese Beschränkungen, können die Schleifen manchmal außer Kontrolle geraten. Frühzeitig führte ein MR mit einem unzuverlässigen Integrationstest dazu, dass innerhalb eines Nachmittags 80 sinnlose „CI korrigieren“-Kommitts vorgenommen wurden, bevor jemand es bemerkte.
Aus Fehlern einzelner Operationen wiederherstellen
Die oben beschriebenen Schleifen zur automatischen Behebung von Fehlern durch CI und zur Antwort der Überprüfer ermöglichen es, ganze Workflows von Anfang bis Ende wiederherzustellen. Darunter beruht jede primitive Operation, die fehlschlagen kann (ein Push, ein Rebase, ein Kommentar in einer MR, ein Branch-Reset), auf einem separaten, kleineren dreischichtigen Design zur selbstständigen Wiederherstellung pro Operation. Dieses unterscheidet sich vom dreischichtigen Sicherheitsmodell in Schicht 6, das sich auf Beschränkungen bezieht, also darauf, was der Agent tun darf. Dieses Modell hingegen bezieht sich auf die Wiederherstellung, also darauf, was passiert, wenn eine erlaubte Operation fehlschlägt. Die beiden sind leicht zu verwechseln, daher sollte man sie voneinander trennen.
L1 ist ein deterministischer Schutzmechanismus. Er basiert auf Regeln und ist ständig aktiv, wodurch er in weniger als einer Sekunde reagiert. Für Push-Operationen wird _pre_push_rebase(repo_path, branch) verwendet: Unmittelbar vor dem Push führt das System git fetch origin sowie git rebase origin/ aus. Ein erfolgreicher Rebase ermöglicht den weiteren Ablauf des Pushs. Treten Konflikte oder ein fehlgeschlagener Fetch auf, stoppt L1 sicher ab, listet die konfliktierenden Dateien auf und leitet den Fall an L2 weiter. L1 darf absichtlich nicht kreativ sein – die Regeln bleiben klein genug, um verständlich zu bleiben, und kostengünstig genug, ohne Tokenverbrauch, um auf jede einzelne Operation angewendet zu werden.
L2 ist ein selbstheilender Prozess mit Agentenfunktion. Wenn L1 es nicht schafft, die Situation zu beheben, startet das System eine eingeschränkte Claude-Sitzung (_self_heal_push_loop) und gibt ihr alle Informationen über den Fehler: den Git-Zustand, die konfliktspezifischen Dateien, die Aufgabe, die den Push ausgelöst hat, sowie einige strenge Einschränkungen. Man sollte niemals einen geschützten Branch mit Force-Push bearbeiten, niemals unpushte Commits ignorieren und niemals blind eine Seite im Konflikt wählen. Drei Einschränkungen sorgen dafür, dass dies sicher geschieht:
- Begrenzte Wiederholungsversuche. Jedes Problem erhält maximal 3 Versuche, und jede Aktion von Claude hat eine Zeitbegrenzung von 4 Minuten. Nach jeder Aktion von Claude wird der eigentliche
git pusherneut ausgeführt. Claudes Einschätzung, ob der Konflikt beseitigt ist, hat keinerlei Gewicht – nur ein Ausgabecode von 0 ausgit pushgilt als zuverlässige Information. Wenn der nächste Push einen nicht-nullen Wert zurückgibt, protokolliert der Loop den fehlgeschlagenen Versuch, unabhängig davon, wie zuversichtlich Claude den Erfolg behauptet hat. - Zuverlässigkeitsgrenze von 70 oder mehr. Dies wurde unverändert aus der
oncall_run-Konfiguration des on-call-Ermittlungsprozesses übernommen. Claude bewertet sich selbst bei jeder Aktion auf einer Skala von 0 bis 100; bei einem Wert unter 70 muss sie aufhören, anstatt weiter zu handeln. Eine selbst gemeldete Zuverlässigkeit unter dieser Grenze berechtigt nicht dazu, den Arbeitsbaum zu verändern.
git push mit Status 0 gekoppelt und niemals an irgendetwas, was Claude über sich selbst sagt. L2 kann dieses System nicht umgehen – es kann ihm nur einen echten Push zur Verfügung stellen.L3 ist die Eskalation an den Operator. Wenn L2 aufgrund geringer Zuverlässigkeit abbricht oder alle Versuche aufgebraucht hat, sendet das System dem Operator eine Privatnachricht mit allen Informationen aus L2 – also jeder Versuch, jede von Claude durchgeführte Aktion, jede von ihm angegebene Zuverlässigkeitsbewertung sowie der finale git status. Der Operator startet dabei von einem vollständig dokumentierten Zustand aus und nicht von der Annahme, „etwas sei schiefgelaufen“. Die Zeitskala beträgt Stunden, nicht Sekunden.
Zwei Prinzipien heben sich hervor:
- L2 wird nur bei jedem einzelnen Vorfall genutzt und ist nicht ständig aktiv. L1 läuft bei jeder Übertragung, weil sie kostengünstig ist, während L2 Token verbraucht und erst dann aktiv wird, nachdem L1 versagt hat – somit hängt die Kostenentstehung vom seltenen Fall und nicht vom häufigen ab.
- Die echte Referenz stammt direkt aus dem System. Unabhängig davon, was Claude über seine eigene Arbeit denkt, wiederholt die Validierung die tatsächliche Aktion: den Exit-Code von
git pushbei Übertragungen, einen tatsächlichen Testlauf bei Korrekturen sowie die Überprüfung des Push-Exit-Codes durch das Antwortsystem bei Rückfragen. Der Selbstbericht des Agenten wird niemals als echte Referenz angesehen, da das System dies gegenüber dem tatsächlichen System erneut überprüft.
Dieser gleiche Wrapper eignet sich weitaus mehr als nur für Push-Operationen. Eine Operation erfüllt die Voraussetzungen, wenn drei Elemente vorhanden sind: eine einfache, regelbasierte Korrektur (L1), ein streng begrenztes automatisches Wiederholungsversuchssystem (L2) sowie eine klare Möglichkeit, die Aufgabe an einen Menschen weiterzugeben (L3). Diese dreiteilige Struktur unterscheidet zwischen einem autonomen Schleifenmodell, das von bereits bekannten Fehlern selbst wiederherstellt, und einem Modell, das sofort menschliches Eingreifen benötigt, sobald sich die Umstände ändern.
Schicht 5: vier Orte, an denen man nachvollziehen kann, was passiert ist
Das Framework schreibt in vier Überwachungsplattformen, wobei jede davon für einen anderen Leser optimiert ist:
- Echtzeit-Updates über Slack. Während ein Agent läuft, wechselt eine Platzhalternachricht im Fallthread durch verschiedene Statusseiten (
Reading TASK.md, anschließendSearching codebase, dannDrafting patch) und wird schließlich aufDoneoderFailed: <reason>gesetzt. Dieser strömende Berichterstatter ändert die Nachricht direkt vor Ort, sodass die Threads nicht mit unnötigem Inhalt gefüllt werden. - Gestrukturierte Protokolle an den Orten
~/.harness/logs/agent.logund~/.harness/logs/error.log. Jeder Neustart, jede Verteilung in einer Kette sowie jeder Wiederholungsversuch werden zu gestrukturierten Ereignissen, und diese Dateien werden dann durchsucht, wenn eine Diagnose erforderlich ist.
~/.harness/logs/system.log für quer durch alle Bereiche auftretende Ereignisse wie abgeschlossene Deploys, Watchdog-Aktionen und Sync-Zustände.Eine Anzeigetafel wurde absichtlich weggelassen. Slack und grep dienen als Konsole. Eine Anzeigetafel würde eine weitere Ebene schaffen, um auf dem Laufenden zu bleiben, und ist das Erste, was Ingenieure nicht mehr lesen, sobald sie veraltet ist. Das Muster der strömenden Nachrichten liefert bereits ausreichend operative Signale, weshalb niemand eine Benutzeroberfläche darüber haben wollte.
Überwachung der MCP-Verbindungen
Fünf externe MCP-Server (Slack, Datadog, Jira und Confluence, Glean, GitLab) bilden die Grundlage dieses Systems. Jeder verfügt über seinen eigenen OAuth-Token, eine eigene Erneuerungsintervall und unklare Mechanismen bei Fehlern. Wenn ein Token unbemerkt abläuft, beginnt eine Claude-Sitzung mit der Antwort „Ich habe keinen Zugriff auf dieses Tool“, wobei der Operator keinerlei Fehler sieht.
Ein kleines Tool namens mcp-watchdog schließt diese Lücke. Alle 10 Minuten prüft es den Health-Endpoint jedes MCPs und versucht einen sinnlosen Toolaufruf. Wenn dieser fehlschlägt, führt es Folgendes aus:
- Es versucht eine stille Token-Erneuerung.
- Falls die Erneuerung fehlschlägt, sendet es eine private Slack-Nachricht an den Operator mit dem Inhalt etwa „Der Atlassian MCP benötigt eine erneute Authentifizierung, klicken Sie hier.“
- Nach zwei aufeinanderfolgenden Trennungen (
DISCONNECT_CONFIRM_THRESHOLD) wird die Situation mit einer:warning:-Reaktion im neuesten Ticket eskaliert.
Fehlt diese Schleife, wird ein abgelaufenes Token fälschlicherweise als „der Agent ist heute dumm“ interpretiert – ein Fehler, dessen Diagnose äußerst schwierig ist, da agent.log niemals „Token ist abgelaufen“ anzeigt, sondern lediglich „Das Tool gibt ein leeres Ergebnis zurück“. Die Behandlung des Authentifizierungsstatus als zentrale Überwachungsinstanz wäre schon früher implementiert werden sollen.
Schicht 6: Die Steueroberfläche des Operators
Es handelt sich dabei um die am häufigsten genutzte Oberfläche, die ursprünglich jedoch unzureichend entwickelt wurde. Jede Interaktion des Operators erfolgt über einen einzigen Kanal, das Self-DM, und die Befehle lassen sich in sechs Kategorien einteilen:
- Aufgabe:
admin: task <jira>führt den gesamten Analyse-, Implementierungs- und MR-Prozess aus; durch Hinzufügen von--autowird dieser Prozess unüberwacht ablaufen.
admin: oncall-run <url> startet eine Untersuchung aus einem Slack-Thread, während oncall-toggle die automatische Überwachung ein- oder ausschaltet.admin: mr rescan prüft einen bestimmten MR erneut, und mr pause/resume schaltet den automatischen Antwortzyklus für diesen MR ein oder aus.admin: oncall pause [Dauer] deaktiviert die automatische Zuweisung für eine Weile, und oncall resume/status beendet die Pause oder gibt den aktuellen Stand an.admin: finalize <Fall> fasst die Lückenberichte zusammen und erstellt einen Verbesserungsantrag für das System selbst.admin: register-thread verbindet manuell einen Slack-Thread mit einem Fall, während close-case diesen als abgeschlossen markiert.Der Pausenschalter war am schwierigsten in die richtige Form zu bringen. In Version eins wurde alles pausiert, einschließlich der Admin-Befehle, wodurch ein Operator, der das System pausiert hatte, es nicht wieder in Betrieb nehmen konnte. In Version zwei wurde nur zu eng gepausiert, sodass der Befehl „den Lärm stoppen“ nicht berücksichtigt wurde. Das aktuelle Design basiert auf einem präzisen Unterschied: Die Pause schweigt die durch Aktivitäten anderer ausgelöste automatische Verteilung aus, niemals jedoch die eigenen Admin-Befehle oder Aktionen des Operators im Thread. Im Poller werden die Verteilungsorte in zwei Gruppen aufgeteilt. Eine Gruppe umfasst automatische Aktivitäten, die von anderen ausgelöst werden, und diese wird während der Pause blockiert. Die andere Gruppe umfasst die eigenen Absichten des Operators, und diese bleiben weiterhin aktiv.
Die Kalibrierung war ein schwieriger Prozess. Kurz nach dem Versand der ersten Pause wurde automatisch eine Antwort auf einen Review-Kommentar in einem anderen Fall ausgelöst, ohne dass dies bemerkt wurde – schließlich sah es so aus, als wäre die Pause tatsächlich aktiv. Das aktuelle Design betrachtet die Pause als kontrollierte Stille: Es wird das System stillgelegt, während die Handlungsfreiheit des Bediners gewahrt bleibt.
Ein Bild zeigt die Aufteilung:
Die Regel lautet, dass die eigenen Aktionen des Bediners niemals gestoppt werden, während die Aktivitäten anderer Personen während einer Pause eingeschränkt sind. Das ist alles, was admin: oncall pause steuert.
Zwei weitere Sicherheitsebenen
Der Aus-Schalter für die Pause ist die auffälligste Sicherheitsmaßnahme – allerdings nicht die einzige. Zwei weitere funktionieren ohne jegliche Konfiguration während der Laufzeit, eine im Code und eine durch Deployment-Regeln:
Die Allowlist für die Slack-Kanäle verdient mehr Aufmerksamkeit, als es auf den ersten Blick scheint. Ein knapper Vorfall zu Beginn des Projekts betraf einen falsch konfigurierten Slack-Token, der in die internen Teamkanäle schreiben konnte. Der Agent hätte direkt an die Teamkollegen schreiben können, ohne den Operator zu durchlaufen, und niemand hätte diese Beiträge von menschlichen Nachrichten unterscheiden können. Heute wird jede ausgehende chat.postMessageAktion vor dem Versand anhand einer Allowlist auf das Ziel überprüft. Das einzige erlaubte Ziel ist die private Nachricht des Operators sowie eine fest codierte Kanal-ID für das eigene Gespräch des Operators mit dem Bot. Wenn der Agent einen Teamkollegen erreichen möchte, gibt er den Inhalt an den Operator zurück, der entscheidet, ob er weitergeleitet wird. Diese architektonische Regel hat sich immer wieder bewährt: Der Agent kommuniziert nach außen nur über den Posteingang des Operators.
Jenseits der sechs Schichten: Was macht es für die Produktion geeignet
Die sechs Schichten bilden die tragende Struktur. Mehrere Mechanismen liegen außerhalb dieser Klassifizierung, sind aber genauso wichtig. Sie unterscheiden ein gut funktionierendes Harness von einem, das ohne Unterbrechungen läuft.
Mehrere Projekte aus einer YAML-Datei routen
Derzeit laufen zwei Projekte über das Harness, jeweils mit eigenen Betriebsregeln. Die Hinzufügung eines dritten Projekts erfordert keinerlei Codeänderungen, lediglich einen neuen Eintrag in agent-config/projects.yaml:
projects:
team-a:
sop: "team-a/SOP.md"
kb: "team-a/KNOWLEDGE-BASE.md"
dfr_threads_dir: "team-a/threads"
task_dir: "task-workspaces"
slack_channels: ["support-channel-a", "support-channel-b"]
jira_prefixes: ["AAA", "BBB", "CCC"]
team-b:
sop: "team-b/SOP.md"
kb: "team-b/knowledge-base/kb.md"
dfr_threads_dir: "team-b/threads"
task_dir: "task-workspaces"
slack_channels: []
jira_prefixes: ["XX", "YY"]
Die Funktion resolve_project() leitet jedes eingehende Signal nach Priorität weiter: Zuerst das Jira-Präfix, anschließend der Slack-Kanal und danach die Standardroute. Jedes Projekt verfügt über seine eigene SOP-Datei, KB-Datei sowie Verzeichnisstruktur, und die automatische Auswahl der entsprechenden Dokumente für Ermittlungen ermittelt je nach dem zugehörigen Projekt automatisch die richtige SOP- und KB-Datei. Dadurch kann eine einzige Harness-Instanz zwei Teams mit jeweils unterschiedlichen Regeln bedienen.
Dieses Muster lässt sich generalisieren. Jede Organisation mit mehreren Produktteams unter einem Harness kann denselben Ansatz nutzen: deklarative Konfiguration ohne projektbezogene Code-Branches. Zudem sorgt dies für eine klare Disziplin, da alles, was spezifisch für ein Projekt ist, in der SOP-Datei dieses Projekts aufbewahrt werden muss und niemals im Code, da der Code gemeinsam genutzt wird.
Fortsetzung einer Sitzung auf einem der Geräte
Der Operator arbeitet mit zwei Maschinen – einem Laptop und einer langlebigen Cloud-VM im Rechenzentrum – und eine Claude-Sitzung muss auf beiden wieder aufgenommen werden können. Das ist schwierig, weil Claude Code standardmäßig den Sitzungszustand auf der lokalen Festplatte speichert, sodass der Sitzungszustand nach einem Neustart an einem anderen Ort nicht mehr sichtbar ist.
Das Tool löst dieses Problem mit einem durch Git unterstützten Sitzungsspeicher:
Der Mechanismus besteht aus drei Teilen:
- Sitzungen werden in Git verfolgt. Die
.jsonl- und.meta-Dateien jeder Sitzung werden bei jeder bedeutenden Zustandsänderung gespeichert und in ein privates Repository hochgeladen, wobei dieses Repository als einzige Quelle der Wahrheit dient. - Ein Hintergrundprozess läuft alle 5 Sekunden auf jeder Maschine, um die lokale Kopie aktuell zu halten. Er lädt den Kontext im Voraus herunter, sodass beim Wiederaufnehmen einer Claude-Sitzung keine Netzwerkverzögerungen bei jeder Tasteneingabe entstehen.
session-start.sh die lokalen .meta-Dateien nach dem Eintrag, der für dieses Arbeitsverzeichnis gespeichert ist, und holt dessen UUID ab. Somit folgt eine UUID dem Benutzer von Maschine zu Maschine.Der Synchronisierungs-Hook user-prompt-submit.sh wird nach jeder Anfrage an Claude ausgelöst und führt in strenger Reihenfolge drei Operationen durch, die mit flock seriellisiert werden:
- Abrufen und Zurücksetzen. Durch Ausführung von
git fetch origin main && git reset --hardbleibt die lokale Dateiactive.jsonlmit der Transkription der anderen Maschine erhalten. - Extrahieren Sie den Delta-Unterschied vor dem Überschreiben. Es liest das Wasserzeichen ab, das angibt, wie viele Zeilen bereits von der anderen Maschine eingefügt wurden, extrahiert nur die neueren Zeilen und speichert sie in einer temporären Datei. Dies muss vor Schritt 3 erfolgen. Ein früherer Fehler führte dazu, dass die beiden Schritte vertauscht wurden, wodurch die Einpflegung weiterhin die eigene Transkription der Maschine erneut las.
- Senden Sie Ihre eigene Transkription. Es kopiert die lokale Claude-Sitzungstranskription in
active.jsonl, führt einen Commit durch und sendet die Datei hoch, bevor es das Wasserzeichen auf die lokale Zeilenanzahl setzt.
Sobald die Gruppe die Kontrolle freigibt, erreicht der in Schritt 2 gespeicherte Delta-Unterschied Claude als Systemnachricht, die angibt, dass die andere Maschine seit dem letzten Synchronisieren N Nachrichten hinzugefügt hat. Der nächste Prompt erhält anschließend den Kontext beider Maschinen.
Eine separate .linecount-Datei enthält die tatsächliche Gesamtzahl der Zeilen, da wc -l irreführend ist, sobald eine Transkription zum Hochladen gekürzt wurde. Um unter der 25-MiB-Limitierung von git zu bleiben, werden Transkripte auf 1.000 Zeilen gekürzt, bevor sie hochgeladen werden. Ohne .linecount würde jede Kürzung das Wasserzeichen zurücksetzen und die Wiedergabe würde bereits gesehene Tausende von Zeilen erneut liefern.
Die durch flock serialisierte git-Operation verhindert eine Korruption von index.lock durch gleichzeitige Hochladevorgänge – was bereits einmal geschah, als ein blockierter Sitzungsstart mit dem Ausführen eines Meta-Enrichers kollidierte. Ein drosselbarer Mechanismus, standardmäßig auf 30 Sekunden eingestellt, überspringt bei schnellen Tasteneingaben die vollständige Synchronisierung, sodass es keine git-bezogene Verzögerung pro Zeichen gibt.
Die übergeordnete Idee, die man sich aneignen sollte, ist Git als Zustandsspeicher. Hier dient Git nicht nur als Code-Repository, sondern fungiert auch als langlebiger Log im Stil von CRDTs für den Zustand der Agenten, wobei die beiden Maschinen des Operators als letztendlich konsistente Leser fungieren.
Die Gedächtniskonsolidierung hängt eng mit der Kontinuität über verschiedene Maschinen hinweg zusammen. Der Schritt „memory_consolidate“, der die Transkripte in saubere DATEIEN TASK.md und ANALYSIS.md umschreibt, wird nicht nach einer Zeitvorlage ausgeführt. Ein separates Service namens consolidate_trigger prüft bei jeder Runde vier Signale: einen Commit-SHA oder ein Entscheidungsverb im Transkript, einen gerade geschlossenen Überprüfungsthread, ein Arbeitsbereich mit mehr als 5 KB an angesammelten Transkripten oder mindestens eine Stunde seit der letzten Konsolidierung. Jedes dieser Signale kann sie auslösen. Der Grund dafür ist, dass Informationen nach einer Entscheidung aufhören, sich anzuhäufen – und nicht nach einer festgelegten Zeitdauer. Gemeinsam ermöglichen die vier Signale eine Einschätzung, ob das Gespräch eine natürliche Pause erreicht hat, sodass der Operator dies nicht extra angeben muss.
Worktrees sind mehr als nur ein Implementierungsdetail
Zuvor wurde gesagt, dass alles in Worktrees abläuft. Das erfordert eine Erklärung, denn die dahinterstehende Entscheidung hat tatsächlich große Bedeutung.
Das ursprüngliche Design sah vor, dass der Agent einen Diff ausgibt und das Harness in dem Haupt-Repo-Checkout git apply ausführt. Dadurch traten zwei wiederkehrende Fehlermuster auf:
- Brüchige Diff-Überschriften. Claude gab einen Diff aus, dessen Zeilennummern zum Zeitpunkt der Erstellung korrekt waren, aber nach dem Eintreffen eines gleichzeitigen Commits falsch wurden, wodurch
git applyden gesamten Patch ablehnte. - Ein blockierter Hauptbaum. Wenn
git apply --checkauf halbem Weg fehlschlug, blieb das Haupt-Repo teilweise angewendet, und der nächste Vorgang im selben Repo übernahm diesen „schmutzigen“ Baum.
worktree_manager ist die Lösung. Vor jedem Agenten, der Code ändern muss, erstellt er einen abgeschirmten Arbeitstree unter ~/.worktrees/case-<case_id>-<stamp>/, der von einer sauberen Branch aus heruntergeladen wird. Claude arbeitet dort mit seinen eingebauten Bearbeitungs- und Schreibwerkzeugen, wodurch git apply sowie der Hin- und Rückweg über Diff-Texte entfallen. Es verhält sich wie ein menschlicher Ingenieur: neue Branch, neuer Download, anschließend Bearbeitung, Commit und Push.
Sobald der Pull Request integriert oder geschlossen wird, wird der Arbeitstree entfernt. Ein teilweiser Fehler betrifft nur diesen Arbeitstree und lässt die Haupt-Branch sowie andere gleichzeitige Fälle unberührt.
Deshalb sind mehrere Agenten auf derselben Maschine überhaupt sicher. Ohne Arbeitstrees pro Fall würden zwei Fälle im selben Repository um den Zugriff auf den Dateisystemzustand konkurrieren. Mit ihnen sind die Fälle von vornherein isoliert.
The harness behebt seine eigenen Pull Requests
Die Quelle des Harnesses befindet sich in einem privaten GitHub-Repository. Wenn der Gap-Report, das Finalisieren sowie der MR-Lauf eine Verbesserungsvorschlag für den Harness selbst ergeben, durchläuft dieser Vorschlag dessen eigene CI-Pipeline mit pytest, Lintern und einer Python-Syntaxprüfung. Ein separates Service namens pr-ci-fixer kümmert sich auf dieselbe Weise um eventuelle Fehler wie mr-monitor um Fehler in Ticket-MRs.
Dadurch erfolgt eine Selbstbehebung sowohl für den für Tickets geschriebene Code als auch für den Code bezüglich des Harnesses. Angenommen, ein MR fügt einen neuen Wiederholungsversuchsbudget hinzu und bricht dabei einen bestehenden Test, wodurch die CI fehlschlägt. pr-ci-fixer erkennt dies, startet eine Claude-Sitzung in einem Worktree, behebt das Problem und pusht erneut, sodass der menschliche Reviewer einen grünen MR vorfindet, der direkt eingemergt werden kann. Der Kreislauf hat sich bereits mehrfach bei tatsächlichen Änderungen am Harness geschlossen.
Die Überprüfung, ob der Loop auf die eigene Quelle des Harnesses verweist, ist die beste Methode, um festzustellen, ob er tatsächlich den Namen „Production“ verdient. Ein Agent, der seine eigenen Pull Requests erfolgreich abschließen kann, ist vermutlich geeignet, auch die von anderen zu betreuen.
Fünf Testebenen für fünf Fehlerkategorien
Der Harness enthält 4.656 Testfunktionen in insgesamt 126 Dateien. Diese Zahl sagt wenig ohne ein Framework, das angibt, was jeder Test überprüft – schließlich sind Tests nicht alle gleich.
Das L0 bis L4-Framework ordnet jeden Test einer der fünf Ebenen zu, je nachdem, was er überprüft:
- L0, reine Grenzüberprüfung. Es werden keine Mocks verwendet, es gibt weder Dateisysteme noch Eingabe/Ausgabe-Operationen. Hier werden reine Logiken wie Gate-Funktionen, JSON-Extraktion sowie Berechnungen zum Konfidenzrahmen überprüft; alles, was bei L0 funktioniert, funktioniert auch in jedem Deployment-Umfeld.
Die L4g-Tests sind am aufwendigsten in der Erstellung und am wertvollsten in der Aufrechterhaltung. Sie enthalten institutionelles Wissen über Fehlermuster, die bis zu ihrem erneuten Auftreten unsichtbar bleiben.
Ein Stilleitfaden, der verhindert, dass die Ausgabe wie maschinengeschrieben wirkt
Jeder Pull Request durchläuft vor der Einreichung einen weiteren Filter – es handelt sich dabei um eine speziell erstellte Prozessanleitung, damit das Ergebnis nicht wie von KI erzeugt aussieht. Die Regeln sind eindeutig:
- Ganzekeine Angabe einer KI. Kein
Co-Authored-By: Claude, kein „Generated with Claude Code“ und kein[bot]-Suffix in den Commit-Nachrichten. Der Pull Request gehört dem Team und nicht dem Modell. - Keine auszufüllenden Überschriften. Vorlagen wie „Was dieser Pull Request leistet / warum wir ihn benötigen“ sind verboten. Die Beschreibung besteht aus kontinuierlichem Text mit einer konkreten
Changes:-Aufzählung, geschrieben auf die Weise, wie es ein Ingenieur von Hand tun würde. - Keine fettgedruckten Inline-Tags. Ein
Root cause:-Label gefolgt von einem Absatz ist nicht zulässig, genauso wenig wieFix:undRisk:. Fettgedruckte Tags sind der zuverlässigste Hinweis auf maschinengenerierte Texte.
pytest tests/test_foo.py::test_bar -v mit dem tatsächlichen Befehl sowie den entsprechenden 3 Ausgabezeilen schon.Zur Zeit der Erstellung der MR-Beschreibung wird die SOP in den Prompt zur Patch-Generierung eingefügt. Sie steht getrennt vom Prompt-Template da, weil die Operator sie verwalten: Editieren Sie sie jederzeit nach Belieben – die nächste MR folgt dann den neuen Regeln, ohne Neustart des Daemons oder Änderungen am Code. Selbst der Gap-Loop kann Vorschläge zur Anpassung der SOP einreichen, sodass Metaregeln darüber, wie der Agent MRs erstellt, als eigene MRs gegenüber dem Dateiinhalt, in dem sie gespeichert sind, weitergegeben werden.
Dies ist wichtiger, als es klingt. Nichts zerstört das Vertrauen in einen automatisierten MR-Prozess schneller, als wenn das Team bemerkt, dass alle Beschreibungen wie maschinengeneriert wirken. Sobald sich dieses Bild festsetzt, steigt der Merge-Bar-Wert, die echten Signale des Mitarbeiters gehen unter, und die Operator beginnen, die Beschreibungen von Hand umzuschreiben – was dem Zweck widerspricht. Die Stilrichtlinien sorgen dafür, dass die Beschreibungen sich mit menschlich verfassten Texten vermischen, wodurch der Prozess weiterhin funktioniert.
Ein Ticket, ein MR – von Anfang bis Ende
So verläuft der Ablauf, wenn ein echtes Ticket eintrifft. Die Zeiten sind ungefähre Werte.
Insgesamt dauert dieser Prozess für ein kleines oder mittelgroßes Ticket in der Regel 30 bis 90 Minuten. Die gesamte aktive Beteiligung des Operators beträgt in der Regel weniger als 5 Minuten: Bestätigung der Analyse, gegebenenfalls Leitung bei unklaren Entscheidungen und optionales Klicken auf „Merge“.
Es sammeln sich Untersuchungen. Nach 30 Fällen gibt es 30 gap_report*.md-Dateien, jede mit einer Anmerkung darüber, was das LLM für verbessert halten könnte. Ein admin: gap-patterns-Ablauf alle zwei Wochen gruppiert sie in wiederkehrende Fehlermuster, und die anschließende Endabnahme wandelt die größten Cluster in MRs um, die sich auf das harness-Repo richten – dadurch verbessert sich das harness selbst. Das ist der in die Tat umgesetzte Selbstverbesserungskreislauf.
Vergleich mit anderen Harnesses
Mehrere andere Systeme haben eine ähnliche Struktur wie dieses Harness. Die Tabelle zeigt, wo es Überschneidungen mit ihnen gibt und wo es abweicht:
Wo dieses Harness ungewöhnlich tief geht:
- Verriegelung der Hypothese vor der Bearbeitung. Claude legt mindestens sechs Hypothesen vor, bevor eine Untersuchungsrunde ausgeführt wird, was eine nachträgliche Rationalisierung verhindert. Keines der im Vergleich stehenden kommerziellen Tools bietet etwas Ähnliches.
- Ein Qualitätskontrollrahmen mit 19 Funktionen und mechanischen Vertrauensgrenzen. Das Vertrauen wird durch eine feste Formel begrenzt, die bei 1,0 beginnt und pro offener Frage um 0,08 sowie pro unüberprüfter Quelle um 0,05 abnimmt – es handelt sich somit um mehr als nur eine selbst gemeldete Zahl. Zu den drei Kontrollkategorien für logische Konsistenz, strukturelle Vollständigkeit und Aussagegrenzen kommen noch dimensionsspezifische Strafmaßnahmen hinzu. Keines der im Vergleich stehenden kommerziellen Tools bietet dies.
oncall_run über case_followup, gap_analyzer, finalize_case bis zu dev-agent. Jeder Übergang verfügt über ein definiertes Übergabeschema sowie einen isolierten Arbeitsbaum, wodurch die Arbeit unter den Agenten aufgeteilt wird anstatt auf einen einzigen Agenten abgewälzt zu werden.Dort, wo es absichtlich schlicht gehalten ist:
- Es gibt kein formelles Bewertungswerkzeug. Das LLM wird nicht anhand von Benchmarks bewertet, sondern die Rückmeldungen aus der Produktion dienen als Bewertungsgrundlage.
- Es gibt kein Dashboard, nur Slack und Logs.
- Es gibt keinen Kostenanzeiger. Die Token-Nutzung wird nur ungenau erfasst und nicht im Dashboard angezeigt; die Kosten werden stattdessen durch die Bestätigungsprozesse durch Menschen begrenzt.
Was bleibt und der Meta-Zyklus
Das Werkzeug entwickelt sich weiterhin, es gibt noch offene Punkte in Bezug auf die Abdeckung des autonomen Zyklus, die Kostenmessung sowie ein formelles Bewertungswerkzeug – doch keines davon stellt ein Hindernis dar. Es erfüllt bereits seinen ursprünglichen Zweck: Slack-Signale in zusammengeführten Code umzuwandeln, Rückmeldungen von Reviewern über Nacht zu beantworten, den CI-Prozess selbstständig zu reparieren und seine eigenen Verbesserungen in die nächste Version einzubringen.
Die eigentliche Lektion ist der Meta-Zyklus. Jede „Scar“ im Harness existiert, weil ein echtes Ticket Druck auf sie ausgeübt hat. Entwicklung und Betrieb bilden einen Zyklus, der mit zwei verschiedenen Geschwindigkeiten abläuft. Das Produktionssignal fließt zurück zu der Quelle des Harnesses selbst – der Agent entwirft eine Korrektur, ein Mensch prüft und integriert sie, wodurch eine weitere Gruppe von Fehlern der Beseitigung näherkommt.
Das System ist noch nicht fertig. Ein Produktionsharness, der glaubt, fertig zu sein, hat aufgehört, „Scars“ anzusammeln – was wiederum bedeutet, dass er nicht mehr unter echter Last läuft.
Bauen Sie zunächst den Zyklus auf und machen Sie ihn anschließend autonom. Ein autonomes System ohne Rückkopplungspfad zu seinem eigenen Substrat führt einfach dieselben Fehler nur schneller und in größerer Anzahl aus – deshalb ist die Reihenfolge wichtig.