2.6 KiB
2.6 KiB
summary, read_when
| summary | read_when | |
|---|---|---|
| TypeBox schemas as the single source of truth for the gateway protocol |
|
TypeBox as Protocol Source of Truth
Last updated: 2025-12-09
We use TypeBox schemas in src/gateway/protocol/schema.ts as the single source of truth for the Gateway control plane (hello/req/res/event frames and payloads). All derived artifacts should be generated from these schemas, not edited by hand.
Current pipeline
- TypeBox → JSON Schema:
pnpm protocol:genwritesdist/protocol.schema.json(draft-07) and runs AJV in the server tests. - TypeBox → Swift (quicktype):
pnpm protocol:gencurrently also generatesapps/macos/Sources/ClawdisProtocol/Protocol.swiftvia quicktype. This produces a single struct with many optionals and is not ideal for strong typing.
Problem
- Quicktype flattens
oneOf/discriminatorinto an all-optional struct, so Swift loses exhaustiveness and safety forGatewayFrame.
Preferred plan (next step)
- Add a small, custom Swift generator driven directly by the TypeBox schemas:
- Emit a sealed
enum GatewayFrame: Codable { case hello(Hello), helloOk(HelloOk), helloError(...), req(RequestFrame), res(ResponseFrame), event(EventFrame) }. - Emit strongly typed payload structs/enums (
Hello,HelloOk,HelloError,RequestFrame,ResponseFrame,EventFrame,PresenceEntry,Snapshot,StateVersion,ErrorShape,AgentEvent,TickEvent,ShutdownEvent,SendParams,AgentParams,ErrorCode,PROTOCOL_VERSION). - Custom
init(from:)/encode(to:)enforces thetypediscriminator and can include anunknowncase for forward compatibility. - Wire a new script (e.g.,
pnpm protocol:gen:swift) intoprotocol:checkso CI fails if the generated Swift is stale.
- Emit a sealed
Why this path:
- Single source of truth stays TypeBox; no new IDL to maintain.
- Predictable, strongly typed Swift (no optional soup).
- Small deterministic codegen (~150–200 LOC script) we control.
Alternative (if we want off-the-shelf codegen)
- Wrap the existing JSON Schema into an OpenAPI 3.1 doc (auto-generated) and use swift-openapi-generator or openapi-generator swift5. More moving parts, but also yields enums with discriminator support. Keep this as a fallback if we don’t want a custom emitter.
Action items
- Implement
protocol:gen:swiftthat reads the TypeBox schemas and emits the sealed Swift enum + payload structs. - Update
protocol:checkto include the Swift generator output in the diff check. - Remove quicktype output once the custom generator is in place (or keep it for docs only).