Wie betreibt man Claude Code auf einem Server, ohne davorzusitzen?
Claude Code läuft headless mit einem Schalter. Was ein Serverbetrieb sonst braucht: ein Schlüssel außerhalb des Containers, eine Sitzung, die wartet, Grenzen am Aufruf.
Ein nachts arbeitender Agent braucht zuerst einen Rechner, der nachts läuft. Der übliche Weg dorthin ist bekannt: eine kleine Maschine bei einem Hoster mieten, Claude Code installieren, das Repository klonen.
Dazu kommt ein privates Netz gegen offene Ports und tmux, damit die Sitzung den Verbindungsabbruch überlebt. Danach kann man den Deckel zuklappen und den Rechner die Nacht über allein arbeiten lassen. Das funktioniert.
Was fehlt, zeigt sich erst im Betrieb der ersten Wochen. Auf einem Linux-Server liegt der Token unter ~/.claude/.credentials.json mit dem Dateimodus 0600. Gegen ein anderes Konto schützt dieser Modus, und jeder weitere Prozess desselben Kontos liest die Datei trotzdem, etwa der Cronjob oder der Deploy-Hook. Niemand hat festgelegt, wie viele Schritte ein Lauf machen darf.
Was in dem Fenster passiert ist, steht danach allein im Scrollback-Puffer, und der ist begrenzt: In der Voreinstellung hebt tmux 2000 Zeilen auf. Und wenn der Kunde am Vormittag antwortet, sitzt niemand davor, der die Antwort in das wartende Fenster tippt.
Genau an dieser Stelle setzt covey an. Es ruft dasselbe Werkzeug im selben Modus auf, und der Unterschied liegt im Betrieb drumherum.
Headless ist ein Schalter, der Betrieb ist der Rest
Claude Code bringt den nicht-interaktiven Modus mit: claude -p "…" führt einen Auftrag ohne Oberfläche aus. Der Daemon im Sandbox-Image spricht das Werkzeug über einen Adapter an, headless, mit --output-format stream-json.
Aus diesem Strom kommt mehr heraus als das Ergebnis, nämlich der ganze Verlauf. Jede Zeile ist ein JSON-Ereignis vom Typ assistant, tool_use oder result und der Daemon reicht jede einzelne an die Control Plane weiter. Die Aufzeichnung eines Laufs kostet dadurch fast nichts: Wer ihn später ansieht, sieht jeden Werkzeugaufruf statt einer Zusammenfassung.
Am selben Aufruf hängt das Schrittlimit des Agenten. --max-turns trägt es, und ohne eigenen Wert setzt der Orchestrator die Vorgabe von dreißig ein. Das Budget reist im Laufauftrag als Feld MaxBudgetUSD mit, und der Adapter lässt es beim Bauen der Argumente liegen.
Die Kostengrenze wirkt eine Ebene höher. Das abschließende result-Ereignis nennt total_cost_usd, und der Daemon meldet den Betrag an die Control Plane. Dort hält der Orchestrator die bisherige Gesamtsumme des Agenten gegen dessen Feld BudgetUSD und gegen die Guard-Rule budget_limit, von denen die strengere gilt. Ist die Grenze erreicht, pausiert der Agent, die Aufgabe geht mit „budget exceeded“ wieder auf, und der Daemon bekommt ein TypeKill mit dem Grund budget.
Geprüft wird dabei erst beim Eintreffen eines Kostenberichts, und den liefert Claude Code zum Schluss eines Laufs; zwischen zwei Berichten kann die Summe die Grenze deshalb überschreiten.
Auf einem Abo-Platz ist dieser Betrag rechnerisch: Claude Code preist den Lauf, als wäre er abgerechnet worden, bezahlt ist der Platz ohnehin. Die Plattform übernimmt ihn unverändert und beschriftet ihn mit dem Zugang, aus dem er stammt.
Der Schlüssel liegt nicht in der Sandbox
In einer frisch gestarteten Sandbox hat sich nie jemand interaktiv angemeldet. Ohne hinterlegtes Secret liegen dort deshalb keine Zugangsdaten, und jede Aufgabe scheitert an „Not logged in · Please run /login“, das der Adapter zu einem Hinweis auf das fehlende Secret umschreibt. Drei Formen sind vorgesehen: ein API-Schlüssel in ANTHROPIC_API_KEY, ein langlebiger OAuth-Token, einmal mit claude setup-token erzeugt, sowie Zugangsdaten eines Anbieters für Bedrock, Vertex oder Foundry.
Welcher Name welche Variable füllt, ist festgelegt und wird nicht aus dem Präfix des Tokens geraten: anthropic_api_key wird zu ANTHROPIC_API_KEY und claude_code_oauth_token zu CLAUDE_CODE_OAUTH_TOKEN.
Der Unterschied zur Maschine unter dem Schreibtisch liegt aber woanders. Der Schlüssel ist ein gebrokertes Geheimnis. Dauerhaft liegt er nicht in der Sandbox, sondern wird dem Daemon zur Laufzeit eingesetzt.
Eine Sitzung, die auf die Antwort von morgen wartet
Headless-Läufe sind zunächst zustandslos und lassen sich trotzdem zu einer Kette verbinden. Der Aufruf liefert eine session_id zurück, und ein späterer Lauf mit --resume <session_id> lädt den Kontext des vorherigen.
covey benutzt das für den Fall, den ein tmux-Fenster nicht abbilden kann.
Stellt der Agent eine Rückfrage, meldet der Daemon die Aufgabe als blocked und speichert den Korrelationsschlüssel samt session_id auf der geparkten Aufgabe. Trifft die Antwort im Ticket ein, startet die Sandbox neu und der Adapter ruft claude -p --resume <session_id> damit auf. Der Agent wartet nicht, er schläft und kostet schlafend nichts als eine Zeile in der Datenbank.
Die Grenze dieser Sitzung steht in spec/12 gleich daneben. Sie ist Kurzzeitgedächtnis, ein begrenztes Kontextfenster, das ablaufen kann. Dauerhaftes Wissen liegt in der Speicherschicht der Plattform, in den Wiki-Seiten des Agenten.
Was den Container überlebt, und was nicht
Der Container entsteht zu jedem Aufwachen und verschwindet nach dem Lauf wieder. Was bleibt, ist /home/agent: die geklonten Repositories, die heruntergeladenen Anhänge, die Wiki-Seiten und ~/.claude. Der Lauf startet mit diesem Verzeichnis als HOME.
Daraus folgt eine Regel für jedes Werkzeug eines Agenten: Toolchain ins Image, Version ins Home. Das Home wird bei jedem Aufwachen durchgelaufen und nach jedem Lauf zurückgeschrieben, das Image liegt einmal pro Runner. Das Sandbox-Profil dev-flutter kehrt diese Regel absichtlich um: Im Profil dev holt fvm das rund 1,3 GB große SDK in das Home jedes Flutter-Agenten, während dieses Rollenprofil die Grundversion im Image trägt, da für einen Flutter-Agenten die Versionsfrage entschieden ist und fvm daneben installiert bleibt.
Der Preis dieses Aufbaus ist die Nebenläufigkeit: Ein Agent bearbeitet eine Aufgabe zur Zeit, weil zwei gleichzeitige Läufe desselben Agenten um dasselbe Home streiten würden. Mehr Durchsatz entsteht deshalb aus mehr Agenten, die nebeneinander laufen. Wer Startzeit sparen will, schaltet zusätzlich eine warme Sandbox ein: Der Container bleibt zwischen zwei Aufwachphasen stehen, kostet Speicher und spart Sekunden.
Den Deckel zuklappen kann man in beiden Aufbauten, und der Unterschied zeigt sich am Morgen danach.
Er zeigt sich daran, ob jemand nachlesen kann, was in der Nacht passiert ist, und ob der Lauf von selbst dort weitermacht, wo die Antwort des Kunden ihn erwartet.