Gateway protocol (WebSocket)
The Gateway WS protocol is the single control plane + node transport for OpenClaw. All clients (CLI, web UI, macOS app, iOS/Android nodes, headless nodes) connect over WebSocket and declare their role + scope at handshake time.Transport
- WebSocket, text frames with JSON payloads.
- First frame must be a
connectrequest.
Handshake (connect)
Gateway → Client (pre-connect challenge):hello-ok also includes:
Node example
Framing
- Request:
{type:"req", id, method, params} - Response:
{type:"res", id, ok, payload|error} - Event:
{type:"event", event, payload, seq?, stateVersion?}
Roles + scopes
Roles
operator= control plane client (CLI/UI/automation).node= capability host (camera/screen/canvas/system.run).
Scopes (operator)
Common scopes:operator.readoperator.writeoperator.adminoperator.approvalsoperator.pairing
Caps/commands/permissions (node)
Nodes declare capability claims at connect time:caps: high-level capability categories.commands: command allowlist for invoke.permissions: granular toggles (e.g.screen.record,camera.capture).
Presence
system-presencereturns entries keyed by device identity.- Presence entries include
deviceId,roles, andscopesso UIs can show a single row per device even when it connects as both operator and node.
Node helper methods
- Nodes may call
skills.binsto fetch the current list of skill executables for auto-allow checks.
Operator helper methods
- Operators may call
tools.catalog(operator.read) to fetch the runtime tool catalog for an agent. The response includes grouped tools and provenance metadata:source:coreorpluginpluginId: plugin owner whensource="plugin"optional: whether a plugin tool is optional
Exec approvals
- When an exec request needs approval, the gateway broadcasts
exec.approval.requested. - Operator clients resolve by calling
exec.approval.resolve(requiresoperator.approvalsscope).
Versioning
PROTOCOL_VERSIONlives insrc/gateway/protocol/schema.ts.- Clients send
minProtocol+maxProtocol; the server rejects mismatches. - Schemas + models are generated from TypeBox definitions:
pnpm protocol:genpnpm protocol:gen:swiftpnpm protocol:check
Auth
- If
OPENCLAW_GATEWAY_TOKEN(or--token) is set,connect.params.auth.tokenmust match or the socket is closed. - After pairing, the Gateway issues a device token scoped to the connection
role + scopes. It is returned in
hello-ok.auth.deviceTokenand should be persisted by the client for future connects. - Device tokens can be rotated/revoked via
device.token.rotateanddevice.token.revoke(requiresoperator.pairingscope).
Device identity + pairing
- Nodes should include a stable device identity (
device.id) derived from a keypair fingerprint. - Gateways issue tokens per device + role.
- Pairing approvals are required for new device IDs unless local auto-approval is enabled.
- Local connects include loopback and the gateway host’s own tailnet address (so same‑host tailnet binds can still auto‑approve).
- All WS clients must include
deviceidentity duringconnect(operator + node). Control UI can omit it only whengateway.controlUi.dangerouslyDisableDeviceAuthis enabled for break-glass use. - All connections must sign the server-provided
connect.challengenonce.
Device auth migration diagnostics
For legacy clients that still use pre-challenge signing behavior,connect now returns
DEVICE_AUTH_* detail codes under error.details.code with a stable error.details.reason.
Common migration failures:
| Message | details.code | details.reason | Meaning |
|---|---|---|---|
device nonce required | DEVICE_AUTH_NONCE_REQUIRED | device-nonce-missing | Client omitted device.nonce (or sent blank). |
device nonce mismatch | DEVICE_AUTH_NONCE_MISMATCH | device-nonce-mismatch | Client signed with a stale/wrong nonce. |
device signature invalid | DEVICE_AUTH_SIGNATURE_INVALID | device-signature | Signature payload does not match v2 payload. |
device signature expired | DEVICE_AUTH_SIGNATURE_EXPIRED | device-signature-stale | Signed timestamp is outside allowed skew. |
device identity mismatch | DEVICE_AUTH_DEVICE_ID_MISMATCH | device-id-mismatch | device.id does not match public key fingerprint. |
device public key invalid | DEVICE_AUTH_PUBLIC_KEY_INVALID | device-public-key | Public key format/canonicalization failed. |
- Always wait for
connect.challenge. - Sign the v2 payload that includes the server nonce.
- Send the same nonce in
connect.params.device.nonce. - Preferred signature payload is
v3, which bindsplatformanddeviceFamilyin addition to device/client/role/scopes/token/nonce fields. - Legacy
v2signatures remain accepted for compatibility, but paired-device metadata pinning still controls command policy on reconnect.
TLS + pinning
- TLS is supported for WS connections.
- Clients may optionally pin the gateway cert fingerprint (see
gateway.tlsconfig plusgateway.remote.tlsFingerprintor CLI--tls-fingerprint).
Scope
This protocol exposes the full gateway API (status, channels, models, chat, agent, sessions, nodes, approvals, etc.). The exact surface is defined by the TypeBox schemas insrc/gateway/protocol/schema.ts.