HTTP API リファレンス
ccmux デーモンは、セッションの一覧表示、プロジェクト データの読み取り、リモート クライアントの構築のために HTTP および JSON API を公開します。このリファレンスでは、接続セットアップ、信頼モデル、エンドポイント、および応答タイプについて説明します。
ルートとタイプは ccmux source。古いデーモン バージョンでは、ここに記載されているすべてのエンドポイントがサポートされていない可能性があります。実行中のバージョンの正常性エンドポイントを確認してください。
輸送と到達可能性
同じルートが 2 つのトランスポートで提供されます。
| トランスポート | アドレス | デフォルト |
|---|---|---|
| ローカル 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 ソケットのみが提供されます)。
- すべてのパスは以下にあります
/v1/。ありません/v2. - リクエスト/レスポンスボディは
application/json— を除く/v1/events(text/event-stream) とエンドポイントの接続 (WebSocket アップグレード)。 - TLS がありません。 Tailscale の WireGuard トンネルは暗号化 + ID 境界です。 HTTP リスナーは、tailnet IP にバインドされたプレーン HTTP です。
- リクエストボディの上限は次のとおりです 64 KiB.
認証と信頼モデル — 最初にお読みください
HTTP API にはアプリケーションレベルの認証がありません。 ベアラー トークン、API キー、リクエストごとの署名、IP ホワイトリストがありません。信頼境界は Tailscale tailnet: デーモンにアクセスできる任意のホスト
100.x.x.x:7474 すべてのエンドポイントを呼び出すことができます - リスト/作成/強制終了/名前変更/キーの送信、 完全な対話型端末に接続します、メモ/会話/使用法を読みます。
これを保護します Tailscale ACL、アプリレベルの認証ではありません。デーモンのtailnet IP にルーティングできるものはすべて、完全に信頼できるものとして扱います。
リクエストごとに 2 つのエンドポイントが検証され、デバイスの信頼 + プッシュをブートストラップするためだけに検証されます。API を保護するためではありません。
POST /v1/pair有効な使い捨てペアリング トークンが必要です プラス 解析可能な SSH 公開キー。それを引き換えると、そのキーがホストの~/.ssh/authorized_keys.POST /v1/pair-tokenは Unix ソケットのみ (tailnet上には決してありません) 追加で返されます503ただし、listen_tailnetがオンになっています。
エラーの形状
エラーは次のとおりです プレーンテキスト (text/plain): 単一行メッセージ、 ではありません JSON エンベロープ。チェックしてください ステータスコード、本文を人間のメッセージの文字列として読み取ります。成功した JSON 応答は次のとおりです。 application/json.
| コード | 意味 |
|---|---|
200 |
OK (JSON 本体) |
204 |
OK、本文はありません (kill / send-keys / device register) |
400 |
不正な入力/検証エラー |
401 |
無効または期限切れのペアリング トークン (/v1/pair のみ) |
404 |
見つかりません — またはこのデーモンはエンドポイントよりも古いものです |
405 |
HTTP メソッドが間違っています |
500 |
サーバー / tmux / スキャフォールドの障害 |
503 |
機能は利用できません (例: /v1/pair-token 付き listen_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=…] |
[]NoteEntry または NoteContent |
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→[]SessionState。このデーモンが管理するすべてのセッション (デーモン由来のセッション)state(active/idle/needs_input/error/unknown).POST /v1/sessions(NewSessionRequest,project必須)→SessionState。プロジェクトにバインドされたエージェント セッションを作成またはアタッチします (tmux 名に対して冪等)。pathデフォルトはPROJECTS_ROOT/PROJECTデーモンホスト上で。POST /v1/sessions/bare(NewBareSessionRequest) →NewBareSessionResponse。シェルのみのセッション (プロジェクトやスキャフォールドなし)。POST /v1/sessions/NAME/kill→204。を発しますkilledSSE イベント。POST /v1/sessions/NAME/rename(RenameRequest) →SessionState.NAMEは現在の名前です。体は新しいものを運びます。POST /v1/sessions/NAME/send-keys(SendKeysRequest) →204。に渡されましたtmux send-keys(例: 返信を入力 +\n).GET /v1/sessions/NAME/preview?lines=N→PreviewResponse。アクティブ ペインの最後の N 行をプレーン テキスト (ANSI ストリップ) として表示します。Nは1..200、デフォルト24。アタッチソケットを開かずに軽量のピークを確認できます。
対話型端末 — GET /v1/sessions/NAME/attach (Webソケット)
実際の WebSocket にブリッジされた WebSocket にアップグレードします。 tmux attach-session PTY 内: 真の対話型ターミナル (ライブ出力、入力、サイズ変更) それなし SSH/モッシュ。用途 coder/websocket フレーム。
- クライアント → サーバー、バイナリ フレーム: 生の stdin バイト (キーストローク)。
- クライアント→サーバー、テキストフレーム: JSON
{"cols":N,"rows":N}サイズを変更します。 - サーバー → クライアント、バイナリ フレーム: 生の PTY 出力バイト。
初期 PTY サイズは 80x24 最初のサイズ変更まで。サーバーは 25 秒ごとに ping を送信し、期限は 10 秒です。ポンに応答するか、ティアダウンを期待します。
InsecureSkipVerify が設定されています(いいえ) Origin チェック)。ソケットのみを閉じる
が切り離されます; tmux セッションは実行を続けます。ポーリングよりもこれを優先します
/preview 対話型ビューの場合。
プロジェクト
GET /v1/projects→[]ProjectInfo。デーモンのプロジェクト ルートで発見されたプロジェクトは、ホスト名でタグ付けされています。POST /v1/projects(NewProjectRequest,name必須)→NewProjectResponse。新しいプロジェクトを作成します (ディレクトリのみ - いいえ)CLAUDE.md/git) を実行し、エージェント セッションを開始します。nameは、非表示ではない単一のパス セグメントである必要があります (/,\、先頭なし.).
会話、使用法、メモ
GET /v1/conversations→[]Conversation。過去のエージェントの記録、最新のものから順。idはエージェント自身の UUID (エージェント自体の UUID) です。--resumeID)。GET /v1/usage?window=DURATION→AgentUsage。エージェントごとのトークン + ローリング ウィンドウにわたるコスト (Go 期間など)2h,24h;デフォルト5h).GET /v1/notes?project=NAME→[]NoteEntry;と&file=REL→NoteContent.fileはプロジェクト関連である必要があります.mdパス、いいえ...GET /v1/notes/search?project=NAME&q=QUERY→[]SearchHit。 Ripgrep支援。 (古いデーモン404— 「検索不可」として扱います。)
ライブアップデート — 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 再同期します。
健康と発見
GET /v1/health→HealthInfo。生存性 + ID プローブ。GET /v1/peers→[]PeerInfo。すべてのtailnet ピア + それぞれが ccmuxd を実行しているかどうか (戻り値[]ではありません500、Tailscale が存在しない場合)。
ペアリングとプッシュ(モバイル)
ネイティブ プッシュ (APN/iOS、FCM/Android) と SSH キーのインストールのオプション フロー。 ssh/mosh 添付。 違います tailnet経由で読み取り/動作エンドポイントを使用する必要があります。
POST /v1/pair-token(Unix ソケットのみ) →PairTokenResponse。ワンタイム トークン (128 ビット 16 進数、使い捨て、5 分間 TTL) + を作成します。ccmux://pair?…ディープリンク。503場合listen_tailnetがオフになっています。POST /v1/pair(PairRequest) →PairResponse。トークンを引き換える: デバイスの SSH 公開キーをインストールし、必要に応じてプッシュ トークンをインラインで登録します。401トークンが無効または期限切れです。tailnetで到達可能。POST /v1/devices(RegisterDeviceRequest) →204。ペアリング済みのホスト上でプッシュ トークンを登録/更新します。 SSH で識別されるデバイスpublic_key(SHA-256 ハッシュとしてのみ保存されます)。providerはapns(デフォルト) またはfcm; APNのニーズenv=development/production、FCM は空である必要がありますenv.POST /v1/devices/test({"public_key":"…"}) →204。そのキーのデバイスへの検証プッシュ。
プッシュは 2 つの遷移で起動します: セッションの開始 needs_input、および
active → idle (「エージェントは終了しました」)。プッシュのセッションIDは
local/SESSIONNAME。 APN と FCM は、 デフォルトではオフ サーバー側の設定が必要です。 FCM ルーティングは存在しますが、Android 配信はまだ確立されていません。
タイプ
からコピーされました internal/daemon/protocol.go (JSON タグを持つ Go 構造体)。
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": "..." }
クライアント側をミラーリングするための検証ルール
- tmux session names には以下を含めてはなりません
/,\、または:. - プロジェクト名 (用
POST /v1/projects) は、非表示でない単一のパス セグメントである必要があります。 - ファイルパスをメモします はプロジェクト相対である必要があります。いいえ
..、で終わる.md. - リクエストボディの上限は次のとおりです。 64 KiB.
例
# 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 の改善にご協力ください
不具合、わかりにくい説明、不自然な翻訳を見つけましたか?小さな改善も歓迎します。Issue やプルリクエストでお知らせください。
エラーまたは古いものを見つけましたか? GitHub でこのページを編集します.