Gateway WS 协议是 OpenClaw 的单一控制面 + 节点传输。所有客户端(CLI、Web UI、macOS、iOS/Android 节点、无头节点)均通过 WebSocket 连接,握手时声明 role + scope。
传输层
- WebSocket,文本帧,JSON payload
- 第一帧必须是
connect请求 - 握手前帧上限 64 KiB;握手后遵循
hello-ok.policy.maxPayload和maxBufferedBytes
握手流程
Gateway → Client(预连接挑战):
{ "type": "event", "event": "connect.challenge", "payload": { "nonce": "…", "ts": 1737264000000 } }Client → Gateway(connect 请求):
{
"type": "req", "id": "…", "method": "connect",
"params": {
"minProtocol": 3, "maxProtocol": 4,
"client": { "id": "cli", "version": "1.2.3", "platform": "macos", "mode": "operator" },
"role": "operator",
"scopes": ["operator.read", "operator.write"],
"auth": { "token": "…" },
"device": { "id": "device_fingerprint", "publicKey": "…", "signature": "…", "nonce": "…" }
}
}Gateway → Client(hello-ok):
{
"type": "res", "id": "…", "ok": true,
"payload": {
"type": "hello-ok", "protocol": 4,
"server": { "version": "…", "connId": "…" },
"auth": { "role": "operator", "scopes": ["operator.read", "operator.write"] },
"policy": { "maxPayload": 26214400, "maxBufferedBytes": 52428800, "tickIntervalMs": 15000 }
}
}帧格式
- Request:
{type:"req", id, method, params} - Response:
{type:"res", id, ok, payload|error} - Event:
{type:"event", event, payload, seq?, stateVersion?}
角色与 Scope
operator:控制面客户端(CLI/UI/自动化)node:能力宿主(camera/screen/canvas/system.run)
常用 operator scope:operator.read、operator.write、operator.admin、operator.approvals、operator.pairing、operator.talk.secrets
广播事件 Scope 门控
- chat/agent/tool 帧:需要
operator.read - plugin 广播:需要
operator.write或operator.admin - 状态/心跳事件:无限制
版本控制
- 协议版本在
src/gateway/protocol/version.ts,当前 v4,最低兼容 v3 - 客户端发送
minProtocol+maxProtocol,服务端拒绝不兼容范围 - Schema 生成:
pnpm protocol:gen
客户端常量
| 常量 | 默认值 |
|---|---|
PROTOCOL_VERSION | 4 |
| 请求超时 | 30,000 ms |
| 握手超时 | 15,000 ms |
| 初始重连退避 | 1,000 ms |
| 最大重连退避 | 30,000 ms |
MAX_PAYLOAD_BYTES | 25 MB |
设备身份与配对
- 节点应包含稳定设备身份(
device.id),来自密钥对指纹 - Gateway 按设备 + 角色签发 token
- 新设备 ID 需要配对审批(本地 loopback 可自动审批)