> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fased.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# TypeBox

# TypeBox as protocol source of truth

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 app. One source of truth; everything else is generated.

If you want the higher-level protocol context, start with
[Gateway architecture](/concepts/architecture).

## Mental model (30 seconds)

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? }`

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
  |---- req:connect -------->|
  |<---- res:hello-ok --------|
  |<---- event:tick ----------|
  |---- req:health ---------->|
  |<---- res:health ----------|
```

Common methods + events:

| Category  | Examples                                                  | Notes                              |
| --------- | --------------------------------------------------------- | ---------------------------------- |
| Core      | `connect`, `health`, `status`                             | `connect` must be first            |
| Messaging | `send`, `poll`, `agent`, `agent.wait`                     | side-effects need `idempotencyKey` |
| Chat      | `chat.history`, `chat.send`, `chat.abort`, `chat.inject`  | WebChat uses these                 |
| Sessions  | `sessions.list`, `sessions.patch`, `sessions.delete`      | session admin                      |
| Nodes     | `node.list`, `node.invoke`, `node.pair.*`                 | Gateway WS + node actions          |
| Events    | `tick`, `presence`, `agent`, `chat`, `health`, `shutdown` | server push                        |

The authoritative method/event lists are composed from
`src/gateway/server-methods-list.ts` plus channel/plugin method registries.

## Where the schemas live

* Source: `src/gateway/protocol/schema.ts` and
  `src/gateway/protocol/schema/*`
* Runtime validators (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/FasedAgentProtocol/GatewayModels.swift` and
  `apps/shared/FasedAgentKit/Sources/FasedAgentProtocol/GatewayModels.swift`

## Current pipeline

* `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 the output is committed

## How the schemas are used at runtime

* **Server side**: every inbound frame is validated with AJV. The handshake only
  accepts a `connect` request whose params match `ConnectParams`.
* **Client side**: the JS client validates event and response frames before
  using them.
* **Method surface**: the Gateway advertises the supported `methods` and
  `events` in `hello-ok`.

## Example frames

Connect (first message):

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "type": "req",
  "id": "c1",
  "method": "connect",
  "params": {
    "minProtocol": 3,
    "maxProtocol": 3,
    "client": {
      "id": "fased-macos",
      "displayName": "macos",
      "version": "1.0.0",
      "platform": "macos 15.1",
      "mode": "ui",
      "instanceId": "A1B2"
    }
  }
}
```

Hello-ok response:

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "type": "res",
  "id": "c1",
  "ok": true,
  "payload": {
    "type": "hello-ok",
    "protocol": 3,
    "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:

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{ "type": "req", "id": "r1", "method": "health" }
```

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{ "type": "res", "id": "r1", "ok": true, "payload": { "ok": true } }
```

Event:

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{ "type": "event", "event": "tick", "payload": { "ts": 1730000000 }, "seq": 12 }
```

## Adding a method

For a new Gateway method:

1. Add params/result schemas under `src/gateway/protocol/schema/*`.
2. Export them through `ProtocolSchemas` and generated TypeScript types.
3. Compile any needed AJV validator in `src/gateway/protocol/index.ts`.
4. Add the handler under `src/gateway/server-methods/*`.
5. Add the method name to `src/gateway/server-methods-list.ts` or the
   appropriate channel/plugin registry.
6. Regenerate and verify:

```bash theme={"theme":{"light":"min-light","dark":"min-dark"}}
pnpm protocol:check
```

7. Add server/protocol tests and update docs when the method is public.

## Swift codegen behavior

The 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.

## Versioning + compatibility

* `PROTOCOL_VERSION` lives in `src/gateway/protocol/schema.ts`.
* Clients send `minProtocol` + `maxProtocol`; the server rejects mismatches.
* The Swift models keep unknown frame types to avoid breaking older clients.

## Schema patterns and conventions

* Most objects use `additionalProperties: false` for strict payloads.
* `NonEmptyString` is the default for IDs and method/event names.
* The top-level `GatewayFrame` uses a **discriminator** on `type`.
* Methods with side effects usually require an `idempotencyKey` in params
  (example: `send`, `poll`, `agent`, `chat.send`).

## Live schema JSON

Generated JSON Schema is in the repo at `dist/protocol.schema.json`. The
published raw file is typically available at:

* [Generated protocol schema](https://raw.githubusercontent.com/fased-ai/fased/main/dist/protocol.schema.json)

## When you change schemas

1. Update the TypeBox schemas.
2. Run `pnpm protocol:check`.
3. Commit the regenerated schema + Swift models.
