Caricamento in corso...
Caricamento in corso...
Last synced: Today, 22:00
Technical reference for the OpenClaw framework. Real-time synchronization with the official documentation engine.
Use this file to discover all available pages before exploring further.
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.
connecthello-ok.policy.maxPayloadhello-ok.policy.maxBufferedBytespayload.largeGateway → Client (pre-connect challenge):
json{ "type": "event", "event": "connect.challenge", "payload": { "nonce": "…", "ts": 1737264000000 } }
Client → Gateway:
json{ "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 → Client:
json{ "type": "res", "id": "…", "ok": true, "payload": { "type": "hello-ok", "protocol": 3, "server": { "version": "…", "connId": "…" }, "features": { "methods": ["…"], "events": ["…"] }, "snapshot": { "…": "…" }, "auth": { "role": "operator", "scopes": ["operator.read", "operator.write"] }, "policy": { "maxPayload": 26214400, "maxBufferedBytes": 52428800, "tickIntervalMs": 15000 } } }
While the Gateway is still finishing startup sidecars, the
connectUNAVAILABLEdetails.reason"startup-sidecars"retryAfterMsserverfeaturessnapshotpolicysrc/gateway/protocol/schema/frames.tsauthcanvasHostUrlWhen no device token is issued,
hello-ok.authjson{ "auth": { "role": "operator", "scopes": ["operator.read", "operator.write"] } }
Trusted same-process backend clients (
client.id: "gateway-client"client.mode: "backend"deviceWhen a device token is issued,
hello-okjson{ "auth": { "deviceToken": "…", "role": "operator", "scopes": ["operator.read", "operator.write"] } }
During trusted bootstrap handoff,
hello-ok.authdeviceTokensjson{ "auth": { "deviceToken": "…", "role": "node", "scopes": [], "deviceTokens": [ { "deviceToken": "…", "role": "operator", "scopes": ["operator.approvals", "operator.read", "operator.talk.secrets", "operator.write"] } ] } }
For the built-in node/operator bootstrap flow, the primary node token stays
scopes: []operator.approvalsoperator.readoperator.talk.secretsoperator.writejson{ "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": "…" } } }
{type:"req", id, method, params}{type:"res", id, ok, payload|error}{type:"event", event, payload, seq?, stateVersion?}Side-effecting methods require idempotency keys (see schema).
operatornodeCommon scopes:
operator.readoperator.writeoperator.adminoperator.approvalsoperator.pairingoperator.talk.secretstalk.configincludeSecrets: trueoperator.talk.secretsoperator.adminPlugin-registered gateway RPC methods may request their own operator scope, but reserved core admin prefixes (
config.*exec.approvals.*wizard.*update.*operator.adminMethod scope is only the first gate. Some slash commands reached through
chat.send/config set/config unsetoperator.adminnode.pair.approveoperator.pairingoperator.pairingoperator.writesystem.runsystem.run.preparesystem.whichoperator.pairingoperator.adminNodes declare capability claims at connect time:
capscommandspermissionsscreen.recordcamera.captureThe Gateway treats these as claims and enforces server-side allowlists.
system-presencedeviceIdrolesscopesnode.listlastSeenAtMslastSeenReasonlastSeenAtMsconnectNodes may call
node.eventevent: "node.presence.alive"json{ "event": "node.presence.alive", "payloadJSON": "{\"trigger\":\"silent_push\",\"sentAtMs\":1737264000000,\"displayName\":\"Peter's iPhone\",\"version\":\"2026.4.28\",\"platform\":\"iOS 18.4.0\",\"deviceFamily\":\"iPhone\",\"modelIdentifier\":\"iPhone17,1\",\"pushTransport\":\"relay\"}" }
triggerbackgroundsilent_pushbg_app_refreshsignificant_locationmanualconnectbackgroundhandled: falseSuccessful gateways return a structured result:
json{ "ok": true, "event": "node.presence.alive", "handled": true, "reason": "persisted" }
Older gateways may still return
{ "ok": true }node.eventServer-pushed WebSocket broadcast events are scope-gated so that pairing-scoped or node-only sessions do not passively receive session content.
agentoperator.readoperator.readplugin.*operator.writeoperator.adminheartbeatpresencetickEach client connection keeps its own per-client sequence number so broadcasts preserve monotonic ordering on that socket even when different clients see different scope-filtered subsets of the event stream.
The public WS surface is broader than the handshake/auth examples above. This is not a generated dump —
hello-ok.features.methodssrc/gateway/server-methods-list.tssrc/gateway/server-methods/*.tschatchat.injectsession.messagesession.toolsessions.changedpresencetickhealthheartbeatcronshutdownnode.pair.requestednode.pair.resolvednode.invoke.requestdevice.pair.requesteddevice.pair.resolvedvoicewake.changedexec.approval.requestedexec.approval.resolvedplugin.approval.requestedplugin.approval.resolvedskills.binscommands.listoperator.readagentIdscopenametext/nativebothtextAliases/model/mnativeNameproviderincludeArgs=falsetools.catalogoperator.readsourcecorepluginpluginIdsource="plugin"optionaltools.effectiveoperator.readsessionKeyskills.statusoperator.readagentIdskills.searchskills.detailoperator.readskills.installoperator.admin{ source: "clawhub", slug, version?, force? }skills/{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }metadata.openclaw.installskills.updateoperator.adminskills.entries.<skillKey>enabledapiKeyenvmodels.listmodels.listview"default"agents.defaults.models"configured"agents.defaults.modelsmodels.providers.*.models"all"agents.defaults.modelsexec.approval.requestedexec.approval.resolveoperator.approvalshost=nodeexec.approval.requestsystemRunPlanargvcwdrawCommandsystemRunPlannode.invoke system.runsystemRunPlancommandrawCommandcwdagentIdsessionKeysystem.runagentdeliver=truebestEffortDeliver=falseINVALID_REQUESTbestEffortDeliver=truePROTOCOL_VERSIONsrc/gateway/protocol/schema/protocol-schemas.tsminProtocolmaxProtocolpnpm protocol:genpnpm protocol:gen:swiftpnpm protocol:checkThe reference client in
src/gateway/client.ts| Constant | Default | Source |
|---|---|---|
text PROTOCOL_VERSION | text 3 | text src/gateway/protocol/schema/protocol-schemas.ts |
| Request timeout (per RPC) | text 30_000 | text src/gateway/client.tstext requestTimeoutMs |
| Preauth / connect-challenge timeout | text 15_000 | text src/gateway/handshake-timeouts.ts |
| Initial reconnect backoff | text 1_000 | text src/gateway/client.tstext backoffMs |
| Max reconnect backoff | text 30_000 | text src/gateway/client.tstext scheduleReconnect |
| Fast-retry clamp after device-token close | text 250 | text src/gateway/client.ts |
| Force-stop grace before text terminate() | text 250 | text FORCE_STOP_TERMINATE_GRACE_MS |
text stopAndWait() | text 1_000 | text STOP_AND_WAIT_TIMEOUT_MS |
| Default tick interval (pre text hello-ok | text 30_000 | text src/gateway/client.ts |
| Tick-timeout close | code text 4000text tickIntervalMs * 2 | text src/gateway/client.ts |
text MAX_PAYLOAD_BYTES | text 25 * 1024 * 1024 | text src/gateway/server-constants.ts |
The server advertises the effective
policy.tickIntervalMspolicy.maxPayloadpolicy.maxBufferedByteshello-okconnect.params.auth.tokenconnect.params.auth.passwordgateway.auth.allowTailscale: truegateway.auth.mode: "trusted-proxy"connect.params.auth.*gateway.auth.mode: "none"hello-ok.auth.deviceTokenhello-ok.auth.deviceTokenselectConnectAuthsrc/gateway/client.tsauth.passwordauth.tokendeviceTokendeviceIdroleauth.bootstrapTokenauth.tokenAUTH_TOKEN_MISMATCHwss://tlsFingerprintwss://hello-ok.auth.deviceTokenswss://deviceTokenscopesdevice.token.rotatedevice.token.revokeoperator.pairingdevice.token.rotateoperator.admindevice.token.rotatedevice.token.revokeerror.details.codeerror.details.canRetryWithDeviceTokenerror.details.recommendedNextStepretry_with_device_tokenupdate_auth_configurationupdate_auth_credentialswait_then_retryreview_auth_configurationAUTH_TOKEN_MISMATCHdevice.iddeviceconnectgateway.controlUi.allowInsecureAuth=truegateway.auth.mode: "trusted-proxy"gateway.controlUi.dangerouslyDisableDeviceAuth=truegateway-clientconnect.challengeFor legacy clients that still use pre-challenge signing behavior,
connectDEVICE_AUTH_*error.details.codeerror.details.reasonCommon migration failures:
| Message | details.code | details.reason | Meaning |
|---|---|---|---|
text device nonce required | text DEVICE_AUTH_NONCE_REQUIRED | text device-nonce-missing | Client omitted text device.nonce |
text device nonce mismatch | text DEVICE_AUTH_NONCE_MISMATCH | text device-nonce-mismatch | Client signed with a stale/wrong nonce. |
text device signature invalid | text DEVICE_AUTH_SIGNATURE_INVALID | text device-signature | Signature payload does not match v2 payload. |
text device signature expired | text DEVICE_AUTH_SIGNATURE_EXPIRED | text device-signature-stale | Signed timestamp is outside allowed skew. |
text device identity mismatch | text DEVICE_AUTH_DEVICE_ID_MISMATCH | text device-id-mismatch | text device.id |
text device public key invalid | text DEVICE_AUTH_PUBLIC_KEY_INVALID | text device-public-key | Public key format/canonicalization failed. |
Migration target:
connect.challengeconnect.params.device.noncev3platformdeviceFamilyv2gateway.tlsgateway.remote.tlsFingerprint--tls-fingerprintThis protocol exposes the full gateway API (status, channels, models, chat, agent, sessions, nodes, approvals, etc.). The exact surface is defined by the TypeBox schemas in
src/gateway/protocol/schema.ts© 2024 TaskFlow Mirror
Powered by TaskFlow Sync Engine