Zurück zur Übersicht

Blog

Warum wir Tactic Remote auf tmux aufgebaut haben: Sitzungspersistenz und Terminal-Architektur

Tactic Remote verwendet tmux zur Verwaltung von Claude Code Sitzungen und bietet Persistenz über Netzwerkunterbrechungen, Mac-Ruhezustandszyklen und App-Neustarts hinweg, während die Terminal-Ausgabe in Echtzeit auf dein iPhone gestreamt wird.

Veröffentlicht Tags: architecture / tmux / reliability / engineering
Blog

Weitere Produkt- und Engineering-Updates aus dieser Kategorie.

Kategorie öffnen

Als wir mit dem Bau von Tactic Remote begannen, war die erste architektonische Entscheidung grundlegend: Wie hält man eine Claude Code Sitzung am Leben und beobachtbar, wenn das steuernde Gerät (dein iPhone) eine unzuverlässige Verbindung hat? Die Antwort war tmux, und diese Entscheidung hat fast alles andere am Produkt geprägt.

Das Problem

Claude Code läuft als langlebiger interaktiver Prozess. Eine typische Sitzung dauert 10 bis 60 Minuten. In dieser Zeit liest Claude Dateien, schlägt Änderungen vor, führt Befehle aus, wartet auf Genehmigungen und iteriert auf Feedback. Wenn der Prozess mitten in der Sitzung stirbt, geht der gesamte Kontext verloren. Claude muss von vorne beginnen, Dateien neu einlesen und sein Verständnis der Aufgabe rekonstruieren.

Auf einem lokalen Terminal ist das kein Problem — dein Mac bleibt an und der Prozess läuft bis zum Ende. Aber Tactic Remote führt einen mobilen Client ein. iPhones wechseln zwischen WLAN und Mobilfunk. Sie sperren den Bildschirm und suspendieren Hintergrund-Apps. Benutzer gehen durch Gebiete ohne Empfang. Jede Architektur, die den Prozesslebenszyklus von Claude Code an die Netzwerkverbindung des iPhones koppelt, ist grundlegend fehlerhaft.

Wir brauchten Claude Code, das unabhängig von jeder Client-Verbindung läuft, und Clients, die sich verbinden und trennen können, ohne die laufende Sitzung zu beeinflussen.

Warum tmux

tmux ist ein Terminal-Multiplexer, der seit 2007 im Produktivbetrieb eingesetzt wird. Er trennt das Konzept einer Terminal-Sitzung vom Terminal-Emulator, der sie anzeigt. Eine tmux-Sitzung läuft als Serverprozess auf der Host-Maschine. Clients verbinden sich, um die Sitzung zu sehen und mit ihr zu interagieren, und trennen sich, ohne die laufenden Prozesse zu beeinflussen.

Wir haben mehrere Alternativen evaluiert, bevor wir uns für tmux entschieden:

screen — Der ursprüngliche Terminal-Multiplexer. Funktional, aber weniger aktiv gepflegt und mit einer eingeschränkteren Scripting-API. Die strukturierte Befehlsschnittstelle von tmux machte die programmatische Steuerung deutlich einfacher.

Eigene PTY-Verwaltung — Wir haben einen Prototyp mit rohen Pseudo-Terminals über node-pty gebaut. Er funktionierte für einfache Fälle, erforderte aber die Neuimplementierung von Sitzungspersistenz, Fensterverwaltung und Ausgabepufferung. Wir bauten ein schlechteres tmux von Grund auf.

Container-basierte Isolierung — Claude Code in einem Docker-Container mit angeschlossenem PTY ausführen. Das fügt Overhead hinzu, verkompliziert den Dateisystemzugriff (Claude Code muss deine tatsächlichen Projektdateien lesen und schreiben) und führt eine Abstraktionsschicht ein, die mehr Probleme schafft als sie löst.

nohup / disown — Einfache Hintergrundprozessverwaltung. Keine Ausgabeerfassung, keine Wiederanbindung, keine programmatische Steuerung. Unzureichend für interaktive Sitzungen.

tmux bot uns alles, was wir brauchten: Sitzungspersistenz, programmatische Pane-Steuerung, Ausgabeerfassung und eine stabile, gut dokumentierte API. Der Kompromiss ist, dass tmux auf dem Mac des Entwicklers installiert sein muss, aber brew install tmux ist ein einmaliger Einrichtungsaufwand, den wir für akzeptabel halten.

Architektur

Die tmux-Integration von Tactic Remote funktioniert über drei Schichten:

Schicht 1: Sitzungsverwaltung

Wenn du eine Claude Code Sitzung über Tactic Remote startest, erstellt der Mac Companion eine neue tmux-Sitzung mit einer eindeutigen Kennung. Claude Code wird im primären Pane dieser Sitzung gestartet.

tmux new-session -d -s claude-remote-{session-id} "claude-code --project /path/to/project"

Das -d-Flag ist entscheidend — es erstellt die Sitzung im getrennten Modus. Kein Terminal-Emulator muss verbunden sein, damit die Sitzung existiert und läuft. Claude Code startet sofort, und der Mac Companion überwacht es im Hintergrund.

Jede Sitzung bekommt eine eigene tmux-Sitzung statt eines Panes in einer gemeinsamen Sitzung. Das bietet saubere Isolierung: sitzungsspezifische Umgebungsvariablen, unabhängige Scroll-Buffer und kein Risiko von Cross-Session-Interferenzen.

Schicht 2: Ausgabeerfassung und Streaming

Der Mac Companion erfasst kontinuierlich die Terminal-Ausgabe aus dem tmux-Pane und streamt sie über WebSocket an verbundene iPhone-Clients. Das ist der Mechanismus, der dir erlaubt, Claude Codes Ausgabe in Echtzeit auf deinem Telefon zu sehen.

Die Ausgabeerfassung nutzt tmux capture-pane mit Koordinaten, die den sichtbaren Pane-Inhalt plus den Scroll-Buffer abdecken. Der Companion führt eine Erfassungsschleife aus, die:

  1. Den aktuellen Pane-Inhalt in einem konfigurierbaren Intervall (Standard: 200ms) erfasst.
  2. Den erfassten Inhalt mit dem letzten bekannten Zustand vergleicht.
  3. Nur das Delta an verbundene Clients sendet.
  4. Einen Ringpuffer der letzten Ausgabe für Clients pflegt, die sich neu verbinden und aufholen müssen.

Das 200ms-Erfassungsintervall ist ein Gleichgewicht zwischen Reaktionsfähigkeit und CPU-Nutzung. Bei dieser Rate fühlen sich Terminal-Updates auf dem iPhone nahezu in Echtzeit an, während weniger als 2% CPU auf einem modernen Mac verbraucht werden. Wer schnellere Updates bevorzugt, kann das Intervall auf 100ms reduzieren; wer auf Batterie läuft, kann es auf 500ms erhöhen.

Schicht 3: Eingabe-Routing

Wenn du eine Eingabe vom iPhone sendest — ob Genehmigungsantwort, getippte Nachricht oder Sitzungssteuerungsbefehl — leitet der Mac Companion sie mit tmux send-keys an das entsprechende tmux-Pane weiter. Das erhält die Illusion einer direkten Terminal-Verbindung, während die tatsächliche Eingabe über WebSocket, durch das Netzwerk und in die tmux-Sitzung wandert.

Genehmigungsantworten sind ein Sonderfall. Anstatt als rohe Tastatureingaben gesendet zu werden, werden sie vom Hook-System verarbeitet und als strukturierte Antworten injiziert, die Claude Codes Berechtigungssystem erwartet. Das stellt sicher, dass Genehmigungen atomar sind und nicht durch partielle Netzwerkzustellung beschädigt werden können.

Persistenz in der Praxis

Die tmux-Architektur bietet Persistenz auf mehreren Ebenen:

iPhone-App wird geschlossen. Die tmux-Sitzung läuft weiter. Claude Code arbeitet weiter, und Genehmigungen werden auf dem Mac Companion in eine Warteschlange gestellt. Wenn du die iPhone-App wieder öffnest, verbindet sie sich mit dem WebSocket, empfängt die gepufferte Ausgabe, und du bist wieder da, wo du warst.

iPhone verliert die Netzwerkverbindung. Identisch mit dem Schließen der App aus Sitzungsperspektive. Der WebSocket bricht ab, Ausgabe wird auf dem Mac gepuffert, und Wiederverbindung stellt den Zustand her.

Mac geht in den Ruhezustand. tmux-Sitzungen überleben Schlaf- und Aufwachzyklen. Wenn der Mac aufwacht, wird der tmux-Serverprozess fortgesetzt, und jeder Claude Code Prozess, der gerade lief, setzt fort. Der Mac Companion stellt den WebSocket-Listener wieder her und verbindet sich mit dem iPhone.

Mac Companion stürzt ab. Die tmux-Sitzung überlebt unabhängig. Ein Neustart des Mac Companion erkennt bestehende tmux-Sitzungen mit dem Präfix claude-remote-, verbindet sich mit ihnen und nimmt das Streaming wieder auf. Kein Claude Code Kontext geht verloren.

Mac startet neu. Das ist das einzige Szenario, in dem tmux-Sitzungen nicht überleben, weil sie nur im Speicher existieren. Claude Code muss neu gestartet werden. Wir dokumentieren das klar und untersuchen die tmux-resurrect-Integration für zukünftige Versionen, obwohl die Komplexität der Wiederherstellung interaktiver KI-Sitzungen (nicht nur Shell-Zustand) dies nicht trivial macht.

Sitzungslebenszyklus

Eine Tactic Remote Sitzung durchläuft diese Zustände:

Zustandtmux-StatusiPhone-Status
StartendSitzung erstellt, Claude Code startetLadeindikator
AktivProzess läuft, Ausgabe fließtLive-Terminal-Ansicht
Wartet auf GenehmigungProzess durch Hook blockiertGenehmigungsbenachrichtigung
Pausiert (Client getrennt)Läuft, Ausgabe wird gepuffertNicht verbunden
AbgeschlossenProzess beendet, Sitzung beibehaltenSitzungszusammenfassung
AbgelaufenSitzung nach Aufbewahrungsfrist zerstörtArchiviert

Abgeschlossene Sitzungen werden für einen konfigurierbaren Zeitraum (Standard: 30 Minuten) in tmux beibehalten, damit du die finale Ausgabe auch nach dem Beenden von Claude Code überprüfen kannst. Nach der Aufbewahrungsfrist wird die tmux-Sitzung zerstört und das Ausgabeprotokoll archiviert.

Beobachtbarkeit

tmux gibt uns Introspektionsfähigkeiten, die mit einer eigenen PTY-Lösung schwer zu erreichen wären:

  • Sitzungsliste — tmux list-sessions liefert sofort eine Bestandsaufnahme aller aktiven Tactic Remote Sitzungen.
  • Pane-Dimensionen — Wir können Pane-Dimensionen abfragen und setzen, um sie an die Display-Eigenschaften des iPhones anzupassen und korrekten Zeilenumbruch sicherzustellen.
  • Prozessüberwachung — Der Befehl tmux list-panes mit Format-Flags ermöglicht die Überwachung des Claude Code Prozesses ohne separates PID-Tracking-System.
  • Zugriff auf den Scroll-Buffer — Der vollständige Scroll-Buffer steht für Suche und Abruf bereit und speist die Sitzungsverlaufsansicht auf dem iPhone.

Leistungsmerkmale

Die Ausführung über tmux fügt im Vergleich zu einem direkten Terminal minimalen Overhead hinzu:

MetrikDirektes Terminaltmux-Sitzung
Prozessstart~800ms~850ms
Tastaturlatenz<1ms~2ms
Speicher-Overhead pro Sitzung—~3MB
CPU-Overhead (inaktive Sitzung)—<0.1%

Der Overhead ist in der Praxis nicht messbar. tmux wurde über fast zwei Jahrzehnte Produktivbetrieb optimiert, und die zusätzliche Indirektion ist für Benutzer unsichtbar.

Erkenntnisse

Auf tmux aufzubauen war die richtige Entscheidung, aber nicht ohne Herausforderungen:

Terminal-Encoding-Randfälle. Claude Codes Ausgabe enthält gelegentlich ANSI-Escape-Sequenzen, die unerwartet mit tmux' Terminal-Emulation interagieren. Wir pflegen eine Normalisierungsschicht, die die Ausgabe vor dem Streaming an das iPhone bereinigt.

tmux-Installation unter macOS. tmux ist unter macOS nicht vorinstalliert. Wir haben erwogen, es mitzuliefern, aber dagegen entschieden — Entwickler bevorzugen generell, ihre eigene tmux-Installation zu verwalten, und Bundling würde Versionskonflikte für Nutzer verursachen, die tmux bereits installiert haben.

Capture-Pane-Performance bei Skalierung. Bei vielen gleichzeitigen Sitzungen skaliert die CPU-Nutzung der Erfassungsschleife linear. Wir haben adaptive Erfassungsraten implementiert, die die Frequenz für Sitzungen ohne kürzliche Ausgabeänderungen reduzieren.

tmux ist Infrastruktur, die verschwindet, wenn sie gut funktioniert. Die meisten Tactic Remote Nutzer wissen nicht und kümmern sich nicht darum, dass tmux beteiligt ist — sie sehen eine zuverlässige Sitzung, die überlebt, was auch immer ihr Telefon oder Netzwerk macht. Das war das Ergebnis, das wir angestrebt haben.

Tactic Remote ausprobieren

Coding-Agenten vom Smartphone aus steuern

Verbinde dich mit Claude Code, Codex und anderen Agenten auf deinem Mac-, Windows- oder Linux-Rechner. Prüfe den Fortschritt und sende die nächste Anweisung vom iPhone oder iPad.