TypeBox
TypeBox スキーマを Gateway プロトコルの単一の真実(SSOT)として扱います。
Last updated: 2026-01-10
TypeBox is a TypeScript-first schema library. We use it to define the **Gateway
WebSocket protocol** (handshake, request/response, server events). Those schemas
drive runtime validation, JSON schema export, and Swift codegen for the
macOS application. One source of truth; everything else is generated.
If you want a higher-level protocol context, start from
メンタルモデル(30秒)
Every gateway WS message is one of three frames:
- ''Request'': ''{ type: "req", id, method, params }''
- ''Reply'': ''{ type: "res", id, ok, payload | error }''
- ''Event'': ''{ type: "event", event, payload, seq?, stateVersion? }''
The first frame ''must'' be a ''connect'' request. After that, clients can call
methods (e.g. ''health'', ''send'', ''chat.send'') and subscribe to events (e.g.
''presence'', ''tick'', ''agent'').
Connection flow (minimal):
Client Gateway |- res:hello-ok --| |<-| |->| |<-|
Common methods + events:
| Category | Examples | Notes |
-
| Core | ''connect'', ''health'', ''status'' | ''connect'' must be first |
| Messages | ''send'', ''poll'', ''agent'', ''agent.wait'' | Side effects require ''idempotencyKey'' |
| Chat | ''chat.history'', ''chat.send'', ''chat.abort'', ''chat.inject'' | WebChat uses these |
| Sessions | ''sessions.list'', ''sessions.patch'', ''sessions.delete'' | Session management |
| Nodes | ''node.list'', ''node.invoke'', ''node.pair.*'' | Gateway WS + node operations |
| Events | ''tick'', ''presence'', ''agent'', ''chat'', ''health'', ''shutdown'' | Server push |
The authoritative list lives in ''src/gateway/server.ts'' (''METHODS'', ''EVENTS'').
スキーマの場所
- Source: ''src/gateway/protocol/schema.ts''
- Runtime validator (AJV): ''src/gateway/protocol/index.ts''
- Server handshake + method dispatch: ''src/gateway/server.ts''
- Node client: ''src/gateway/client.ts''
- Generated JSON schema: ''dist/protocol.schema.json''
- Generated Swift models: ''apps/macos/Sources/OpenClawProtocol/GatewayModels.swift''
現在のパイプライン
- ''pnpm protocol:gen''
- Writes JSON schema (draft 07) to ''dist/protocol.schema.json''
- ''pnpm protocol:gen:swift''
- Generates Swift gateway models
- ''pnpm protocol:check''
- Runs both generators and verifies output is committed
ランタイムがスキーマを使用する方法
- Server-side: Every inbound frame is validated via AJV. Only handshake
accepts a ''connect'' request with params matching ''ConnectParams''.
- Client: JS client validates event and response frames before
using them.
- ''Method surface'': Gateway advertises supported ''methods'' and
''events'' in ''hello-ok''.
例のフレームワーク
Connection (first message):
{
"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"
}
}
}Hello-ok response:
{
"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 }
}
}Request + Response:
{ "type": "req", "id": "r1", "method": "health" }{ "type": "res", "id": "r1", "ok": true, "payload": { "ok": true } }Event:
{ "type": "event", "event": "tick", "payload": { "ts": 1730000000 }, "seq": 12 }最小クライアント (Node.js)
Minimal useful flow: connect + health.
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();
}
});動作例:エンドツーエンドメソッドの追加
Example: Add a new ''system.echo'' request that returns ''{ ok: true, text }''.
1. Schema (source of truth)
Add to ''src/gateway/protocol/schema.ts'':
export const SystemEchoParamsSchema = Type.Object(
{ text: NonEmptyString },
{ additionalProperties: false },
);
export const SystemEchoResultSchema = Type.Object(
{ ok: Type.Boolean(), text: NonEmptyString },
{ additionalProperties: false },
);Add both to ''ProtocolSchemas'' and export types:
SystemEchoParams: SystemEchoParamsSchema, SystemEchoResult: SystemEchoResultSchema,
export type SystemEchoParams = Static<typeof SystemEchoParamsSchema>; export type SystemEchoResult = Static<typeof SystemEchoResultSchema>;
2. Validation
In ''src/gateway/protocol/index.ts'', export AJV validators:
export const validateSystemEchoParams = ajv.compile<SystemEchoParams>(SystemEchoParamsSchema);
3. Server behavior
Add a handler in ''src/gateway/server-methods/system.ts'':
export const systemHandlers: GatewayRequestHandlers = {
"system.echo": ({ params, respond }) => {
const text = String(params.text ?? "");
respond(true, { ok: true, text });
},
};Register it in ''src/gateway/server-methods.ts'' (merged ''systemHandlers''),
then add ''"system.echo"'' to ''METHODS'' in ''src/gateway/server.ts''.
4. Regeneration
pnpm protocol:check
5. Test + Docs
Add server tests in ''src/gateway/server.*.test.ts'' and note the method in docs.
Swift コード生成動作
Swift generator emits:
- ''GatewayFrame'' enum with ''req'', ''res'', ''event'', and ''unknown'' cases
- Strongly-typed payload structs/enums
- ''ErrorCode'' values and ''GATEWAY_PROTOCOL_VERSION''
未知のフレームタイプは前方互換性のために生ペイロードとして保持されます。
バージョニング+互換性
- ''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.
スキーマパターンと規約
- 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'').
ライブスキーマ JSON
The generated JSON schema is committed in the repo at ''dist/protocol.schema.json''. The
published raw file is typically available at:
- https://raw.githubusercontent.com/openclaw/openclaw/main/dist/protocol.schema.json
スキーマを変更する場合
1. Update TypeBox schema.
2. Run ''pnpm protocol:check''.
3. Commit regenerated schema + Swift models.