Zurück zum Blog

Natives SSH für Comma-Agenten

LoslegenDokumentation lesen

Der Heimserver schließt sein nächtliches Backup nicht mehr ab. Die Logs liegen auf dem Server, der Server steht hinter dem Router, und Comma soll herausfinden, was passiert ist, statt eine Liste von Befehlen zu liefern, die man hin und her kopiert. Die Agenten von Comma können jetzt über SSH auf diesem Rechner arbeiten, ohne dass dort ein weiterer KI-Agent installiert wird.

Der Agent lebt außerhalb der Sandbox

Die meisten Cloud-Agenten laufen in ihrer Sandbox: einem Container oder einer VM, die Modellschleife, Tools und Dateien enthält und so lange läuft wie der Agent. Salix, das verteilte Harness hinter Comma, trennt diese Teile. Die Agent-Schleife läuft im Harness, außerhalb jeder Sandbox, mit mehr als 100 Agenten pro CPU-Kern. Eine Cloud-VM oder ein Gerät ist ein Ort, an dem Befehle laufen, und wird nur genutzt, wenn die Arbeit einen Computer braucht.

Um auf dem Server zu arbeiten, zieht der Agent also nicht dorthin um. Er ruft aus dem Harness native SSH-Tools auf:

  • ssh.open, ssh.write, ssh.read und ssh.screen für ein interaktives Terminal, auch mit Vollbildprogrammen;

  • ssh.exec für einen einzelnen Befehl, mit getrennter Ausgabe von stdout, stderr und Exit-Status;

  • ssh.list_files, ssh.download und ssh.upload für Dateien, über SFTP;

  • ssh.close und ssh.list für den Lebenszyklus der Verbindung.

Der Agent authentifiziert sich mit einem Group SSH key: einem Schlüssel pro Workspace, den sich dessen Agenten teilen. ssh.public_key gibt ihn zurück, und er wird auf dem Rechner in ~/.ssh/authorized_keys eingetragen, wie für jeden anderen SSH-Client.

Das Harness kann den Rechner auf drei Wegen erreichen.

1. Eine öffentliche Adresse

Hat der Rechner bereits einen erreichbaren SSH-Server, verbindet sich der Agent mit dessen IP-Adresse oder DNS-Namen:

json
{ "tool": "ssh.open", "params": { "host": "203.0.113.10", "user": "deploy" } }

2. Tailcat, für einen Rechner ohne öffentliche Adresse

Ein Laptop oder ein Heimserver hinter NAT hat oft keine Adresse, die das Harness anwählen kann. Tailcat bindet ihn an, ohne eingehenden Port, VPN oder Konto. Es läuft auf dem Rechner, baut nur ausgehende Verbindungen auf und gibt eine Adresse aus, die mit tc beginnt.

Tailcat kann auch selbst der SSH-Server sein. Dazu wird es mit dem öffentlichen Group-Schlüssel gestartet:

sh
tailcat serve --ssh-authorized-keys='ssh-ed25519 AAAA...' ssh

Das liefert eine Login-Shell, Befehlsausführung und SFTP unter dem Konto, das Tailcat ausführt. Es braucht kein sshd und ändert die SSH-Konfiguration nicht. Läuft auf dem Rechner bereits OpenSSH, genügt stattdessen tailcat serve 22, und OpenSSH übernimmt den Login. Danach geht die Adresse an den Agenten:

json
{ "tool": "ssh.open", "params": { "tailcat": "tc...", "user": "deploy" } }

3. Das eigene Tailscale-Netz

Sind die Rechner bereits in einem Tailnet, kann der Workspace ihm beitreten. Die Verbindung lässt sich in den Einstellungen der Comma-App herstellen, oder der Agent übernimmt das auf Anfrage. Ein Tailnet-Admin öffnet einen Login-Link und genehmigt den Node. Der Node trägt standardmäßig das Tag tag:comma-agent, sodass die Tailnet-Policy genau festlegt, welche Geräte und Ports er erreicht, zum Beispiel nur Port 22 auf dem Heimserver.

Der Agent listet Geräte mit tailnet.peers auf und verbindet sich per MagicDNS-Name oder Tailscale-Adresse:

json
{
  "tool": "ssh.open",
  "params": { "host": "nas.tail1234.ts.net", "via_tailnet": true, "user": "deploy" }
}

Vertrauen und Lebensdauer

Auf jedem Weg speichert die erste Verbindung zu einem Host dessen Host-Key. Eine spätere Verbindung mit einem anderen Schlüssel wird mit host_key_mismatch und beiden Fingerprints abgelehnt, und der Agent fragt nach, bevor er den alten Schlüssel mit ssh.known_hosts.remove entfernt.

Eine SSH-Verbindung gehört zu genau einer Agent-Sitzung. Sie schließt sich nach 30 Minuten ohne Nutzung und übersteht weder einen Neustart des Agenten noch ein Deploy der Plattform. Lange Arbeit gehört deshalb in tmux oder screen auf dem entfernten Rechner. Befehle sind begrenzt: ssh.exec bricht standardmäßig nach 60 Sekunden ab, höchstens nach 600, und ein Timeout wird gemeldet, nie automatisch wiederholt.

Für das Backup könnte die Anweisung lauten: „Lies die Logs und prüf den freien Speicherplatz, aber lösch keine Dateien und ändere nichts an der Konfiguration. Sag mir zuerst, was du findest.“

Try Comma, Now.

Loslegen