Overview and framing
Zyris Protocol v1 — the normative wire reference. This page covers the transport and how frames are laid out.
This section is the normative reference for Zyris Protocol v1: what the bytes on the wire mean.
It is not a tutorial — start with the quickstart and come here when you need to
know exactly what happens. The source of truth is
docs/zyris-protocol.md
in the protocol repository.
In this section, node means the dialing peer and server the accepting peer. Every rule applies in both directions unless it says otherwise. Where the text describes something a deployment chooses rather than something the wire requires — credential formats, enrollment, cross-replica routing — it says so and uses Attacca as the worked example.
The key words MUST, MUST NOT and MAY are used in their RFC 2119 sense.
Transport
One websocket per connection, at:
wss://<host>/zyris/v1/wsTLS is mandatory. The URL path pins the protocol major version: a breaking envelope change
becomes /zyris/v2/ws.
Frames
Two classes of frame ride the socket. Every websocket binary frame begins with a one-byte kind tag:
| Tag | Name | Layout after the tag |
|---|---|---|
0x00 | CONTROL | A msgpack-encoded envelope. |
0x01 | STREAM_DATA | stream_id: u32 BE, chunk_seq: u32 BE, then raw payload bytes. |
0x02–0x0F | reserved | Receivers MUST close with 4408 on an unknown tag. |
chunk_seq starts at 0 for each stream and increases by 1 per chunk. On a direct connection TCP
makes it trivially contiguous; it exists so that a relayed hop can detect
loss. Any gap MUST fail the stream with stream_lagged — bytes past a gap are never delivered.
Serialization
| Mode | CONTROL envelopes | STREAM_DATA |
|---|---|---|
| msgpack (default) | Binary frames with tag 0x00. | Binary, tag 0x01. |
| json (negotiated) | Websocket text frames, no tag byte — the opcode discriminates. | Binary, tag 0x01. |
JSON mode exists for debuggability and browser-adjacent clients. Blob bytes never pass through msgpack or JSON encoding when they travel as STREAM_DATA. The mode is chosen in the handshake, which itself is always msgpack.
Limits
The server declares limits in hello_ack. Defaults:
| Limit | Default |
|---|---|
| Maximum CONTROL frame | 8 MiB — headroom above the 4 MiB inline-blob ceiling |
Maximum STREAM_DATA payload (max_chunk) | 256 KiB |
max_inflight_reqs | 64 |
initial_stream_credit | 256 KiB |
A violation is a protocol error: payload_too_large on the offending request, or connection close
4409 for a flow-control violation.
Sections
Messages
The envelope union: requests, responses, notes, progress, cancel and stream control.
Connection lifecycle
Auth, the handshake, heartbeat, close and reconnect.
Streams
Stream ids, transfer mechanisms, credit-based flow control, termination.
Capabilities
Announcing, revoking, reserving and versioning capabilities.
Datums and blobs
Text, file and image values, and when bytes travel as attachments.
Errors and close codes
The registered error codes and websocket close codes.