Zum Inhalt springen
covey

Ein Agent, der nur auf Zuruf arbeitet, ist ein Chatfenster mit Verwaltungsaufwand. Er soll selbst nachsehen, ob auf seinen Merge Request geantwortet wurde, und dafür braucht er einen Takt. Auf Hacker News wird genau das gefragt: Die meisten Agenten seien reaktiv und arbeiteten nur auf Ansprache. Offen bleibe, ob man dafür Cronjobs, eigene Middleware oder etwas anderes nimmt (news.ycombinator.com/item?id=48028035).

Dahinter steht eine Rechnung. Ein Zeitplan ist billig, ein Agentenlauf ist teuer. Wer beides ungeprüft koppelt, bezahlt alle fünf Minuten einen vollständigen Lauf für die Auskunft, dass nichts zu tun war.

Ein Show-HN-Projekt wirbt deshalb mit geplanten Agenten, die an einem ruhigen Tag nichts kosten (item?id=49475656). Vor dem Lauf steht dort ein Wächter-Befehl ohne Modell. Schweigt er, bleibt der Agent schlafen.

Eine Zeile in HEARTBEAT.md beschreibt den Takt

Das Verhalten eines covey-Agenten steht in versionierten Markdown-Dateien, darunter SOUL.md für Rolle und Ton und HEARTBEAT.md für die wiederkehrenden Aufgaben. HEARTBEAT.md ist dabei Plattformkonfiguration und kein Prompt-Material: Die Datei wird beim Speichern geparst, statt in den Systemprompt einzugehen. Eine Zeile darin sieht so aus:

- alle: 15m nur-wenn: gitlab:mr titel: Merge Requests betreuen aufgabe: Prüfe deine offenen Merge Requests auf neues Review-Feedback, arbeite es ein und reagiere auf Merge oder Close.

Pro Eintrag steht genau eine der beiden Zeitplanformen. alle: nimmt ein Intervall, beispielsweise 30m, 2h oder 1d, und täglich: nimmt eine Uhrzeit in Serverzeit. Der Parser ist an dieser Stelle streng, sodass eine erkannte Zeile ohne titel: oder ohne genau einen Zeitplan einen Fehler zurückgibt; ein geschluckter Tippfehler würde bedeuten, dass die Aufgabe nie wieder läuft.

Beim Speichern der Konfiguration wandern die Einträge in die Tabelle agent_heartbeats, angelegt mit Migration 0013, wobei last_fired_at bei now() beginnt. Ein frisch angelegter Heartbeat feuert deshalb erst nach Ablauf seines Intervalls.

Der Takt selbst kommt ohne Modell aus

Die Kontrollebene tickt standardmäßig alle 30 Sekunden und ist über COVEY_TICK_INTERVAL einstellbar. Die Frage nach dem Fälligen ist dabei eine reine SQL-Entscheidung. Die Intervallform ist fällig, sobald last_fired_at plus Intervall erreicht ist, die Tagesform einmal je Tag ab der eingetragenen Uhrzeit.

Ein fälliger Eintrag wird zu einer gewöhnlichen Backlog-Aufgabe mit origin='heartbeat'. Von dort an gilt der übliche Ablauf: Sandbox hochfahren, Aufgabe aufnehmen, arbeiten, Ergebnis festhalten, wieder schlafen.

Der optionale Zusatz nur-wenn: schiebt eine Nachfrage davor und nennt ein Zielsystem, dessen Plugin die Kontrollebene über die Schnittstelle target.WorkChecker nach wartender Arbeit fragt, bei email nach ungelesenen Mails im Arbeitsvorrat. Die Zugangsdaten löst sie selbst auf und behält sie bei sich.

Ein Doppelpunkt verengt den Bereich, etwa gitlab:mr für die Review-Schleife und gitlab:issues für die Issue-Sichtung, sodass zwei Heartbeats desselben Systems getrennt feuern. Meldet das Zielsystem keine Arbeit, entfällt der Lauf. last_fired_at rückt trotzdem vor, sodass der Zeitplan im gewohnten Rhythmus weiterfragt.

Die Prüfung ist fail-open: Fehlt dem Plugin der WorkChecker, fehlen die Zugangsdaten oder bricht die Verbindung, feuert der Heartbeat wie gewohnt.

Schweigen wird eine gültige Antwort

Eine nur-wenn:-Bedingung misst einen Pegel, und „dort wartet Arbeit" bleibt wahr, solange der Zustand besteht. Bei einem Merge Request weckt derselbe Kommentar den Agenten in jedem Intervall erneut, solange der letzte Beitrag von jemand anderem stammt.

Ein Agent beendet einen Lauf bewusst kommentarlos, etwa weil die Rückmeldung des QA-Kollegen eine Freigabe war. Er würde am Ende nur noch kommentieren, um seinen eigenen Wecker abzustellen. Zwischen zwei Agenten trägt das einen Selbstläufer: Jeder Kommentar schließt das eigene Tor und öffnet das des anderen.

Deshalb liefern Plugins neben dem Ja oder Nein eine Signatur des gefundenen Arbeitsvorrats. Bei GitLab sind das Projekt, Nummer und höchste Notiz-ID je wartendem Strang. Die Kontrollebene hält sie in agent_heartbeats.last_work_sig, ergänzt mit Migration 0038, und feuert erst wieder, wenn die Signatur sich geändert hat.

Der Agent wird damit zu jeder Neuigkeit geweckt und zu derselben kein zweites Mal.

Nachgeführt wird die Signatur nur nach einem Lauf, der selbst geschrieben hat. Über target.SignatureWriter melden Plugins, welche ihrer Aktionen sie bewegen können. Bei GitLab zählt alles dazu, was eine Notiz erzeugt: Zuweisung, Label, Freigabe, Push und Merge. Ein Lauf ohne eigene Schreibaktion lässt die Wassermarke stehen. Der nächste Tick feuert dann für das, was inzwischen angekommen ist.

Eine Lücke bleibt.

Ein fremder Beitrag in genau dem Strang, den der Agent selbst kommentiert hat, geht in diesem Fenster in der Wassermarke auf. Zum Trennen bräuchte es die IDs der Notizen aus dem Lauf selbst, und die Aufzeichnung hält allein die Aktion fest.

Wo der Takt von selbst aufhört

Ein Heartbeat hält seine Läufe auseinander. Besteht aus diesem Heartbeat noch eine Aufgabe desselben Titels, die offen, in Arbeit oder blockiert ist, bleibt es bei dieser einen. Der Lauf gilt trotzdem als gefeuert, sodass nach dem Abschluss der reguläre Zeitplan einfach weiterläuft.

Die Fortsetzung eines abgebrochenen Laufs zählt mit. Sie trägt den Herkunftsvermerk continuation:<Aufgaben-ID> und behält den Titel, da sie dieselbe Arbeit weiterträgt. Verpasste Läufe holt die Kontrollebene nicht nach; stand sie über Nacht, feuert allein der nächste fällige Lauf.

Drei Zustände halten den Takt vollständig an. Die Abfrage verlangt hired_at IS NOT NULL, sodass ein noch nicht eingestellter Agent übersprungen wird, und killed am einzelnen Agenten sowie fleet_killed an der Organisation unterdrücken das Feuern ebenso.

Läuft ein Agent in seine Zugbegrenzung, meldet die Laufzeit den Zustand incomplete. Eine Fortsetzung nimmt dieselbe Sitzung wieder auf. Nach drei Fortsetzungen in Folge, in maxContinuations festgelegt, eskaliert die Aufgabe an die vorgesetzte Person. Das Budget je Agent zieht eine weitere Grenze: Beim Überschreiten der kumulierten Kosten pausiert die Plattform den Agenten über denselben Kill-Switch.

Was der Heartbeat tut, wenn niemand zusieht, ist an den meisten Abenden wenig: eine SQL-Abfrage, eine Nachfrage beim Zielsystem, ein Vergleich zweier Signaturen. Der teure Teil beginnt erst, wenn sich etwas geändert hat.

Zurück zur Übersicht