Mental model (30 sec)
Every Gateway WS message is one of three frames:- Request:
{"type": "req", "id", "method", "params"} - Response:
{"type": "res", "id", "ok", "payload | error"} - Event:
{"type": "event", "event", "payload", "seq?", "stateVersion?"}
connect request. After that, clients can call methods (for example health, send, chat.send) and subscribe to events (for example presence, tick, agent).
Connection flow (minimal example):
| Category | Examples | Notes |
|---|---|---|
| Core | connect, health, status | connect must be first |
| Messaging | send, agent, agent.wait, system-event, logs.tail | Side effects require idempotencyKey |
| Chat | chat.history, chat.send, chat.abort | Used by WebChat |
| Sessions | sessions.list, sessions.patch, sessions.delete | Session management |
| Automation | wake, cron.list, cron.run, cron.runs | Wake + scheduled task control |
| Nodes | node.list, node.invoke, node.pair.* | Gateway WS + node operations |
| Events | tick, presence, agent, chat, health, shutdown | Server push |
src/gateway/server-methods-list.ts (listGatewayMethods, GATEWAY_EVENTS).
Where the schemas live
- Source:
packages/gateway-protocol/src/schema.ts - Runtime validators (AJV):
packages/gateway-protocol/src/index.ts - Advertised feature/discovery registry:
src/gateway/server-methods-list.ts - Server handshake + method dispatch:
src/gateway/server.impl.ts - Node client:
src/gateway/client.ts - Generated JSON Schema:
dist/protocol.schema.json - Generated Swift models:
apps/macos/Sources/OpenClawProtocol/GatewayModels.swift
Current pipeline
pnpm protocol:gen- Writes JSON Schema (draft-07) to
dist/protocol.schema.json
- Writes JSON Schema (draft-07) to
pnpm protocol:gen:swift- Generates Swift gateway models
pnpm protocol:check- Runs both generators and verifies the output is committed
How these schemas are used at runtime
- Server: every incoming frame is validated with AJV. The handshake only accepts a
connectrequest whose params matchConnectParams. - Client: the JS client validates event and response frames before using them.
- Feature discovery: Gateway sends a conservative
features.methodsandfeatures.eventslist inhello-okfromlistGatewayMethods()andGATEWAY_EVENTS. - This discovery list is not a generative dump of every callable helper in
coreGatewayHandlers; some auxiliary RPC implementations live insrc/gateway/server-methods/*.tsbut are not published in the feature list.
Example frames
Connect (first message):Minimal client (Node.js)
Minimal usable flow: connect + health.Practical example: add a method end to end
Example: add a newsystem.echo request that returns { ok: true, text }.
- Schema (single source of truth)
packages/gateway-protocol/src/schema.ts:
ProtocolSchemas and export the types:
- Validation
packages/gateway-protocol/src/index.ts, export an AJV validator:
- Server behavior
src/gateway/server-methods/system.ts:
src/gateway/server-methods.ts (it already merges systemHandlers), then add "system.echo" to the listGatewayMethods input in src/gateway/server-methods-list.ts.
If the method is callable by operators or node clients, also classify it in src/gateway/method-scopes.ts so scope enforcement and hello-ok feature publication stay aligned.
- Regenerate
- Tests + docs
src/gateway/server.*.test.ts, and document the method.
Swift code generation behavior
The Swift generator outputs:GatewayFrameenum withreq,res,event, andunknowncases- Strongly typed payload structs/enums
ErrorCodevalues,GATEWAY_PROTOCOL_VERSION, andGATEWAY_MIN_PROTOCOL_VERSION
Versioning + compatibility
PROTOCOL_VERSIONlives inpackages/gateway-protocol/src/version.ts.- Clients send
minProtocol+maxProtocol; the server rejects ranges that do not include the current protocol. - The Swift models keep unknown frame types to avoid breaking older clients.
Schema patterns and conventions
- Most objects use
additionalProperties: falseto keep payloads strict. NonEmptyStringis the default choice for IDs and method/event names.- The top-level
GatewayFrameuses a discriminator ontype. - Methods with side effects typically require
idempotencyKeyin params (for examplesend,poll,agent,chat.send). agentaccepts optionalinternalEventsfor runtime-generated orchestration context (for example sub-agent/cron handoff completion); treat it as an internal API surface.
Live schema JSON
The generated JSON Schema lives indist/protocol.schema.json in the repo. The published raw file is usually available at:
When you change schemas
- Update the TypeBox schema.
- Register the method/event in
src/gateway/server-methods-list.ts. - Update
src/gateway/method-scopes.tswhen a new RPC needs operator or node scope classification. - Run
pnpm protocol:check. - Commit the regenerated schema + Swift models.