Auf welcher Maschine läuft ein KI-Agent?
Jede Sandbox startet über einen Runner, auch auf einer einzigen Maschine. Wie covey den Host auswählt, was die Tags ausschließen und was ein Runner dafür sehen muss.
Zehn Agenten wachen zur selben Zeit auf. Jeder bekommt einen Container, und jeder Container will Arbeitsspeicher, Plattenplatz und ein paar Kerne. Auf derselben Maschine laufen die Control Plane und daneben Postgres.
Die Frage ist, wo der elfte startet. Unter einer Produktvorstellung auf Hacker News berichtete ein Entwickler im Mai 2026 von vielen Anfragen nach dem Betrieb auf einer getrennten Maschine: „in the cloud or some pc gathering dust in the corner". Nachzulesen ist das als Kommentar 48239451.
Covey beantwortet die Frage mit einem Runner. Das ist ein Prozess auf einem beliebigen Host, der sich nach dem Muster der GitLab-Runner bei der Control Plane anmeldet und von dort Sandboxen zugeteilt bekommt. Welcher Host welche bekommt, entscheidet eine Punktzahl.
Jede Sandbox startet über einen Runner, auch auf einer einzigen Maschine
Wer covey auf einer einzelnen Maschine installiert, hat trotzdem einen. covey serve betreibt einen eingebauten Runner im eigenen Prozess, einen je Organisation. Die Einrichtung bleibt dadurch dieselbe: Registrierungstoken, Konfigurationsdatei und zweites Artefakt entfallen.
Der eingebaute und der entfernte Weg sind dabei derselbe Code. Getrennt werden sie allein durch einen Transport: ein Kanalpaar im einen Fall und ein WebSocket im anderen. Ein eingebauter Runner mit einer Abkürzung zur Docker-CLI ließe den entfernten Weg genau dort unbenutzt, wo fast alle Installationen stehen.
Ein zweiter Host meldet sich an und sagt, was er ist
Ein Registrierungstoken entsteht in der Oberfläche und gilt 24 Stunden, nachzulesen als RegistrationTokenTTL in internal/runner/store/store.go Zeile 345. Auf dem neuen Host laufen drei Zeilen: das Installationsskript der eigenen Instanz, covey-runner register mit Adresse und Token, dann covey-runner run.
register schreibt Serveradresse, Runner-Token und Arbeitsverzeichnis nach /etc/covey-runner/config.toml und legt die Datei mit 0600 an. In der Datenbank liegt das Token nur als Hash.
Bei der Registrierung sagt der Host auch, was er ist und was er tragen kann. Ein Tag wie etwa --tag arm64 sagt, was er ist. max_sandboxes = 4 begrenzt, wie viele Sandboxen er gleichzeitig trägt, und die Vorgabe 0 hebt diese Grenze auf.
Gehütet wird dieses Limit von beiden Seiten der Verbindung. Der Scheduler wählt einen vollen Host nicht mehr aus, und der Host selbst lehnt einen Start darüber hinaus in seinem Log unter Nennung beider Zahlen ab. Nur er weiß, was in diesem Moment wirklich auf ihm läuft, und nur er fällt um, wenn die Zahl falsch ist.
Die Auswahl ist eine Punktzahl, und nur die Tags schließen aus
Kandidat wird ein Host nur, wenn er zur Organisation gehört, verbunden ist und die Tags des Agenten trägt. Das Sortieren danach ist eine Addition in internal/runner/pool.go Zeile 1590 bis 1624. Der Host, auf dem der Agent zuletzt lief, bekommt zwei Punkte Abzug, ein Host mit dem passenden Image einen. Bei gleicher Punktzahl gewinnt der mit den wenigsten laufenden Sandboxen.
Der Abzug für den letzten Host ist der größere, weil dort die Arbeitskopie des Homes liegt. Ein Image zu ziehen kostet Sekunden, ein 7 GB großes Home aus dem Store zu materialisieren kostet Minuten.
Von der Kandidatenliste ausgeschlossen wird ein Host allein über seine Tags. Das war einmal anders: Ein Host meldete, welche Images er hält, und bekam nur dazu passende Agenten. Im August 2026 beanspruchte ein registrierter Host covey-sandbox:latest. Die Agenten dieser Organisation brauchten das Deploy-Image, und die Kandidatenliste blieb damit leer. Eine halbe Stunde lang scheiterte jedes Aufwachen alle dreißig Sekunden neben einer Maschine, die die Arbeit hätte tragen können.
Daraus wurde eine Regel, die zwei Zustände eines Hosts unterscheidet. Ein Tag sagt, was ein Host ist, und dafür kann keine andere Maschine einspringen. Ein Image ist ein Zustand, der sich selbst repariert: docker run lädt nach, was fehlt.
Der eingebaute Runner wird zuletzt gefragt
In derselben Sortierung bekommt der eingebaute Runner zehn Punkte aufgeschlagen. Solange ein registrierter Host die Arbeit tragen kann, trägt er sie.
Springt er doch ein, steht es im Log: no connected runner fits — the built-in one takes it. Die Zeile nennt dazu das Image, die verlangten Tags und den Grund. Die Auswahl läuft nach diesem Einsprung erneut, und die Tags schließen ihn aus wie jeden anderen Host. Ein Agent, der arm64 verlangt, wartet auf arm64.
Wer keine Rechenlast auf der Maschine der Control Plane will, pausiert ihn. Eine Pause behält Token, Tags und Arbeitskopien und lässt Laufendes fertig werden; neue Sandboxen gehen anderswohin. COVEY_BUILTIN_RUNNER=off ist derselbe Satz in der Konfiguration der Instanz.
Früher trat der eingebaute Runner von selbst zurück, sobald eine Organisation einen eigenen Host registriert hatte. Diese Regel schloss aus einem Ereignis auf eine Absicht, und sie hat covey.work an einem Nachmittag zweimal die Data Plane gekostet. Eine Pause sagt dasselbe, gesetzt von einem Menschen und lesbar in der Runner-Ansicht.
Ein Runner sieht die Token der Agenten, die er trägt
Mit jedem Start bekommt er das Daemon- und das Egress-Token des Agenten, denn er muss beide in den Container geben. Er kann sich damit für jeden Agenten ausgeben, den er trägt, und das ist dieselbe Vertrauensstufe wie bei einem CI-Runner, der Job-Token sieht.
Die Dokumentation zieht die Grenze in einem Satz: Ein Runner ist vertrauenswürdige Infrastruktur der Organisation. Wer über ihn ungeprüfte Rechenkapazität hereinholt, hebt diese Grenze auf. Die Datenbank bleibt ihm verschlossen, die Zugangsdaten für den Objektspeicher ebenso.
Die gebrokerten Zugangsdaten eines Zielsystems gehen unmittelbar an den Daemon. Der Runner wählt hinaus, und kein Port muss für ihn offen stehen. TLS ist Pflicht, sobald er auf einer anderen Maschine läuft als die Control Plane.
Bleibt eine Sandbox aus, nennt die Meldung den Fall
Genannt werden etwa fehlende Runner in dieser Organisation, fehlende Tags, eine durchgehende Pause und das erreichte Sandbox-Limit. Der letzte Fall beschreibt eine Data Plane, die arbeitet, mit einer Warteschlange davor.
Deshalb trägt er im Code einen eigenen Satz.