Referência da API HTTP

O daemon ccmux expõe um HTTP e JSON API para listar sessões, ler dados de projetos e construir clientes remotos. Esta referência abrange a configuração da conexão, o modelo de confiança, os terminais e os tipos de resposta.

As rotas e tipos são mantidos no ccmux source. Versões mais antigas do daemon podem não suportar todos os endpoints documentados aqui; verifique o endpoint de integridade da versão em execução.

Transporte e acessibilidade

As mesmas rotas são servidas em dois transportes:

Transporte Endereço Padrão
Soquete Unix local ~/.local/state/ccmux/ccmuxd.sock (modo 0600) sempre ativado
tailnet HTTP http://TAILNET-IPv4:PORT (porta padrão 7474) desativado

Para acessar um daemon de outro dispositivo, no daemon host: definido daemon.listen_tailnet = true (opcionalmente daemon.tailnet_port) em ~/.config/ccmux/config.toml e reinicie ccmuxd. O endereço de ligação é o do host tailscale ip -4. Se Tailscale não estiver em execução, o ouvinte tailnet não será iniciado silenciosamente (apenas o soquete Unix será servido).

Modelo de autenticação e confiança — leia isto primeiro

Não há autenticação em nível de aplicativo no HTTP API. Nenhum token de portador, nenhuma chave API, nenhuma assinatura por solicitação, nenhuma lista de permissões de IP. O limite de confiança é sua tailnet Tailscale: qualquer host que possa alcançar o daemon 100.x.x.x:7474 pode chamar todos os endpoints – listar/criar/matar/renomear/enviar-chaves, anexado a um terminal interativo completoe leia notas/conversas/uso.

Proteja isso com ACLs Tailscale, não autenticação em nível de aplicativo. Trate qualquer coisa que possa ser roteada para o IP da tailnet do daemon como totalmente confiável.

Dois endpoints são validados por solicitação e apenas para inicializar a confiança do dispositivo + push — não para proteger o API:

Formato do erro

Os erros são texto simples (text/plain): uma mensagem de linha única, não um envelope JSON. Verifique o código de statuse leia o corpo como uma string para a mensagem humana. As respostas JSON bem-sucedidas são application/json.

Código Significado
200 OK (corpo JSON)
204 OK, sem corpo (kill / send-keys / registro de dispositivo)
400 falha de entrada/validação incorreta
401 token de emparelhamento inválido ou expirado (/v1/pair apenas)
404 não encontrado — ou este daemon é anterior ao endpoint
405 método HTTP errado
500 servidor / tmux / falha no andaime
503 recurso indisponível (por ex. /v1/pair-token com listen_tailnet desativado)

O API evolui em adicionando Campos JSON (todos os campos opcionais usam omitempty) e adicionando rotas. Trate um 404 em um endpoint inteiro como “este daemon é mais antigo que esse recurso” e degrada normalmente.

Resumo de endpoint

Método Caminho Resposta
GET /v1/health HealthInfo
GET /v1/peers []PeerInfo
GET /v1/sessions []SessionState
POST /v1/sessions SessionState (criar ou anexar)
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 (PTY interativo)
GET /v1/projects []ProjectInfo
POST /v1/projects NewProjectResponse
GET /v1/conversations []Conversation
GET /v1/usage?window=… AgentUsage
GET /v1/notes?project=…[&file=…] []NoteEntry ou NoteContent
GET /v1/notes/search?project=…&q=… []SearchHit
GET /v1/events Fluxo SSE de SessionEvent
POST /v1/pair-token (somente Unix) PairTokenResponse
POST /v1/pair PairResponse
POST /v1/devices 204
POST /v1/devices/test 204

(Onde um caminho mostra NAME é o segmento do caminho do nome da sessão tmux, ou seja, /v1/sessions/{name}/kill.)

Detalhes do terminal

Sessões

Terminal interativo — GET /v1/sessions/NAME/attach (WebSocket)

Atualização para um WebSocket interligado a um real tmux attach-session em um PTY: um verdadeiro terminal interativo (saída ao vivo, entrada, redimensionamento) sem ssh/mosh. Usos coder/websocket enquadramento.

O tamanho inicial do PTY é 80x24 até o primeiro redimensionamento. O servidor faz ping a cada 25 segundos com um prazo de 10 segundos – responda aos pongs ou espere uma desmontagem. InsecureSkipVerify está definido (sem Origin verificação). Fechando apenas o soquete desconecta; a sessão tmux continua em execução. Prefira isso a pesquisas /preview para uma visualização interativa.

Projetos

Conversas, uso, notas

Atualizações ao vivo — GET /v1/events (SSE)

text/event-stream. Cada data: quadro é um JSON SessionEvent; kind é created / killed / state_change / needs_input. Batimentos cardíacos: : connected aberto, : ping a cada 20 segundos (linhas de comentários começando com : são ignoráveis). Um event: drops / data: N frame significa que você perdeu N eventos e deve buscar novamente /v1/sessions para ressincronizar.

Saúde e descoberta

Emparelhamento e push (móvel)

Fluxo opcional para push nativo (APNs/iOS, FCM/Android) e instalação de uma chave SSH para que o dispositivo possa ssh/mosh anexar. Não necessário para usar os endpoints de leitura/ação na tailnet.

Aciona duas transições: uma sessão entrando needs_inpute active → idle (“agente finalizado”). O ID da sessão do push é local/SESSIONNAME. APNs e FCM são desativado por padrão e precisa de configuração do lado do servidor; O roteamento FCM existe, mas a entrega do Android ainda não está configurada.

Tipos

Copiado de internal/daemon/protocol.go (estruturas Go com suas tags JSON).

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": "..." }

Regras de validação para espelhar o lado do cliente

Exemplos

# 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

O cliente de referência Go em internal/daemon/client.go é o consumidor canônico e um mapa útil do método → endpoint.

Ajude a melhorar o ccmux

Encontrou um bug, uma explicação confusa ou uma tradução que pode melhorar? Toda contribuição é bem-vinda. Abra uma issue ou envie um pull request.


Detectou um erro ou algo desatualizado? Edite esta página em GitHub.