Protocolo del Gateway (WebSocket)
El protocolo WS del Gateway es el único plano de control + transporte de nodos para OpenClaw. Todos los clientes (CLI, web UI, app de macOS, nodos iOS/Android, nodos headless) se conectan por WebSocket y declaran su rol + alcance en el momento del handshake.
Transporte
- WebSocket, tramas de texto con payloads JSON.
- La primera trama debe ser una solicitud
connect.
Handshake (connect)
Gateway -> Cliente (desafío pre-conexión):
{
"type": "event",
"event": "connect.challenge",
"payload": { "nonce": "…", "ts": 1737264000000 }
}
Cliente -> 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 -> Cliente:
{
"type": "res",
"id": "…",
"ok": true,
"payload": { "type": "hello-ok", "protocol": 3, "policy": { "tickIntervalMs": 15000 } }
}
Cuando se emite un token de dispositivo, hello-ok también incluye:
{
"auth": {
"deviceToken": "…",
"role": "operator",
"scopes": ["operator.read", "operator.write"]
}
}
Ejemplo de nodo
{
"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": "…"
}
}
}
Tramas
- Solicitud:
{type:"req", id, method, params} - Respuesta:
{type:"res", id, ok, payload|error} - Evento:
{type:"event", event, payload, seq?, stateVersion?}
Los métodos con efectos secundarios requieren claves de idempotencia (consulta el esquema).
Roles + alcances
Roles
operator= cliente del plano de control (CLI/UI/automatización).node= host de capacidades (cámara/pantalla/canvas/system.run).
Alcances (operator)
Alcances comunes:
operator.readoperator.writeoperator.adminoperator.approvalsoperator.pairing
El alcance del método es solo la primera compuerta. Algunos comandos slash alcanzados a través de chat.send aplican verificaciones más estrictas a nivel de comando por encima. Por ejemplo, las escrituras persistentes /config set y /config unset requieren operator.admin.
Caps/commands/permissions (nodo)
Los nodos declaran claims de capacidad en el momento de la conexión:
caps: categorías de capacidades de alto nivel.commands: lista de comandos permitidos para invocación.permissions: toggles granulares (por ejemplo,screen.record,camera.capture).
El Gateway trata estos como claims y aplica listas de permitidos del lado del servidor.
Presencia
system-presencedevuelve entradas indexadas por identidad de dispositivo.- Las entradas de presencia incluyen
deviceId,rolesyscopespara que las UIs puedan mostrar una sola fila por dispositivo incluso cuando se conecta como operator y node simultáneamente.
Métodos auxiliares de nodo
- Los nodos pueden llamar a
skills.binspara obtener la lista actual de ejecutables de habilidades para verificaciones de auto-permitido.
Métodos auxiliares de operador
- Los operadores pueden llamar a
tools.catalog(operator.read) para obtener el catálogo de herramientas en tiempo de ejecución de un agente. La respuesta incluye herramientas agrupadas y metadatos de procedencia:source:coreopluginpluginId: propietario del plugin cuandosource="plugin"optional: si una herramienta de plugin es opcional
Aprobaciones de ejecución
- Cuando una solicitud de ejecución necesita aprobación, el gateway difunde
exec.approval.requested. - Los clientes operadores resuelven llamando a
exec.approval.resolve(requiere alcanceoperator.approvals). - Para
host=node,exec.approval.requestdebe incluirsystemRunPlan(argv/cwd/rawCommand/metadatos de sesión canónicos). Las solicitudes sinsystemRunPlanse rechazan.
Versionado
PROTOCOL_VERSIONreside ensrc/gateway/protocol/schema.ts.- Los clientes envían
minProtocol+maxProtocol; el servidor rechaza las discrepancias. - Los esquemas + modelos se generan a partir de definiciones TypeBox:
pnpm protocol:genpnpm protocol:gen:swiftpnpm protocol:check
Autenticación
- Si
OPENCLAW_GATEWAY_TOKEN(o--token) está configurado,connect.params.auth.tokendebe coincidir o el socket se cierra. - Después del emparejamiento, el Gateway emite un token de dispositivo con alcance para el rol + alcances de la conexión. Se devuelve en
hello-ok.auth.deviceTokeny el cliente debe persistirlo para futuras conexiones. - Los tokens de dispositivo pueden rotarse/revocarse mediante
device.token.rotateydevice.token.revoke(requiere alcanceoperator.pairing). - Los fallos de autenticación incluyen
error.details.codemás sugerencias de recuperación:error.details.canRetryWithDeviceToken(boolean)error.details.recommendedNextStep(retry_with_device_token,update_auth_configuration,update_auth_credentials,wait_then_retry,review_auth_configuration)
- Comportamiento del cliente para
AUTH_TOKEN_MISMATCH:- Los clientes de confianza pueden intentar un reintento limitado con un token de dispositivo en caché.
- Si ese reintento falla, los clientes deben detener los bucles de reconexión automática y mostrar orientación para acción del operador.
Identidad de dispositivo + emparejamiento
- Los nodos deben incluir una identidad de dispositivo estable (
device.id) derivada de una huella digital de par de claves. - Los Gateways emiten tokens por dispositivo + rol.
- Las aprobaciones de emparejamiento son obligatorias para nuevos IDs de dispositivo a menos que la aprobación automática local esté habilitada.
- Las conexiones locales incluyen loopback y la propia dirección tailnet del host del gateway (para que los enlaces tailnet del mismo host puedan auto-aprobar).
- Todos los clientes WS deben incluir identidad
deviceduranteconnect(operator + node). La UI de control puede omitirla solo en estos modos:gateway.controlUi.allowInsecureAuth=truepara compatibilidad HTTP insegura solo en localhost.gateway.controlUi.dangerouslyDisableDeviceAuth=true(solución de emergencia, degradación severa de seguridad).
- Todas las conexiones deben firmar el nonce
connect.challengeproporcionado por el servidor.
Diagnósticos de migración de autenticación de dispositivo
Para clientes heredados que aún usan el comportamiento de firma pre-desafío, connect ahora devuelve códigos de detalle DEVICE_AUTH_* en error.details.code con un error.details.reason estable.
Fallos de migración comunes:
| Mensaje | details.code | details.reason | Significado |
|---|---|---|---|
device nonce required | DEVICE_AUTH_NONCE_REQUIRED | device-nonce-missing | El cliente omitió device.nonce (o envió vacío). |
device nonce mismatch | DEVICE_AUTH_NONCE_MISMATCH | device-nonce-mismatch | El cliente firmó con un nonce obsoleto/incorrecto. |
device signature invalid | DEVICE_AUTH_SIGNATURE_INVALID | device-signature | El payload de firma no coincide con el payload v2. |
device signature expired | DEVICE_AUTH_SIGNATURE_EXPIRED | device-signature-stale | La marca de tiempo firmada está fuera del margen permitido. |
device identity mismatch | DEVICE_AUTH_DEVICE_ID_MISMATCH | device-id-mismatch | device.id no coincide con la huella de clave pública. |
device public key invalid | DEVICE_AUTH_PUBLIC_KEY_INVALID | device-public-key | El formato/canonización de la clave pública falló. |
Objetivo de migración:
- Siempre espera
connect.challenge. - Firma el payload v2 que incluye el nonce del servidor.
- Envía el mismo nonce en
connect.params.device.nonce. - El payload de firma preferido es
v3, que vinculaplatformydeviceFamilyademás de los campos device/client/role/scopes/token/nonce. - Las firmas heredadas
v2siguen aceptándose por compatibilidad, pero el pinning de metadatos de dispositivos emparejados sigue controlando la política de comandos en la reconexión.
TLS + pinning
- TLS es soportado para conexiones WS.
- Los clientes pueden opcionalmente anclar la huella del certificado del gateway (consulta la configuración
gateway.tlsmásgateway.remote.tlsFingerprinto CLI--tls-fingerprint).
Alcance
Este protocolo expone la API completa del gateway (estado, canales, modelos, chat, agente, sesiones, nodos, aprobaciones, etc.). La superficie exacta está definida por los esquemas TypeBox en src/gateway/protocol/schema.ts.