HTTP API 参考

ccmux 守护进程提供 HTTP 和 JSON API,可用于列出会话、读取项目数据和构建远程客户端。本参考文档介绍连接设置、信任模型、端点和响应类型。

路由和类型定义维护在 ccmux 源码中。旧版守护进程可能不支持此处列出的所有端点;请通过健康检查端点查看运行版本。

传输方式与可达性

同一组路由通过两种传输方式提供:

传输方式 地址 默认值
本地 Unix 套接字 ~/.local/state/ccmux/ccmuxd.sock (权限模式为 0600) 始终开启
Tailnet HTTP http://TAILNET-IPv4:PORT (默认端口 7474) 关闭

若要从其他设备访问守护进程,请在 守护进程 所在主机设置 daemon.listen_tailnet = true (可选设置 daemon.tailnet_port),配置文件为 ~/.config/ccmux/config.toml ,然后重启 ccmuxd。绑定地址为主机的 tailscale ip -4。如果 Tailscale 未运行,则不会启动 tailnet 监听器(仅提供 Unix 套接字服务)。

身份验证与信任模型——请先阅读

HTTP API 没有应用层身份验证。 没有 Bearer 令牌、API 密钥、请求签名或 IP 白名单。信任边界是 你的 Tailscale tailnet:任何能够访问守护进程 100.x.x.x:7474 的主机都能调用所有接口——列出、创建、终止、重命名、发送按键, 连接完整的交互式终端,以及读取笔记、对话和用量。

请通过 Tailscale ACL保护访问权限,而非应用层身份验证。将任何能路由到守护进程 tailnet IP 的设备视为完全受信任的设备。

只有两个接口会逐请求验证,其用途是建立设备信任和推送服务,而非保护整个 API:

错误格式

错误采用 纯文本 (text/plain):单行消息, 不是 JSON 对象。请检查 状态码,并将响应正文作为可读的错误字符串。成功的 JSON 响应使用 application/json.

状态码 含义
200 成功(JSON 正文)
204 成功,无正文(终止会话 / 发送按键 / 注册设备)
400 输入错误或验证失败
401 配对令牌无效或已过期(仅限/v1/pair
404 未找到—— 也可能是守护进程版本尚不支持该接口
405 HTTP 方法错误
500 服务器 / tmux / 项目模板出错
503 功能不可用(例如 /v1/pair-tokenlisten_tailnet 关闭时)

API 通过 新增 JSON 字段(所有可选字段使用 omitempty)和 新增 路由来演进。如果整个接口返回 404 ,应视为“此守护进程版本不支持该功能”,并妥善降级。

接口概览

方法 路径 响应
GET /v1/health HealthInfo
GET /v1/peers []PeerInfo
GET /v1/sessions []SessionState
POST /v1/sessions SessionState (创建或连接)
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)
GET /v1/projects []ProjectInfo
POST /v1/projects NewProjectResponse
GET /v1/conversations []Conversation
GET /v1/usage?window=… AgentUsage
GET /v1/notes?project=…[&file=…] []NoteEntryNoteContent
GET /v1/notes/search?project=…&q=… []SearchHit
GET /v1/events SSE 事件流,类型为 SessionEvent
POST /v1/pair-token (仅 Unix) PairTokenResponse
POST /v1/pair PairResponse
POST /v1/devices 204
POST /v1/devices/test 204

(路径中的 NAME 指 tmux 会话名称这一段,即 /v1/sessions/{name}/kill.)

接口详情

会话

交互式终端—— GET /v1/sessions/NAME/attach (WebSocket)

升级为 WebSocket,通过 PTY 桥接到真实的 tmux attach-session ,提供真正的交互式终端(实时输出、输入、调整尺寸), 无需 ssh/mosh。使用 coder/websocket 帧格式。

初始 PTY 尺寸为 80x24 ,直到首次调整尺寸。服务器每 25 秒发送一次 ping,超时为 10 秒;请回应 pong,否则连接会断开。 InsecureSkipVerify 已设置(不检查 Origin )。关闭套接字只会 断开终端连接;tmux 会话继续运行。交互式界面应优先使用此接口,而非轮询 /preview

项目

对话、用量、笔记

实时更新—— GET /v1/events (SSE)

text/event-stream。每个 data: 帧均为 JSON 格式的 SessionEvent; kind 仅限 created / killed / state_change / needs_input。心跳: : connected 在连接时发送, : ping 每 20 秒发送一次(以 : 开头的注释行可忽略)。收到 event: drops / data: N 帧表示遗漏了 N 个事件,应重新获取 /v1/sessions 以恢复同步。

健康检查与发现

配对与推送(移动端)

可选流程,用于原生推送(APNs/iOS、FCM/Android)和安装 SSH 密钥,以便设备使用 ssh/mosh 连接终端。 无需 配对即可通过 tailnet 使用读取和操作接口。

推送在两种状态变化时触发:会话进入 needs_input,以及 active → idle (“代理已完成”)。推送中的会话 ID 为 local/SESSIONNAME。APNs 和 FCM 默认关闭 ,需要服务器端配置;FCM 路由已实现,但 Android 投递尚未接通。

类型

摘自 internal/daemon/protocol.go (Go 结构体及其 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": "..." }

客户端应同步遵循的验证规则

示例

# 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

Go 参考客户端位于 internal/daemon/client.go ,是标准调用实现,也可作为方法与接口的对应表。

一起改进 ccmux

发现了问题、说明不够清楚,或者翻译可以更自然?欢迎任何大小的贡献。你可以报告问题,或提交拉取请求。


发现错误或过时内容? 在 GitHub 上编辑此页.