Gateway-Protokoll (WebSocket)
Das Gateway-WS-Protokoll ist die einzige Steuerungsebene + Node-Transport für OpenClaw. Alle Clients (CLI, Web-UI, macOS-App, iOS/Android-Nodes, Headless-Nodes) verbinden sich per WebSocket und deklarieren ihre Rolle + ihren Scope beim Handshake.
Transport
- WebSocket, Text-Frames mit JSON-Payloads.
- Der erste Frame muss eine
connect-Anfrage sein.
Handshake (connect)
Gateway an Client (Pre-Connect-Challenge):
{
"type": "event",
"event": "connect.challenge",
"payload": { "nonce": "…", "ts": 1737264000000 }
}
Client an 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 an Client:
{
"type": "res",
"id": "…",
"ok": true,
"payload": { "type": "hello-ok", "protocol": 3, "policy": { "tickIntervalMs": 15000 } }
}
Wenn ein Device-Token ausgestellt wird, enthält hello-ok zusätzlich:
{
"auth": {
"deviceToken": "…",
"role": "operator",
"scopes": ["operator.read", "operator.write"]
}
}
Node-Beispiel
{
"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": "…"
}
}
}
Framing
- Request:
{type:"req", id, method, params} - Response:
{type:"res", id, ok, payload|error} - Event:
{type:"event", event, payload, seq?, stateVersion?}
Seiteneffekt-behaftete Methoden erfordern Idempotenz-Keys (siehe Schema).
Rollen + Scopes
Rollen
operator= Control-Plane-Client (CLI/UI/Automatisierung).node= Capability-Host (Kamera/Bildschirm/Canvas/system.run).
Scopes (Operator)
Gängige Scopes:
operator.readoperator.writeoperator.adminoperator.approvalsoperator.pairing
Der Methoden-Scope ist nur die erste Hürde. Einige Slash-Befehle, die über chat.send erreichbar sind, wenden darüber hinaus strengere Befehlsebene-Prüfungen an. Zum Beispiel erfordern persistente /config set- und /config unset-Schreibvorgänge operator.admin.
Caps/Commands/Permissions (Node)
Nodes deklarieren beim Connect ihre Capability-Ansprüche:
caps: übergeordnete Capability-Kategorien.commands: Befehls-Allowlist für Aufrufe.permissions: granulare Toggles (z. B.screen.record,camera.capture).
Das Gateway behandelt diese als Ansprüche und erzwingt serverseitige Allowlists.
Presence
system-presencegibt Einträge zurück, die nach Device-Identität geordnet sind.- Presence-Einträge enthalten
deviceId,rolesundscopes, damit UIs eine einzelne Zeile pro Gerät anzeigen können, auch wenn es sich gleichzeitig als Operator und Node verbindet.
Node-Hilfsmethoden
- Nodes können
skills.binsaufrufen, um die aktuelle Liste der Skill-Executables für Auto-Allow-Checks abzurufen.
Operator-Hilfsmethoden
- Operators können
tools.catalog(operator.read) aufrufen, um den Runtime-Tool-Katalog für einen Agent abzurufen. Die Antwort enthält gruppierte Tools und Provenance-Metadaten:source:coreoderpluginpluginId: Plugin-Besitzer wennsource="plugin"optional: ob ein Plugin-Tool optional ist
Exec-Genehmigungen
- Wenn eine Exec-Anfrage eine Genehmigung braucht, sendet das Gateway
exec.approval.requested. - Operator-Clients lösen dies durch Aufruf von
exec.approval.resolve(erfordertoperator.approvals-Scope). - Für
host=nodemussexec.approval.requesteinensystemRunPlanenthalten (kanonischesargv/cwd/rawCommand/Session-Metadaten). Anfragen ohnesystemRunPlanwerden abgelehnt.
Versionierung
PROTOCOL_VERSIONbefindet sich insrc/gateway/protocol/schema.ts.- Clients senden
minProtocol+maxProtocol; der Server lehnt Inkompatibilitäten ab. - Schemas + Modelle werden aus TypeBox-Definitionen generiert:
pnpm protocol:genpnpm protocol:gen:swiftpnpm protocol:check
Auth
- Wenn
OPENCLAW_GATEWAY_TOKEN(oder--token) gesetzt ist, mussconnect.params.auth.tokenübereinstimmen, sonst wird der Socket geschlossen. - Nach der Kopplung stellt das Gateway ein Device-Token aus, das auf die Verbindungsrolle
- Scopes beschränkt ist. Es wird in
hello-ok.auth.deviceTokenzurückgegeben und sollte vom Client für zukünftige Verbindungen persistiert werden.
- Scopes beschränkt ist. Es wird in
- Device-Tokens können über
device.token.rotateunddevice.token.revokerotiert/widerrufen werden (erfordertoperator.pairing-Scope). - Auth-Fehler enthalten
error.details.codeplus Recovery-Hinweise:error.details.canRetryWithDeviceToken(Boolean)error.details.recommendedNextStep(retry_with_device_token,update_auth_configuration,update_auth_credentials,wait_then_retry,review_auth_configuration)
- Client-Verhalten bei
AUTH_TOKEN_MISMATCH:- Vertrauenswürdige Clients können einen begrenzten Retry mit einem gecachten Per-Device-Token versuchen.
- Wenn dieser Retry fehlschlägt, sollten Clients automatische Reconnect-Schleifen stoppen und Operator-Handlungshinweise anzeigen.
Device-Identität + Kopplung
- Nodes sollten eine stabile Device-Identität (
device.id) mitliefern, die aus einem Keypair-Fingerprint abgeleitet wird. - Gateways stellen Tokens pro Gerät + Rolle aus.
- Kopplungsgenehmigungen sind für neue Device-IDs erforderlich, es sei denn, die lokale Auto-Genehmigung ist aktiviert.
- Lokale Verbindungen umfassen Loopback und die eigene Tailnet-Adresse des Gateway-Hosts (damit Same-Host-Tailnet-Bindungen trotzdem auto-genehmigt werden können).
- Alle WS-Clients müssen während
connecteinedevice-Identität mitsenden (Operator + Node). Die Control-UI kann sie nur in diesen Modi weglassen:gateway.controlUi.allowInsecureAuth=truefür Localhost-only unsichere HTTP-Kompatibilität.gateway.controlUi.dangerouslyDisableDeviceAuth=true(Break-Glass, schwerwiegende Sicherheitsherabstufung).
- Alle Verbindungen müssen die vom Server bereitgestellte
connect.challenge-Nonce signieren.
Diagnose zur Device-Auth-Migration
Für Legacy-Clients, die noch das Verhalten vor der Challenge-Signierung verwenden, gibt connect jetzt
DEVICE_AUTH_*-Detailcodes unter error.details.code mit einem stabilen error.details.reason zurück.
Häufige Migrationsfehler:
| Nachricht | details.code | details.reason | Bedeutung |
|---|---|---|---|
device nonce required | DEVICE_AUTH_NONCE_REQUIRED | device-nonce-missing | Client hat device.nonce ausgelassen (oder leer gesendet) |
device nonce mismatch | DEVICE_AUTH_NONCE_MISMATCH | device-nonce-mismatch | Client hat mit veralteter/falscher Nonce signiert |
device signature invalid | DEVICE_AUTH_SIGNATURE_INVALID | device-signature | Signatur-Payload stimmt nicht mit v2-Payload überein |
device signature expired | DEVICE_AUTH_SIGNATURE_EXPIRED | device-signature-stale | Signierter Zeitstempel liegt außerhalb des erlaubten Skew |
device identity mismatch | DEVICE_AUTH_DEVICE_ID_MISMATCH | device-id-mismatch | device.id stimmt nicht mit dem Public-Key-Fingerprint überein |
device public key invalid | DEVICE_AUTH_PUBLIC_KEY_INVALID | device-public-key | Public-Key-Format/Kanonisierung fehlgeschlagen |
Migrationsziel:
- Immer auf
connect.challengewarten. - Den v2-Payload signieren, der die Server-Nonce enthält.
- Dieselbe Nonce in
connect.params.device.noncesenden. - Bevorzugter Signatur-Payload ist
v3, der zusätzlichplatformunddeviceFamilyneben device/client/role/scopes/token/nonce-Feldern bindet. - Legacy-
v2-Signaturen werden weiterhin aus Kompatibilitätsgründen akzeptiert, aber Paired-Device-Metadaten-Pinning steuert weiterhin die Command-Policy bei Reconnects.
TLS + Pinning
- TLS wird für WS-Verbindungen unterstützt.
- Clients können optional den Gateway-Cert-Fingerprint pinnen (siehe
gateway.tls-Konfiguration plusgateway.remote.tlsFingerprintoder CLI--tls-fingerprint).
Scope
Dieses Protokoll legt die vollständige Gateway-API offen (Status, Channels, Modelle, Chat,
Agent, Sessions, Nodes, Genehmigungen usw.). Die genaue Oberfläche wird durch die
TypeBox-Schemas in src/gateway/protocol/schema.ts definiert.