HTTP-API-Referenz

Der ccmux-Daemon stellt einen HTTP und einen JSON API zum Auflisten von Sitzungen, zum Lesen von Projektdaten und zum Erstellen von Remote-Clients bereit. Diese Referenz behandelt den Verbindungsaufbau, das Vertrauensmodell, Endpunkte und Antworttypen.

Die Routen und Typen werden im verwaltet ccmux source. Ältere Daemon-Versionen unterstützen möglicherweise nicht jeden hier dokumentierten Endpunkt. Überprüfen Sie den Integritätsendpunkt auf die laufende Version.

Transport & Erreichbarkeit

Dieselben Routen werden über zwei Transporte bedient:

Transport Adresse Standard
Lokaler Unix-Socket ~/.local/state/ccmux/ccmuxd.sock (Modus 0600) immer an
Tailnet HTTP http://TAILNET-IPv4:PORT (Port-Standardeinstellung 7474) aus

Um einen Daemon von einem anderen Gerät aus zu erreichen, auf dem -Daemon Host: eingestellt daemon.listen_tailnet = true (optional daemon.tailnet_port) in ~/.config/ccmux/config.toml und starten Sie ccmuxd neu. Die Bindungsadresse ist die des Hosts tailscale ip -4. Wenn Tailscale nicht ausgeführt wird, startet der Tailnet-Listener nicht stillschweigend (nur der Unix-Socket wird bedient).

Authentifizierungs- und Vertrauensmodell – lesen Sie dies zuerst

Auf dem HTTP API gibt es keine Authentifizierung auf Anwendungsebene. Kein Bearer-Token, kein API-Schlüssel, keine Signatur pro Anfrage, keine IP-Zulassungsliste. Die Vertrauensgrenze ist Ihr Tailscale-Tailnet: jeder Host, der den Daemon erreichen kann 100.x.x.x:7474 kann jeden Endpunkt aufrufen – Schlüssel auflisten / erstellen / töten / umbenennen / senden, an ein vollständig interaktives Terminal anschließenund Notizen/Konversationen/Nutzung lesen.

Sichern Sie dies mit Tailscale ACLs, keine Authentifizierung auf App-Ebene. Behandeln Sie alles, was zur Tailnet-IP des Daemons weitergeleitet werden kann, als vollständig vertrauenswürdig.

Zwei Endpunkte validieren pro Anfrage und nur zum Bootstrap-Gerätevertrauen + Push – nicht zum Schutz des API:

Fehlerform

Fehler sind Klartext (text/plain): eine einzeilige Nachricht, nicht ein JSON-Umschlag. Überprüfen Sie die Statuscodeund lesen Sie den Text als Zeichenfolge für die menschliche Nachricht. Erfolgreiche JSON-Antworten sind application/json.

Code Bedeutung
200 OK (JSON-Körper)
204 OK, kein Text (Kill / Send-Keys / Geräteregister)
400 Falsche Eingabe/Validierungsfehler
401 ungültiges oder abgelaufenes Pairing-Token (/v1/pair nur)
404 nicht gefunden – oder dieser Daemon ist älter als der Endpunkt
405 falsche HTTP-Methode
500 Server / tmux / Gerüstfehler
503 Funktion nicht verfügbar (z. B. /v1/pair-token mit listen_tailnet aus)

Der API entwickelt sich weiter Hinzufügen JSON-Felder (alle optionalen Felder verwenden omitempty) und Hinzufügen Routen. Behandle a 404 auf einem gesamten Endpunkt als „Dieser Daemon ist älter als diese Funktion“ und wird ordnungsgemäß heruntergefahren.

Endpunktzusammenfassung

Methode Pfad Antwort
GET /v1/health HealthInfo
GET /v1/peers []PeerInfo
GET /v1/sessions []SessionState
POST /v1/sessions SessionState (erstellen oder anhängen)
POST /v1/sessions/bare NewBareSessionResponse
POST /v1/sessions/NAME/kill 204
POST /v1/sessions/NAME/rename SessionState
POST /v1/sessions/NAME/send-keys 204
GET /v1/sessions/NAME/preview PreviewResponse
GET /v1/sessions/NAME/attach WebSocket (interaktives PTY)
GET /v1/projects []ProjectInfo
POST /v1/projects NewProjectResponse
GET /v1/conversations []Conversation
GET /v1/usage?window=… AgentUsage
GET /v1/notes?project=…[&file=…] []NoteEntry oder NoteContent
GET /v1/notes/search?project=…&q=… []SearchHit
GET /v1/events SSE-Stream von SessionEvent
POST /v1/pair-token (nur Unix) PairTokenResponse
POST /v1/pair PairResponse
POST /v1/devices 204
POST /v1/devices/test 204

(Wo ein Pfad angezeigt wird NAME ist das Sitzungsnamenpfadsegment tmux, d. h. /v1/sessions/{name}/kill.)

Endpunktdetails

Sitzungen

Interaktives Terminal – GET /v1/sessions/NAME/attach (WebSocket)

Upgrade auf einen WebSocket mit Bridge zu einem echten tmux attach-session in einem PTY: ein echtes interaktives Terminal (Live-Ausgabe, Eingabe, Größenänderung) ohne ssh/mosh. Verwendungsmöglichkeiten coder/websocket Rahmen.

Die anfängliche PTY-Größe beträgt 80x24 bis zur ersten Größenänderung. Der Server pingt alle 25 Sekunden mit einer Frist von 10 Sekunden – antworten Sie auf Pongs oder rechnen Sie mit einem Teardown. InsecureSkipVerify ist gesetzt (Nr Origin prüfen). Nur die Steckdose schließen wird getrennt; Die tmux-Sitzung läuft weiter. Dies ist dem Polling vorzuziehen /preview für eine interaktive Ansicht.

Projekte

Gespräche, Verwendung, Notizen

Live-Updates – GET /v1/events (SSE)

text/event-stream. Jeder data: Frame ist ein JSON SessionEvent; kind ist created / killed / state_change / needs_input. Herzschläge: : connected beim Öffnen, : ping alle 20 Sekunden (Kommentarzeilen beginnen mit : sind ignorierbar). Ein event: drops / data: N -Frame bedeutet, dass Sie N Ereignisse verpasst haben und einen erneuten Abruf durchführen sollten /v1/sessions zur Neusynchronisierung.

Gesundheit und Entdeckung

Pairing & Push (mobil)

Optionaler Ablauf für natives Push (APNs/iOS, FCM/Android) und Installation eines SSH-Schlüssels, damit das Gerät dies kann ssh/mosh anhängen. Nicht ist erforderlich, um die Lese-/Aktionsendpunkte über das Tailnet zu verwenden.

Löst zwei Übergänge aus: eine Sitzung beginnt needs_input, und active → idle („Agent beendet“). Die Sitzungs-ID des Pushs lautet local/SESSIONNAME. APNs und FCM sind standardmäßig deaktiviert und serverseitige Konfiguration erforderlich; FCM-Routing ist vorhanden, aber die Android-Bereitstellung ist noch nicht verkabelt.

Typen

Kopiert von internal/daemon/protocol.go (Go-Strukturen mit ihren JSON-Tags).

type SessionState struct {
	Name        string    `json:"name"`
	Host        string    `json:"host"`         // "local" or a remote host name
	Project     string    `json:"project"`
	Path        string    `json:"path"`         // session working directory
	State       string    `json:"state"`        // active|idle|needs_input|error|unknown
	Attached    bool      `json:"attached"`
	Windows     int       `json:"windows"`
	Created     time.Time `json:"created"`
	LastChange  time.Time `json:"last_change"`
	PromptCount int       `json:"prompt_count"`
	Agent       string    `json:"agent,omitempty"`
}

type HealthInfo struct {
	OK        bool   `json:"ok"`
	Hostname  string `json:"hostname"`
	Version   string `json:"version"`
	Sessions  int    `json:"sessions"`
	SleepMode string `json:"sleep_mode"` // off|safe|dangerous|very_dangerous
}

type SessionEvent struct {
	At      time.Time    `json:"at"`
	Kind    string       `json:"kind"` // state_change|created|killed|needs_input
	Session SessionState `json:"session"`
}

type NewSessionRequest struct {
	Project  string `json:"project"`
	Path     string `json:"path"`     // defaults to PROJECTS_ROOT/PROJECT
	Continue bool   `json:"continue"` // start the agent with --continue
	Name     string `json:"name,omitempty"`
	Agent    string `json:"agent,omitempty"`
}

type NewBareSessionRequest struct {
	Name  string `json:"name,omitempty"`
	Path  string `json:"path,omitempty"`
	Agent string `json:"agent,omitempty"`
}
type NewBareSessionResponse struct {
	Session string `json:"session"`
	Path    string `json:"path"`
	Host    string `json:"host"`
}

type NewProjectRequest struct {
	Name  string `json:"name"`
	Agent string `json:"agent,omitempty"`
}
type NewProjectResponse struct {
	Session string `json:"session"`
	Path    string `json:"path"`
	Host    string `json:"host"`
}

type ProjectInfo struct {
	Name      string    `json:"name"`
	Host      string    `json:"host"`
	Path      string    `json:"path"` // absolute on the daemon host
	HasGit    bool      `json:"has_git"`
	HasCM     bool      `json:"has_cm"`
	HasAgents bool      `json:"has_agents,omitempty"`
	HasDocs   bool      `json:"has_docs"`
	Agent     string    `json:"agent,omitempty"`
	Modified  time.Time `json:"modified"`
}

type PeerInfo struct {
	Hostname   string `json:"hostname"`
	Addr       string `json:"addr"` // tailnet IPv4
	OS         string `json:"os"`
	Online     bool   `json:"online"`
	RunsCCMuxd bool   `json:"runs_ccmuxd"`
	Port       *int   `json:"port,omitempty"`
}

type Conversation struct {
	ID       string    `json:"id"` // agent UUID (its --resume id)
	Agent    string    `json:"agent"`
	Project  string    `json:"project,omitempty"`
	Path     string    `json:"path,omitempty"`
	Preview  string    `json:"preview,omitempty"`
	Modified time.Time `json:"modified"`
}

type AgentUsage struct {
	Claude      UsageSummary `json:"claude"`
	Codex       UsageSummary `json:"codex"`
	Antigravity UsageSummary `json:"antigravity"`
}
type UsageSummary struct {
	HasData       bool    `json:"has_data"`
	WindowSeconds int     `json:"window_seconds"`
	Prompts       int     `json:"prompts"`
	InputTokens   int     `json:"input_tokens"`
	OutputTokens  int     `json:"output_tokens"`
	EstimatedCost float64 `json:"estimated_cost"` // USD
}

type NoteEntry struct {
	Rel      string    `json:"rel"`
	Dir      string    `json:"dir"`
	Display  string    `json:"display"`
	Modified time.Time `json:"modified"`
}
type NoteContent struct {
	Rel     string `json:"rel"`
	Content string `json:"content"`
}
type SearchHit struct {
	Rel     string `json:"rel"`
	LineNum int    `json:"line_num"`
	Snippet string `json:"snippet"`
}

type PreviewResponse struct {
	Lines   int    `json:"lines"`
	Content string `json:"content"`
}

type RenameRequest   struct{ Name string `json:"name"` }
type SendKeysRequest struct{ Keys string `json:"keys"` }

type PairRequest struct {
	Token       string `json:"token"`
	PublicKey   string `json:"public_key"`
	DeviceToken string `json:"device_token,omitempty"`
	APNsEnv     string `json:"apns_env,omitempty"` // development|production
}
type PairResponse      struct{ Hostname string `json:"hostname"`; Version string `json:"version"` }
type PairTokenResponse struct{ Token string `json:"token"`; URL string `json:"url"` }
type RegisterDeviceRequest struct {
	Token     string `json:"token"`
	Env       string `json:"env,omitempty"` // apns: development|production; fcm: empty
	PublicKey string `json:"public_key"`
	Provider  string `json:"provider,omitempty"` // apns (default) | fcm
}
// POST /v1/devices/test body is { "public_key": "..." }

Validierungsregeln zur clientseitigen Spiegelung

Beispiele

# Health (over the tailnet)
curl -s http://100.75.64.20:7474/v1/health | jq

# List sessions
curl -s http://100.75.64.20:7474/v1/sessions | jq

# Type a reply into a session and press Enter
curl -s -X POST http://100.75.64.20:7474/v1/sessions/c-auth/send-keys \
  -H 'content-type: application/json' \
  -d '{"keys":"yes, ship it\n"}'

# Peek at the last 40 lines of a pane
curl -s 'http://100.75.64.20:7474/v1/sessions/c-auth/preview?lines=40' | jq -r .content

# Subscribe to live events
curl -sN http://100.75.64.20:7474/v1/events

Der Go-Referenzclient in internal/daemon/client.go ist der kanonische Verbraucher und eine nützliche Zuordnung von Methode → Endpunkt.

Hilf mit, ccmux zu verbessern

Fehler gefunden, eine Anleitung unklar oder eine Übersetzung verbesserungswürdig? Auch kleine Beiträge sind willkommen. Erstelle ein Issue oder einen Pull Request.


Haben Sie einen Fehler entdeckt oder ist etwas veraltet? Bearbeiten Sie diese Seite auf GitHub.