## What Problem This Solves Config, protocol and tool definitions retain unused type inventories and repeat contracts already owned by shared schemas. ## User Impact No user-visible behavior change. Configuration keys, defaults, validation errors, protocol output, plugin manifests and model-facing tool descriptors are preserved. This removes 457 net production lines across 53 production files. ## Why This Change Was Made - Delete 79 unused config type declarations and their unused imports after tracing internal references, SDK facades, root library exports and retirement history. Live fields remain in the canonical inferred config types. Inline the newly orphaned approval-target alias at its sole use. - Use the existing `closedObject` owner for 49 protocol object constructors, preserving each field list and its order. - Infer recovery-step vocabulary and tool/config projections from their existing owners; reuse the existing thinking-level tuple and session-link description owner. - Share channel-path classification between hint and tier generation, and compose Matrix preview config from the existing streaming primitive. No new tests, dependencies, configuration options, public SDK exports or compatibility paths are introduced. ## Evidence - Independent Codex review through P2 found no actionable findings; the final reduced scope also received a clean P0–P2 review. - Blacksmith Testbox proof ([final lease run](https://github.com/openclaw/openclaw/actions/runs/36880055533)) compares separately installed base and candidate: seven full channel descriptors, 1,463 channel parse results, 72 session results, 16 constructed tool variants, protocol schema/validator captures, full config schema/UI hints, and 57 thinking-validation outcomes. Config comparison excludes only the response's volatile `generatedAt` timestamp. - The 199-file sibling selection passed across 20 shards in 194.96 seconds; 48 plugin-contract files / 1,132 tests passed. Final-scope affected checks and all plugin contracts passed again; both cycle checks report zero. - Protocol generation, base config schema, bundled channel metadata and SDK export registration checks preserve generated bytes. SDK surface/export checks pass. SDK API comparison reports zero entrypoint/direct-export changes and 229 reachable declaration-reference changes from the canonical types; this is not a claim of byte-identical declaration text. - Initial hosted CI caught a stale assertion-safety count: `connect-error-details.ts` now has 5 assertions, while its baseline still recorded 7. The exact shrink to 5 passed the ratchet, both zero-cycle checks, Matrix asset-hook check and scoped `check-changed` on a separately verified fresh PR checkout. Cancelled sibling CI jobs are not counted as passes. - The next hosted run identified the approval-target alias left exported after removing its two external aliases. Inlining the identical union passed both full knip passes, zero-cycle checks and two focused config suites (3 tests); independent P0–P2 review found no actionable issue. - Hosted CI on the repaired published head is the final test gate. Full-PR `check-changed` and a full build were not run; no tests or builds ran on the overloaded Mac. |
||
|---|---|---|
| .. | ||
| src | ||
| CHANGELOG.md | ||
| LICENSE | ||
| package.json | ||
| README.md | ||
@openclaw/gateway-protocol
Typed schemas, inferred TypeScript types, and runtime validators for the OpenClaw Gateway WebSocket protocol.
The current wire protocol is version 4. General clients must use v4; authenticated node clients and lightweight probes may use the N-1 window during rolling upgrades. See the Gateway protocol specification for transport, authentication, roles, scopes, and complete frame examples.
Versioning
Package versions follow the OpenClaw calendar release train:
YYYY.M.PATCH, with the same prerelease suffix when applicable. A package version
therefore identifies the OpenClaw source release that produced the schemas; it is
not the wire protocol number.
The wire protocol integer is versioned separately. Its current value is exported
as PROTOCOL_VERSION from @openclaw/gateway-protocol/version. Gateway protocol
changes are additive first. An incompatible wire change requires an explicit
protocol-version decision and coordinated client follow-through. See
CHANGELOG.md for the wire and schema history.
Install
Use the verified stable release with an exact pin:
npm install --save-exact @openclaw/gateway-protocol@2026.8.1
This release declares Node.js >=22.19.0. See the canonical
installation guide
for the matching client package, package/wire-version rules, and recovery from
reserved 0.0.0 artifacts. Test it with the Gateway version you deploy; the root
openclaw CLI has its own package versions and dist-tags.
Entry points
@openclaw/gateway-protocolexports runtime validators, selected schemas, error formatting, and their TypeScript types. This is the main TypeBox-backed entry.@openclaw/gateway-protocol/schemaexports the TypeBox schema graph, including theProtocolSchemasregistry used by generators.@openclaw/gateway-protocol/frame-guardsexports dependency-free structural guards for gateway event and response envelopes.@openclaw/gateway-protocol/client-infoexports client ID, mode, and capability registries plus normalization helpers.@openclaw/gateway-protocol/connect-error-detailsexports structured connect error readers and recovery metadata.@openclaw/gateway-protocol/gateway-error-detailsexports helpers for reading structured details from general gateway errors.@openclaw/gateway-protocol/startup-unavailableexports startup retry constants and helpers.@openclaw/gateway-protocol/versionexports the current and minimum accepted protocol versions.
The frame-guards, client-info, connect-error-details, gateway-error-details,
startup-unavailable, and version entry points are TypeBox-free. Prefer them when
a browser bundle only needs envelope dispatch, handshake constants, or reconnect
policy. This also avoids runtime compilation in CSP-sensitive consumers. The root
and schema entry points provide the full validation surface and depend on TypeBox.
Validate an inbound frame
The compiled validators are callable type guards. Their errors property contains
the most recent validation errors.
import { formatValidationErrors, validateRequestFrame } from "@openclaw/gateway-protocol";
const frame: unknown = JSON.parse(inboundText);
if (!validateRequestFrame(frame)) {
throw new Error(formatValidationErrors(validateRequestFrame.errors));
}
console.log(frame.id, frame.method);
validateRequestFrame validates the request envelope. Dispatch code must also use
the validator for the selected method's params; the root entry point exports those
validators as validate*Params functions.
External lifecycle controllers can validate suspension responses with
validateGatewaySuspendPrepareResult and validateGatewaySuspendStatusResult.
These use the canonical result schemas without changing the payload. Preserve
optional writeCustody: absence means unknown custody, not an empty list. Phase
names are open strings; consumers must not discard an unfamiliar owner phase.
Validation does not authorize a stop or replace lease, process-identity, and
readiness checks owned by the controller.
Leave includeLifecycle unset when using older published status validators.
Request includeLifecycle: true only with a validator that supports ownerId
and phase.
Guard an event without TypeBox
Use the lightweight guards when code only needs safe frame discrimination. They check dispatch-critical envelope fields and intentionally allow additive payload fields.
import { isGatewayEventFrame } from "@openclaw/gateway-protocol/frame-guards";
const frame: unknown = JSON.parse(inboundText);
if (isGatewayEventFrame(frame)) {
console.log(frame.event, frame.seq);
}
Build handshake version and capability fields
Protocol levels and client capabilities live in TypeBox-free entry points.
import { GATEWAY_CLIENT_CAPS } from "@openclaw/gateway-protocol/client-info";
import { MIN_CLIENT_PROTOCOL_VERSION, PROTOCOL_VERSION } from "@openclaw/gateway-protocol/version";
const handshake = {
minProtocol: MIN_CLIENT_PROTOCOL_VERSION,
maxProtocol: PROTOCOL_VERSION,
caps: [GATEWAY_CLIENT_CAPS.TOOL_EVENTS],
};
Nodes and probes use MIN_NODE_PROTOCOL_VERSION and
MIN_PROBE_PROTOCOL_VERSION, respectively. A capability advertises client support;
it does not grant authorization.
Contract notes
Retired worker tool imports
The WorkerSessionsSpawn*, WorkerSessionsSend*, WorkerSessionTool*,
WorkerPortal*, and WorkerPresence* schemas, types, root validators, and associated
feature/limit constants published in 2026.9.6 and 2026.9.7 remain available for decoding older data. They do
not register or advertise the retired worker RPCs. Current workers use the
prepared tool surface and worker.gatewayTool transport; migrate integrations to
WorkerGatewayTool*. These imports can be removed only in an explicitly announced
breaking package API release after consumer migration.
Session identifiers
Several identifier names coexist because they identify different things:
keyis the established logical session selector used by mostsessions.*CRUD, send, subscription, patch, reset, delete, compaction, and usage methods. A key can be canonicalized or resolved within an agent's session store.sessionKeynames the same logical routing identity where the contract needs to make that meaning explicit.chat.*, session file and diff APIs, transcript branch/rewind/fork APIs, agent events, and channel delivery payloads use this spelling.sessionIdis the opaque stored transcript or runtime instance ID. Session results may return it beside a key. Talk, terminal, worker, and selected channel protocols also usesessionIdfor their own concrete session instances; do not substitute a logical session key there.
Follow each method schema rather than converting fields based on their spelling.
sessions.resolve is the explicit bridge when a caller has a key, raw session ID,
label, Control UI short ID, or parent/agent scope.
Intentionally open fields
The schema graph is strict by default, but roughly 60 fields intentionally use
Type.Unknown() passthroughs. The main clusters are transport-owned channel
payloads, logs-chat message and attachment passthrough, worker and node tool
arguments/results, and the dynamic config.schema response. Frame params,
payload, and error details are also open at the envelope layer because the
selected method, event, or error code owns their concrete shape.
Do not treat these fields as validated domain objects. Narrow them at their owner boundary before reading nested values.
Machine-readable schema
protocol.schema.json
ships in the npm tarball as the generated machine-readable
contract. It contains the frame union, named schema definitions, and core method
metadata. It is generated during prepack and is not committed to the repository.
Download it as a file; @openclaw/gateway-protocol/protocol.schema.json is not an
exported package import subpath.
Method discovery
The hello-ok.features.methods list is conservative discovery, not a complete
enumeration of every callable method. It reflects the methods the connected
Gateway intentionally advertises. Core-internal, role-specific, plugin-provided,
or otherwise non-advertised methods can have valid schemas without appearing in
that list. Clients should use discovery to enable optional UI, not to reject an
otherwise documented method contract.