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.read
  • operator.write
  • operator.admin
  • operator.approvals
  • operator.pairing

方法範圍只是第一道關卡。部分透過 chat.send 發出的斜線指令還會額外檢查指令級別的權限。例如,持久化的 /config set/config unset 寫入需要 operator.admin 範圍。

Caps/commands/permissions(node)

節點在連線時宣告能力聲明:

  • caps:高階能力分類。
  • commands:允許呼叫的指令白名單。
  • permissions:細粒度開關(例如 screen.recordcamera.capture)。

Gateway 將這些視為聲明,並在伺服器端強制執行白名單。

線上狀態

  • system-presence 回傳以裝置身分為 key 的條目。
  • 線上狀態條目包含 deviceIdrolesscopes,讓 UI 即使裝置同時以 operatornode 連線,也能顯示為一列。

節點輔助方法

  • 節點可以呼叫 skills.bins 取得目前的技能可執行檔清單,用於自動允許檢查。

操作者輔助方法

  • 操作者可以呼叫 tools.catalogoperator.read)取得某個代理的執行時期工具目錄。回應包含分組的工具及來源中繼資料:
    • sourcecoreplugin
    • pluginIdsource="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:gen
    • pnpm protocol:gen:swift
    • pnpm protocol:check

認證

  • 如果設定了 OPENCLAW_GATEWAY_TOKEN(或 --token),connect.params.auth.token 必須匹配,否則 socket 會被關閉。
  • 配對完成後,Gateway 會發行一組裝置 token,範圍涵蓋連線的角色 + 範圍。它會在 hello-ok.auth.deviceToken 中回傳,用戶端應持久化儲存以供後續連線使用。
  • 裝置 token 可透過 device.token.rotatedevice.token.revoke 輪替/撤銷(需要 operator.pairing 範圍)。
  • 認證失敗時會包含 error.details.code 及恢復提示:
    • error.details.canRetryWithDeviceToken(布林值)
    • error.details.recommendedNextStepretry_with_device_tokenupdate_auth_configurationupdate_auth_credentialswait_then_retryreview_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.challenge nonce。

裝置認證遷移診斷

對於仍使用舊版挑戰簽署行為的用戶端,connect 現在會在 error.details.code 下回傳 DEVICE_AUTH_* 詳細代碼,並附帶穩定的 error.details.reason

常見遷移失敗情況:

訊息details.codedetails.reason說明
device nonce requiredDEVICE_AUTH_NONCE_REQUIREDdevice-nonce-missing用戶端省略了 device.nonce(或送出空值)。
device nonce mismatchDEVICE_AUTH_NONCE_MISMATCHdevice-nonce-mismatch用戶端使用了過期/錯誤的 nonce 進行簽署。
device signature invalidDEVICE_AUTH_SIGNATURE_INVALIDdevice-signature簽章 payload 不符合 v2 payload 格式。
device signature expiredDEVICE_AUTH_SIGNATURE_EXPIREDdevice-signature-stale簽署時間戳超出允許的偏移範圍。
device identity mismatchDEVICE_AUTH_DEVICE_ID_MISMATCHdevice-id-mismatchdevice.id 與公鑰指紋不匹配。
device public key invalidDEVICE_AUTH_PUBLIC_KEY_INVALIDdevice-public-key公鑰格式/正規化失敗。

遷移目標:

  • 務必等待 connect.challenge
  • 簽署包含伺服器 nonce 的 v2 payload。
  • connect.params.device.nonce 中送出相同的 challenge nonce。
  • 建議使用 v3 簽章 payload,額外綁定 platformdeviceFamily 以及 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 定義。