Gateway 協定(WebSocket)
Gateway WS 協定是 OpenClaw 的統一控制層 + 節點傳輸層。所有用戶端(CLI、Web UI、macOS app、iOS/Android 節點、無介面節點)都透過 WebSocket 連線,並在交握時宣告自己的角色和範圍。
傳輸
- WebSocket,文字訊框搭配 JSON payload。
- 第一個訊框必須是
connect請求。
交握(connect)
Gateway → 用戶端(連線前挑戰):
{
"type": "event",
"event": "connect.challenge",
"payload": { "nonce": "…", "ts": 1737264000000 }
}
用戶端 → Gateway:
{
"type": "req",
"id": "…",
"method": "connect",
"params": {
"minProtocol": 3,
"maxProtocol": 3,
"client": {
"id": "cli",
"version": "1.2.3",
"platform": "macos",
"mode": "operator"
},
"role": "operator",
"scopes": ["operator.read", "operator.write"],
"caps": [],
"commands": [],
"permissions": {},
"auth": { "token": "…" },
"locale": "en-US",
"userAgent": "openclaw-cli/1.2.3",
"device": {
"id": "device_fingerprint",
"publicKey": "…",
"signature": "…",
"signedAt": 1737264000000,
"nonce": "…"
}
}
}
Gateway → 用戶端:
{
"type": "res",
"id": "…",
"ok": true,
"payload": { "type": "hello-ok", "protocol": 3, "policy": { "tickIntervalMs": 15000 } }
}
當發行裝置 token 時,hello-ok 也會包含:
{
"auth": {
"deviceToken": "…",
"role": "operator",
"scopes": ["operator.read", "operator.write"]
}
}
節點範例
{
"type": "req",
"id": "…",
"method": "connect",
"params": {
"minProtocol": 3,
"maxProtocol": 3,
"client": {
"id": "ios-node",
"version": "1.2.3",
"platform": "ios",
"mode": "node"
},
"role": "node",
"scopes": [],
"caps": ["camera", "canvas", "screen", "location", "voice"],
"commands": ["camera.snap", "canvas.navigate", "screen.record", "location.get"],
"permissions": { "camera.capture": true, "screen.record": false },
"auth": { "token": "…" },
"locale": "en-US",
"userAgent": "openclaw-ios/1.2.3",
"device": {
"id": "device_fingerprint",
"publicKey": "…",
"signature": "…",
"signedAt": 1737264000000,
"nonce": "…"
}
}
}
訊框格式
- Request:
{type:"req", id, method, params} - Response:
{type:"res", id, ok, payload|error} - Event:
{type:"event", event, payload, seq?, stateVersion?}
會產生副作用的方法需要冪等鍵(詳見 schema)。
角色 + 範圍
角色
operator= 控制層用戶端(CLI/UI/自動化)。node= 能力提供主機(camera/screen/canvas/system.run)。
範圍(operator)
常用範圍:
operator.readoperator.writeoperator.adminoperator.approvalsoperator.pairing
方法範圍只是第一道關卡。部分透過 chat.send 發出的斜線指令還會額外檢查指令級別的權限。例如,持久化的 /config set 和 /config unset 寫入需要 operator.admin 範圍。
Caps/commands/permissions(node)
節點在連線時宣告能力聲明:
caps:高階能力分類。commands:允許呼叫的指令白名單。permissions:細粒度開關(例如screen.record、camera.capture)。
Gateway 將這些視為聲明,並在伺服器端強制執行白名單。
線上狀態
system-presence回傳以裝置身分為 key 的條目。- 線上狀態條目包含
deviceId、roles和scopes,讓 UI 即使裝置同時以 operator 和 node 連線,也能顯示為一列。
節點輔助方法
- 節點可以呼叫
skills.bins取得目前的技能可執行檔清單,用於自動允許檢查。
操作者輔助方法
- 操作者可以呼叫
tools.catalog(operator.read)取得某個代理的執行時期工具目錄。回應包含分組的工具及來源中繼資料:source:core或pluginpluginId:source="plugin"時的外掛擁有者optional:外掛工具是否為可選
執行核准
- 當 exec 請求需要核准時,gateway 會廣播
exec.approval.requested。 - 操作者用戶端透過呼叫
exec.approval.resolve來處理(需要operator.approvals範圍)。 - 當
host=node時,exec.approval.request必須包含systemRunPlan(正規化的argv/cwd/rawCommand/session 中繼資料)。缺少systemRunPlan的請求會被拒絕。
版本控制
PROTOCOL_VERSION定義在src/gateway/protocol/schema.ts中。- 用戶端送出
minProtocol+maxProtocol;伺服器在不匹配時拒絕連線。 - Schema 和模型從 TypeBox 定義生成:
pnpm protocol:genpnpm protocol:gen:swiftpnpm protocol:check
認證
- 如果設定了
OPENCLAW_GATEWAY_TOKEN(或--token),connect.params.auth.token必須匹配,否則 socket 會被關閉。 - 配對完成後,Gateway 會發行一組裝置 token,範圍涵蓋連線的角色 + 範圍。它會在
hello-ok.auth.deviceToken中回傳,用戶端應持久化儲存以供後續連線使用。 - 裝置 token 可透過
device.token.rotate和device.token.revoke輪替/撤銷(需要operator.pairing範圍)。 - 認證失敗時會包含
error.details.code及恢復提示:error.details.canRetryWithDeviceToken(布林值)error.details.recommendedNextStep(retry_with_device_token、update_auth_configuration、update_auth_credentials、wait_then_retry、review_auth_configuration)
AUTH_TOKEN_MISMATCH的用戶端行為:- 受信任的用戶端可以用快取的裝置 token 嘗試一次有限制的重試。
- 如果重試也失敗,用戶端應停止自動重連迴圈,並引導操作者採取行動。
裝置身分 + 配對
- 節點應包含穩定的裝置身分(
device.id),由金鑰對指紋衍生。 - Gateway 按裝置 + 角色發行 token。
- 新的裝置 ID 需要配對核准,除非啟用了本機自動核准。
- 本機連線包含 loopback 和 gateway 主機自身的 tailnet 位址(因此同一主機上的 tailnet 綁定仍可自動核准)。
- 所有 WS 用戶端在
connect時都必須包含device身分(operator + node 皆然)。 Control UI 僅在以下模式中可以省略:gateway.controlUi.allowInsecureAuth=true,用於 localhost 的非安全 HTTP 相容模式。gateway.controlUi.dangerouslyDisableDeviceAuth=true(緊急措施,會嚴重降低安全性)。
- 所有連線都必須簽署伺服器提供的
connect.challengenonce。
裝置認證遷移診斷
對於仍使用舊版挑戰簽署行為的用戶端,connect 現在會在 error.details.code 下回傳 DEVICE_AUTH_* 詳細代碼,並附帶穩定的 error.details.reason。
常見遷移失敗情況:
| 訊息 | details.code | details.reason | 說明 |
|---|---|---|---|
device nonce required | DEVICE_AUTH_NONCE_REQUIRED | device-nonce-missing | 用戶端省略了 device.nonce(或送出空值)。 |
device nonce mismatch | DEVICE_AUTH_NONCE_MISMATCH | device-nonce-mismatch | 用戶端使用了過期/錯誤的 nonce 進行簽署。 |
device signature invalid | DEVICE_AUTH_SIGNATURE_INVALID | device-signature | 簽章 payload 不符合 v2 payload 格式。 |
device signature expired | DEVICE_AUTH_SIGNATURE_EXPIRED | device-signature-stale | 簽署時間戳超出允許的偏移範圍。 |
device identity mismatch | DEVICE_AUTH_DEVICE_ID_MISMATCH | device-id-mismatch | device.id 與公鑰指紋不匹配。 |
device public key invalid | DEVICE_AUTH_PUBLIC_KEY_INVALID | device-public-key | 公鑰格式/正規化失敗。 |
遷移目標:
- 務必等待
connect.challenge。 - 簽署包含伺服器 nonce 的 v2 payload。
- 在
connect.params.device.nonce中送出相同的 challenge nonce。 - 建議使用
v3簽章 payload,額外綁定platform和deviceFamily以及 device/client/role/scopes/token/nonce 欄位。 - 舊版
v2簽章仍然接受以保持相容性,但已配對裝置的中繼資料 pinning 在重連時仍會控制指令策略。
TLS + pinning
- WS 連線支援 TLS。
- 用戶端可以選擇 pin gateway 的憑證指紋(參見
gateway.tls設定以及gateway.remote.tlsFingerprint或 CLI 的--tls-fingerprint)。
涵蓋範圍
此協定涵蓋完整的 gateway API(status、channels、models、chat、agent、sessions、nodes、approvals 等)。確切的 API 介面由 src/gateway/protocol/schema.ts 中的 TypeBox schema 定義。