Repository navigation
Reset the protocol format - #13
Merged
Merged
Conversation
gliff hasn't shipped, so settle a wire format that later releases can extend without breaking each other. postcard is positional, so any new field or message broke every older peer. Messages are now CBOR via minicbor, with every variant and field numbered and encoded as arrays: unknown fields are ignored, absent optional ones decode as None, and names never reach the wire. The frame header carries the payload length too, so a reader skips a message it does not know, payload and all, and the writer refuses frames the reader would reject. The handshake exchanges feature lists; anything new goes only to a peer that listed its feature. The rules for future changes are at the top of gliff-proto's msg.rs. The protocol version starts over at 1. The server reads Hello's version before the rest, so a mismatch is always reported, and it refuses a client with no codec or chroma mode in common before setting anything up. Error codes 1 to 255 mean the ends cannot work together: the client says which end is too old and stops reconnecting.
The writer task stopped on its first error without telling anyone, so input and frame acks went nowhere while the session looked alive.
An offer of 10,000 long paths could exceed the 1 MiB frame body limit. Cap the summed path length, so the largest offer the other caps allow still fits.
kevinmcconnell
force-pushed
the
protocol-version-1
branch
from
September 23, 2026 22:44
d746fff to
9af13ca
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
gliff hasn't shipped, so this is the moment to settle a wire format we can
evolve after release without breaking peers from other builds. Nothing here
is compatible with earlier builds, and that's intended; the version starts
over at 1.
What changes
message broke every older peer. Messages are now CBOR via
minicbor, withevery variant and field numbered (
#[n]) and encoded as arrays. Unknownfields are ignored, absent optional ones decode as
None, and renamesnever touch the wire.
u32 body_len | u32 payload_len, so areader skips a message it doesn't know, payload and all. An unknown value
inside a known message still fails, since the rules forbid sending one.
ClientCapsandHelloAck. Anything new goes onlyto a peer that listed the feature introducing it.
FEATURESis emptytoday.
PROTOCOL_VERSIONis 1. The server reads Hello'sversion before the rest, so a mismatch is reported even when a future
Hello has changed shape. The client shows "Client version is too old" or
"Server version is too old" and stops auto-reconnecting; error codes 1-255
are all treated as incompatible this way.
Errorcarries the server'sversion.
its codec and chroma lists drop values this build doesn't know. Optional
enum fields use a helper, because minicbor's own
Optiondecoding misreadsthe next field on an unknown value.
and file offers cap their summed path length so the largest fits in a
frame.
The rules for future changes are at the top of
crates/gliff-proto/src/msg.rs;PROTOCOL_VERSIONonly changes for a breakthey can't absorb.
Cost
Measured against postcard over whole sessions, video included: +0.02% on a
30 s LAN bench, +0.09% in
scripts/e2e.sh, +0.35% on the 30 s satellitebench (2.5 Mbit/s, 550 ms, 10% loss). A
VideoFrameheader body is 32 bytesand a
FrameAck15.Why this format
minicboroverciborium:minicboris actively released and is whatAWS's
aws-smithy-cboruses in production.ciboriumhasn't releasedsince January 2024, and most of its downloads come in via
criterion.capability sets, and avoids RFB's weakness where an unknown message ends
the session. Protobuf evolves as well but needs codegen and conversion
layers, which isn't worth it with Rust at both ends.
Review
Two rounds of independent review (Codex and a Fable agent). Their findings
are folded in: Hello's version read first, the
Optionenum pitfall, required fields documented as permanent, the serverchecking codecs before any setup, and writer-side limits. Two fixes they
found outside the format have their own commits: a client writer that
failed silently, and a clipboard offer cap.
For the macOS client (#5):
Hello.keymapstays XKB text or empty. Layoutnames can arrive later in a new optional field, which older servers ignore
and fall back to their default keymap.
Testing
Golden bytes pin the frame layout and key messages. Tests cover a Hello
from another version, messages from a newer peer, skipped and nested
unknowns, limits, and
read_msgresuming after cancellation. Clippy, theunit tests and
scripts/e2e.shpass on AMD RADV.