OpenClawSkills
GitHub
Core Concepts • 5 min de lectura

TypeBox

Treat TypeBox schemas as the single source of truth (SSOT) for Gateway protocol.

Última actualización: 2026-01-10

TypeBox es una librería de esquemas TypeScript-first. La usamos para definir el **protocolo

WebSocket del Gateway** (handshake, petición/respuesta, eventos del servidor). Esos esquemas

impulsan validación en runtime, exportación de esquema JSON, y codegen Swift para la

aplicación macOS. Una única fuente de verdad; todo lo demás se genera.

Si quieres un contexto de protocolo de más alto nivel, empieza desde

''Arquitectura del Gateway''.

Tutorial.step

Modelo Mental (30 segundos)

Cada mensaje WS del gateway es uno de tres frames:

- ''Petición'': ''{ type: "req", id, method, params }''

- ''Respuesta'': ''{ type: "res", id, ok, payload | error }''

- ''Evento'': ''{ type: "event", event, payload, seq?, stateVersion? }''

El primer frame ''debe'' ser una petición ''connect''. Después, los clientes pueden llamar

métodos (ej. ''health'', ''send'', ''chat.send'') y suscribirse a eventos (ej.

''presence'', ''tick'', ''agent'').

Flujo de conexión (mínimo):

Terminal
Client                    Gateway
  |- res:hello-ok --|
  |<-|
  |->|
  |<-|

Métodos + eventos comunes:

| Categoría | Ejemplos | Notas |

-

| Core | ''connect'', ''health'', ''status'' | ''connect'' debe ser primero |

| Mensajes | ''send'', ''poll'', ''agent'', ''agent.wait'' | Efectos secundarios requieren ''idempotencyKey'' |

| Chat | ''chat.history'', ''chat.send'', ''chat.abort'', ''chat.inject'' | WebChat usa estos |

| Sesiones | ''sessions.list'', ''sessions.patch'', ''sessions.delete'' | Gestión de sesiones |

| Nodos | ''node.list'', ''node.invoke'', ''node.pair.*'' | Gateway WS + operaciones de nodo |

| Eventos | ''tick'', ''presence'', ''agent'', ''chat'', ''health'', ''shutdown'' | Push del servidor |

La lista autoritativa vive en ''src/gateway/server.ts'' (''METHODS'', ''EVENTS'').

Tutorial.step

Donde Viven los Esquemas

- Fuente: ''src/gateway/protocol/schema.ts''

- Validador runtime (AJV): ''src/gateway/protocol/index.ts''

- Handshake del servidor + despacho de métodos: ''src/gateway/server.ts''

- Cliente Node: ''src/gateway/client.ts''

- Esquema JSON generado: ''dist/protocol.schema.json''

- Modelos Swift generados: ''apps/macos/Sources/OpenClawProtocol/GatewayModels.swift''

Tutorial.step

Pipeline Actual

- ''pnpm protocol:gen''

- Escribe esquema JSON (draft 07) a ''dist/protocol.schema.json''

- ''pnpm protocol:gen:swift''

- Genera modelos Swift del gateway

- ''pnpm protocol:check''

- Ejecuta ambos generadores y verifica que la salida esté commiteada

Tutorial.step

Cómo el Runtime Usa los Esquemas

- Lado servidor: Cada frame entrante se valida via AJV. Solo el handshake

acepta una petición ''connect'' con params que coinciden con ''ConnectParams''.

- Cliente: El cliente JS valida frames de evento y respuesta antes de

usarlos.

- ''Superficie de métodos'': El gateway anuncia ''methods'' y

''events'' soportados en ''hello-ok''.

Tutorial.step

Framework de Ejemplo

Conexión (primer mensaje):

Json
{
  "type": "req",
  "id": "c1",
  "method": "connect",
  "params": {
    "minProtocol": 2,
    "maxProtocol": 2,
    "client": {
      "id": "openclaw-macos",
      "displayName": "macos",
      "version": "1.0.0",
      "platform": "macos 15.1",
      "mode": "ui",
      "instanceId": "A1B2"
    }
  }
}

Respuesta hello-ok:

Json
{
  "type": "res",
  "id": "c1",
  "ok": true,
  "payload": {
    "type": "hello-ok",
    "protocol": 2,
    "server": { "version": "dev", "connId": "ws-1" },
    "features": { "methods": ["health"], "events": ["tick"] },
    "snapshot": {
      "presence": [],
      "health": {},
      "stateVersion": { "presence": 0, "health": 0 },
      "uptimeMs": 0
    },
    "policy": { "maxPayload": 1048576, "maxBufferedBytes": 1048576, "tickIntervalMs": 30000 }
  }
}

Petición + Respuesta:

Json
{ "type": "req", "id": "r1", "method": "health" }
Json
{ "type": "res", "id": "r1", "ok": true, "payload": { "ok": true } }

Evento:

Json
{ "type": "event", "event": "tick", "payload": { "ts": 1730000000 }, "seq": 12 }
Tutorial.step

Cliente Mínimo (Node.js)

Flujo mínimo útil: connect + health.

Ts
import { WebSocket } from "ws";

const ws = new WebSocket("ws://127.0.0.1:18789");

ws.on("open", () => {
  ws.send(
    JSON.stringify({
      type: "req",
      id: "c1",
      method: "connect",
      params: {
        minProtocol: 3,
        maxProtocol: 3,
        client: {
          id: "cli",
          displayName: "example",
          version: "dev",
          platform: "node",
          mode: "cli",
        },
      },
    }),
  );
});

ws.on("message", (data) => {
  const msg = JSON.parse(String(data));
  if (msg.type === "res" && msg.id === "c1" && msg.ok) {
    ws.send(JSON.stringify({ type: "req", id: "h1", method: "health" }));
  }
  if (msg.type === "res" && msg.id === "h1") {
    console.log("health:", msg.payload);
    ws.close();
  }
});
Tutorial.step

Ejemplo Práctico: Agregar un Método End-to-End

Ejemplo: Agregar una nueva petición ''system.echo'' que retorna ''{ ok: true, text }''.

1. Esquema (fuente de verdad)

Agregar a ''src/gateway/protocol/schema.ts'':

Ts
export const SystemEchoParamsSchema = Type.Object(
  { text: NonEmptyString },
  { additionalProperties: false },
);

export const SystemEchoResultSchema = Type.Object(
  { ok: Type.Boolean(), text: NonEmptyString },
  { additionalProperties: false },
);

Agregar ambos a ''ProtocolSchemas'' y exportar tipos:

Ts
SystemEchoParams: SystemEchoParamsSchema,
  SystemEchoResult: SystemEchoResultSchema,
Ts
export type SystemEchoParams = Static<typeof SystemEchoParamsSchema>;
export type SystemEchoResult = Static<typeof SystemEchoResultSchema>;

2. Validación

En ''src/gateway/protocol/index.ts'', exportar validadores AJV:

Ts
export const validateSystemEchoParams = ajv.compile<SystemEchoParams>(SystemEchoParamsSchema);

3. Comportamiento del servidor

Agregar un handler en ''src/gateway/server-methods/system.ts'':

Ts
export const systemHandlers: GatewayRequestHandlers = {
  "system.echo": ({ params, respond }) => {
    const text = String(params.text ?? "");
    respond(true, { ok: true, text });
  },
};

Registrarlo en ''src/gateway/server-methods.ts'' (''systemHandlers'' merged),

luego agregar ''"system.echo"'' a ''METHODS'' en ''src/gateway/server.ts''.

4. Regeneración

Bash
pnpm protocol:check

5. Test + Docs

Agregar tests del servidor en ''src/gateway/server.*.test.ts'' y notar el método en docs.

Tutorial.step

Swift Code Generation Behavior

Swift generator emits:

- ''GatewayFrame'' enum with ''req'', ''res'', ''event'', and ''unknown'' cases

- Strongly-typed payload structs/enums

- ''ErrorCode'' values and ''GATEWAY_PROTOCOL_VERSION''

Unknown frame types are preserved as raw payloads for forward compatibility.

Tutorial.step

Versioning + Compatibility

- ''PROTOCOL_VERSION'' lives in ''src/gateway/protocol/schema.ts''.

- Client sends ''minProtocol'' + ''maxProtocol''; server rejects mismatches.

- Swift models preserve unknown frame types to avoid breaking older clients.

Tutorial.step

Schema Patterns and Conventions

- Most objects use ''additionalProperties: false'' for strict payloads.

- ''NonEmptyString'' is the default for IDs and method/event names.

- Top-level ''GatewayFrame'' uses a ''discriminator'' on ''type''.

- Methods with side effects typically require ''idempotencyKey'' in params

(e.g.: ''send'', ''poll'', ''agent'', ''chat.send'').

Tutorial.step

Live Schema JSON

El esquema JSON generado está en el repositorio en ''dist/protocol.schema.json''. El

published raw file is typically available at:

- https://raw.githubusercontent.com/openclaw/openclaw/main/dist/protocol.schema.json

Tutorial.step

When You Change a Schema

1. Update TypeBox schema.

2. Run ''pnpm protocol:check''.

3. Commit regenerated schema + Swift models.