Zum Inhalt springen

Fernsteuerung und Mobil

Control Center ist eine Desktop-App, aber die Arbeit, die sie verfolgt, hört nicht auf, wenn du vom Schreibtisch weggehst. Die Fernsteuerung koppelt dein Telefon mit deinem cc_server über Remote, die Begleit-App auf remote.usectrl.dev. Von dort folgst du der Flotte: Nachrichten und Tickets lesen, einem Agenten antworten, deinen Newsfeed triagieren. Audio, Transkript, Quellcode und Zugangsdaten, die auf dem Server liegen, verlassen ihn dabei nie.

Stell sie dir als Begleiter vor, der vor allem liest, neben der Arbeitsfläche. Den vollständigen Desktop-Client soll sie nicht ersetzen.

Das Telefon erreicht cc_server über eine WebSocket-Verbindung: entweder direkt (Loopback, LAN, Tailnet oder wss://) oder über einen einladungsgeschützten Raum auf einem Signalisierungs-Broker, der versiegelte Frames weiterleitet. Einen Peer-to-Peer-Datenkanal gibt es nicht.

Das gekoppelte Telefon erreicht einen kleinen, absichtlich engen Ausschnitt der Serveroberfläche:

  • Lesen: Tickets, Agenten, Bereiche und ihre Nachrichten, und deinen Newsfeed
  • Antworten: eine Nachricht in einem Bereich senden, ein Ticket aktualisieren oder zuweisen, einen Artikel als gelesen oder gespeichert markieren
  • Ein Playbook ausführen: eine gespeicherte Planvorlage mit ihren Parametern instanziieren. Das schlägt nur einen Plan vor; nichts läuft und nichts wird ausgegeben, bis jemand ihn in Plan-Studio auf einem vollständigen Client freigibt
  • Arbeitsbereiche wechseln, über die eigene Auswahl auf dem Telefon

Mehr ist es kaum. Ein Telefon ist ein Prinzipal mit geringeren Rechten als ein vollständiger Client. Es kann keine Prozesse starten, kein LLM-Budget ausgeben, nichts zu GitHub schieben und keine Arbeitsbereiche anlegen. Wie das durchgesetzt wird, steht im Zugriffsmodell.

Die Verbindung läuft über ein vermitteltes Relay: Der Server betritt als Eigentümer einen einladungsgeschützten Raum auf einem wss://-Broker, und jeder gekoppelte Client — Desktop, Web, Telefon — betritt denselben Raum mit einem befristeten Einlass-Token. Drei Teile greifen ineinander:

Teil Aufgabe
Remote (Telefon-App) Die Begleit-Web-App, standardmäßig auf remote.usectrl.dev gehostet oder selbst gehostet. Sie lädt im Browser und hält den Kopplungsdatensatz in IndexedDB.
Relay-Broker Ein zustandsloses wss://-Relay (cc_signaling_server) für Räume mit N Teilnehmern. Es trägt nur opake Frames: Jeder Payload ist Ende-zu-Ende zwischen Telefon und Server versiegelt, der Broker sieht deshalb nie App-Daten oder das Kopplungsgeheimnis und deutet nie, was er weiterleitet.
cc_server Eigentümer des Raums. Er beantwortet die Aufrufe des Telefons über denselben Dispatcher, den jeder andere Client nutzt.

Ein Kopplungsangebot trägt einen Verbindungsdeskriptor, der jeden Weg zum Server aufführt (LAN, Tailnet, öffentliches wss://, Relay) plus den Identitäts-Fingerabdruck. Der Resolver des Telefons wählt den besten erreichbaren Weg und legt den Fingerabdruck beim ersten Verbinden fest (TOFU). Das Relay sichert die Erreichbarkeit auch dann, wenn kein direkter Weg existiert, und kann den Verkehr nie lesen.

Die Kopplung wird in der App ausgestellt und als Deep Link ausgeliefert. Den Ablauf beschreibt Ein Gerät koppeln. Hier zählt der Aufbau.

https://<pwa-host>/#<payload>

Der Payload liegt im URL-Fragment, dem Teil nach #, den Browser nie an den Server schicken. Der HTTPS-Host der PWA sieht ihn deshalb nie. Er trägt alles, was das Telefon braucht, um den Server zu erreichen und nachzuweisen, wer es ist: den Verbindungsdeskriptor (jeder Weg plus der Identitäts-Fingerabdruck), eine frisch ausgestellte Geräte-ID, einen vorab geteilten Schlüssel von 32 Byte und einen Ablaufstempel. Das Telefon dekodiert ihn, speichert einen Kopplungsdatensatz lokal und entfernt das Fragment, sodass das Geheimnis aus der URL verschwindet.

Es gibt zwei Payload-Formen, und sie sind nicht austauschbar. Der Telefon-QR aus dem Kopplungsbereich in der App ist der v2-PairingPayload oben und zeigt auf den Host der Remote-PWA. cc_server pair --client-url gibt einen anderen, älteren v1-Link aus ({s, i, k} — Server-URL, Geräte-ID, Schlüssel), nur für den Web-Client.

Sie unterscheiden sich auch in der Lebensdauer, und das vertauscht man leicht:

Ausgestellt von Gültigkeit der Zugangsdaten
Kopplungsbereich in der App (pairing.mint) immer 30 Tage
cc_server pair auf der Kommandozeile Keine — die Zugangsdaten laufen nicht ab

Ein gekoppeltes Gerät ist authentifiziert, aber nicht vertrauenswürdig. Mehrere unabhängige Schranken halten eine freigegebene (oder durchgesickerte) Kopplung davon ab, zur vollen Kontrolle über den Server zu werden.

1. Die Mitgliedschaft ist die Grenze, nicht die Kopplung

Abschnitt betitelt „1. Die Mitgliedschaft ist die Grenze, nicht die Kopplung“

Ein gültiger Kopplungsschlüssel beweist, welches Gerät du bist. Was du lesen oder ändern darfst, entscheidet deine Rolle im Arbeitsbereich, bei jedem einzelnen Aufruf neu aufgelöst, und bei allem, was Repo-Inhalt zeigt, die Freigaben pro Repo. Ein Gerät mit einem völlig gültigen Schlüssel, das einer Person gehört, die kein Mitglied des genannten Arbeitsbereichs ist, wird mit „Not a member of this workspace“ abgelehnt.

Die Mindestrolle leitet sich aus der Art der Operation ab, sofern die Operation keine eigene festlegt: Lesen braucht guest, Änderungen brauchen member, zerstörende Operationen brauchen admin.

Über die Rollenprüfung hinaus trägt eine Telefon-Sitzung geringere Fähigkeiten als eine Desktop- oder Web-Sitzung. Operationen, die nur für den vollständigen Client deklariert sind, werden für ein Telefon abgelehnt, bevor der Handler läuft, unabhängig davon, wie viele Rechte die Person dahinter hat: Kopplungen von Geräten ausstellen, auflisten, umbenennen und widerrufen; Tunnel-Konnektivität lesen und setzen; Server-Sicherung sowie Export und Import eines Arbeitsbereichs; Prozesse erkennen und beenden; Adapter-Sonden; Server-Einstellungen; SSO-Verwaltung; Steuerung der Flotte; und einen laufenden Agenten übernehmen oder zurückgeben.

3. Eine Allow-List für Tools, die standardmäßig ablehnt

Abschnitt betitelt „3. Eine Allow-List für Tools, die standardmäßig ablehnt“

Für die MCP-Tool-Oberfläche (tools/call) gilt eine Allow-List, die standardmäßig ablehnt. Sie legt fest, welche Tools das Telefon aufrufen darf. Was nicht auf der Liste steht, wird abgelehnt, bevor es läuft. Die Liste ist überwiegend Lesen und Beobachten, plus eine Handvoll rein lokaler Schreibvorgänge — eine Nachricht, eine Ticket-Aktualisierung, eine Artikelmarkierung —, die kein LLM-Budget ausgeben, keinen Prozess starten und kein externes System berühren.

Abgelehnt wird zum Beispiel: einen Agenten befragen, eine KI-Review starten, einen Agenten beenden, eine Review auf GitHub veröffentlichen, Agenten einstellen oder entlassen, einen Arbeitsbereich anlegen.

Der Server hält keinen „aktuellen Arbeitsbereich“. Er ist absichtlich zustandslos: Jeder Aufruf mit Arbeitsbereich muss in seinen Argumenten die Ziel-workspace_id nennen, und der Dispatcher lehnt den Aufruf sofort ab, wenn sie fehlt oder einen Arbeitsbereich nennt, den der Server nicht registriert hat — bevor irgendetwas eine Datenbank öffnet. Ein Telefon kann deshalb den Geltungsbereich eines anderen Clients nie erben und auch nicht hineingeraten. Einen fremden Arbeitsbereich zu nennen hilft ebenfalls nicht, weil die Mitgliedschaftsprüfung aus Schranke 1 weiter gilt. Das ist dieselbe Invariante der Arbeitsbereichs-Isolation, die der Rest des Produkts durchsetzt.

5. Ende-zu-Ende versiegelte Frames mit dem vorab geteilten Schlüssel

Abschnitt betitelt „5. Ende-zu-Ende versiegelte Frames mit dem vorab geteilten Schlüssel“

Jeder Frame zwischen Telefon und Server ist mit dem Kopplungsschlüssel versiegelt. Das Einlass-Token lässt einen Client nur in den Raum, es entschlüsselt nichts. Der Broker leitet Chiffretext weiter und sieht den Schlüssel nie. Ein widerrufenes Gerät findet seine Zugangsdaten schon weg, deshalb fällt es beim erneuten Verbinden geschlossen aus.

In der App ausgestellte Zugangsdaten sind auf 30 Tage befristet. Danach lehnt das Verbindungs-Gate sie ab, und das Telefon muss neu gekoppelt werden. Der Widerruf wirkt sofort: Der Server beobachtet die Gerätetabelle und beendet die offenen Sitzungen eines widerrufenen Geräts innerhalb von Sekunden, statt auf die nächste Verbindung zu warten.

Ein Begrenzer mit gleitendem Fenster deckelt den entfernten Tool-Verkehr auf 120 Aufrufe pro Minute, mit einer engeren Teilgrenze von 30 pro Minute für die verändernden Verben. Das Kontingent gehört dem Prinzipal, nicht der Sitzung: Drei deiner Geräte zehren von einem Kontingent. Ein gekaperter Client verschafft sich keinen Spielraum, indem er weitere Sitzungen öffnet, und ein lautes Mitglied kann den anderen das Kontingent nicht wegnehmen.

Der Relay-Broker ist absichtlich dumm: Er stellt Räume bereit, leitet versiegelte Frames weiter und hält keine Konten, keine App-Daten und keine Schlüssel. Räume sind einladungsgeschützt und flüchtig. App-Daten, Audio, Transkript, Quellcode und Zugangsdaten bleiben auf dem Server.

Nach der Kopplung erhält das Telefon Live-Aktualisierungen als Benachrichtigungs-Frames — neue Agentennachrichten, dir zugewiesene Tickets, Statusänderungen — analog zu den Benachrichtigungen des Desktops. Der Server sendet diese Frames an jede verbundene Sitzung, und der Filter auf den Arbeitsbereich greift auf dem Client. Was du siehst, gilt für den Arbeitsbereich, den du gerade ansiehst.

Oberfläche Was sie zeigt
Einstellungen → Du → Deine Geräte (/workspaces/:workspaceId/settings/you/devices) Gekoppelte Clients mit Live-Status, dazu Neuen Client koppeln (Webbrowser, Desktop-App oder Telefon) und Widerrufen

Derselbe Bereich stellt Kopplungen auch für einen zweiten Browser oder eine Desktop-App aus, nicht nur für Telefone. Der Ablauf ist derselbe, nur der Deep Link unterscheidet sich.