pub const PROTOCOL_VERSION: u32 = 31;Expand description
The protocol this server speaks.
Fixed rather than negotiated: the server and the core change far more slowly than a client’s visuals do, so a client either speaks this or it does not, and a mismatch fails plainly instead of silently.
Named here rather than in connection.rs so the socket’s recorded
contract is filed under it: a bump looks for a record directory that is
not there and fails, which is the honest answer for a client that would
refuse the connection anyway.
Renaming an update is a bump. A variant’s name is the tag it crosses
under, so a client that knows the old one narrows the frame to nothing and
drops it silently - which is what a version the server bumps exists to
prevent, since the skewed pair is real: the desktop client ships
separately from the binary. slack_draft_expired became
slack_draft_resolved, and baselines/socket/1/ keeps the older tag as
the record a v1 server emitted. Nothing reads a past version’s directory:
it is an archive, and its staleness is the point rather than a fault.
Removing an update is a bump too, and v3 is one. The peer surface
collapsed to agents__send_message, which retired
peer_inflight_stats_changed along with the per-seat counters and the two
agent-row fields that carried them: a subscriber that still expects the
variant would wait for a badge that never moves again. baselines/socket/2/
is the record a v2 server emitted.
v4 is a bump for the greet’s settings and for the binary path. The
greeting’s settings gains the [dictate] axes a capturing client starts
on, Command gains dictate_stream, and the socket now takes binary
messages as dictation frames - a whole message kind a v3 client has no
vocabulary for. baselines/socket/3/ is the record a v3 server emitted.
v5 is a bump for the take’s owner. A take belongs to the connection
that started it: every Dictate* update is forwarded to that connection
alone, a second take on the seat is refused by name, and a connection
going away DROPS its take rather than submitting what arrived. The
record’s composer loses its take and notice for the same reason -
a take’s meter, phases and words are not a fact any other reader may
draw. baselines/socket/4/ is the record a v4 server emitted.
v6 is a bump for the browser’s ask and answer. The socket gains its
first request in the server-to-client direction: browser_ask carries one
tool call to whichever client holds the browser role, browser_answer
carries the result back under the same id, and a subscription declares
whether a client can host that role at all. A second binary frame kind
joins the dictation frames - a browser answer’s image bytes, under its
answer’s id - so a client with no vocabulary for any of it would read
frames as nothing rather than as news. baselines/socket/5/ is the record
a v5 server emitted.
v7 is a bump for the browser’s hand-off field and for the models read’s
own shape. The hand-off’s context is renamed profile, and a
proposal’s candidate is now candidates, ranked rows rather than the
one the server picked, while the in-use row’s sha256 is nullable where
an installed model publishes none. The first two are renames a v6 client
reads as nothing, and the third is a value it dereferences (slice), so a
same-version skew is a client that throws while drawing rather than one
that shows less. baselines/socket/6/ is the record a v6 server emitted.
v8 is a bump for the board’s own read. A project’s tasks is renamed
rows - each row is its task plus worked time, ages and marks - a row’s
estimate is an object where a v7 server sent a string, and artifact is
gone, folded into links. The rename is what makes this a bump rather than
an addition: a v7 client reads row.tasks.map(...) and throws on
undefined while DRAWING, so a same-version skew would be a page that
never lands rather than one that shows less. baselines/socket/7/ is the
record a v7 server emitted.
v9 is a bump for the board’s own subject (#2517). A project’s rows,
crons and connectors left the home’s project row for a board subject
of their own, and the home’s fleet rows gained rows for the header’s
total. Both directions break silently on a same-version skew: a v9 client
asking a v8 server for board gets that subject back as an unknown
message, and a v8 client reading a v9 home finds no rows, crons or
connectors under its projects - it draws an empty board and a zero total
until the greeting’s version turns it into the notice.
baselines/socket/8/ is the record a v8 server emitted.
v10 is a bump for the browser’s move to the server. The browser role
and its ask/answer pair are gone: a client attaches to a profile’s
browser as a viewer, sends gestures and takes the controller role, and
receives encoded frames as binary messages. A v9 client would send
browser_answer to a server that never asks, and the two would sit
across the socket unable to drive a browser at all.
baselines/socket/9/ is the record a v9 server emitted.
v11 is a bump for the browser’s tabs. A viewer attaches to a tab
rather than a profile, the profile verbs are gone, and a strip reads a
browser_tabs list instead of browser_profiles. A v10 client would
send browser_profiles and a profile name a v11 server no longer
answers, and would pair every surface state against the wrong tab.
baselines/socket/10/ is the record a v10 server emitted.
The tab on a file ask and on a download are additive fields under v11: a
v11 client ignores what it does not know, so no reader is left holding a
value it cannot draw, and the version stays.
v12 is a bump for the client’s showing message. A seat’s diamond,
failure mark and death trace are spent by the seat being shown on screen,
not by a subscription to it, so a client that keeps every visited seat
subscribed spends nothing until the reader opens one. Both directions
break silently on a same-version skew: a v11 server reads showing as a
message it does not know and answers an error naming client_message,
and a v12 server beside a v11 client never learns what is on screen, so
no seat is ever attached and no mark is ever spent - the rail keeps
diamonds the reader has already looked at. baselines/socket/11/ is the
record a v11 server emitted.
v13 is a bump for a hand-off’s answer. The answer carries what it
means, the door in the client that sent it and the connection that
carried it, in place of the bare done flag. A v12 client’s answer names
only done and cannot be decoded, so nothing refuses the connection
(the endings it draws are ignored safely), and its answer comes back as
a dispatch refusal, which a client draws where the answer came from: the
command frame is recognised by its kind even when its body no longer
parses, so the person is told the prompt is still waiting instead of
losing the answer to the console. baselines/socket/12/ is the record a
v12 server emitted.
v14 is a bump for a web client’s perf batch. client_perf carries the
records a page measures, so a client with no shell to write them still
produces its own diagnostics. It shares a number with nothing: v13 was
already the hand-off answer’s, and two schemas cannot answer to one
protocol. A v13 server reads the batch as a message it does not know and
answers an error naming client_message, which the page’s own error
path takes as a refused subscribe: an in-flight read can be marked
refused while the connection stays up. baselines/socket/13/ is the
record a v13 server emitted.
v15 is a bump for the browser frame’s header. It grew from 14 to 18
bytes: the page’s own viewport rides beside the encoded pixels, so a
viewer maps a gesture through the picture it draws rather than sending it
1:1 into a page laid out at another shape. A v14 client splits the header
at the old offsets and reads the four new bytes as the head of the WebP,
so its decoder fails and the surface draws nothing at all - a silent
blank, which is exactly what the greeting’s version is for.
baselines/socket/14/ is the record a v14 server emitted.
v16 is a bump for a renamed composer field. The record’s
composer.compacting became composer.machine, which names a handoff
beside a compaction. A v15 client reads no compacting and draws a live
composer through a compaction it cannot see - the same silent wrong state
a growing header caused at v15, reached by a rename instead. The new
client reads the old name as a fallback, so a v15 server beside it still
stands the box down; the bump is what tells an old client its server has
moved. baselines/socket/15/ is the record a v15 server emitted.
v17 is a bump for the replay sub-protocol’s removal. The transport’s
held copy is the one conversation a seat has: HistoryReplayed and the
ReplayConversation command it answered are gone, and AuthRequired
goes with the event that never produced it. A v16 client holds both names
in its replace list and its composer record; neither frame arrives, so it
draws a seat that never re-reads rather than one that breaks - which is
why the bump, not the client’s decode, is what tells it the server moved.
v18 is a bump for the settings frame. settings carries the whole
effective config, pushed once after the greeting and again after every
applied reload. A v18 client’s settings page waits for it, so a v17
server’s silence would draw as a page that never loads rather than as a
version skew; the bump is what names the mismatch. baselines/socket/17/
is the record a v17 server emitted.
v20 adds the liveness pair. ping and pong are new variants rather
than fields, and a server older than them answers a probe as a message it
does not know - one error frame per probe - so the numbers move.
v21 is a bump for the settings editor. settings_edit is a batched
save and settings_refused is the frame that answers one that wrote
nothing; a v20 server reads the save as a message it does not know and
answers an error no page can attribute, and a v20 client would not read
the refusal. baselines/socket/20/ is the record a v20 server emitted.
v22 opens a hand-off by page. browser_view_page is a new variant, and
a v21 server reads it as a message it does not know: a hand-off whose tab
number outlived its host would fail to open at all rather than open the
wrong tab, so the numbers move. baselines/socket/21/ is the record a v21
server emitted.
v23 takes a voice preview. voice_preview is a new command variant,
and a v22 server reads it as a message it does not know: a page that asked
to hear a voice would be answered by an error rather than by one. The
speaking read’s fields ride along without moving the number, because a
client older than them draws the role it always drew. baselines/socket/22/
is the record a v22 server emitted.
v24 answers a document hand-off explicitly and lands its threads. A
hand-off ends on approve or feedback with a note rather than a bare
done, and a document read’s threads carry the resolution that places
each one in the document as it reads now. A v23 client already ignores a
field it does not know, so the landing rides along; the ENDING is the
break - it reads approve as a command answer no page can attribute -
and the two halves move together. baselines/socket/23/ is the record a
v23 server emitted.
v25 is a bump for the Slack draft’s answer. respond_slack_post
carries an answer now rather than a boolean: the reader can send a held
draft back with words for the agent, and slack_draft_resolved gains the
sent_back ending. The draft’s payload replaces tool with operation,
because one slack__edit is a replacement or a deletion and one
slack__react adds or removes - a card words its verbs from what will
happen. A v24 server reads the new payload as a command it cannot decode,
and a v24 client sends the old one this server refuses, so the numbers
move. baselines/socket/24/ is the record a v24 server emitted.
v26 holds a config write for the reader. respond_settings_write is a
new command variant, and the settings MCP tools park a write as a
settings_write_pending update a v25 client has no vocabulary for: it
would read the parked write as nothing, and the agent’s call would wait on
a dock nobody draws. baselines/socket/25/ is the record a v25 server
emitted.
v27 drops the handoff row from the conversation record and the prompt
origin from the wire. The record’s handoff field was what a client
drew the block from; the block is gone, so the field goes with it - a v26
client reading a v27 record draws no block from it, and one that watches
the swap still receives the handoff update and draws its own block from
that, because it is the old client - though the record no longer carries
the judgment turn, which only that block read. ChatAppended.origin and
PromptUnder.origin were the dispatch-time row’s bookkeeping; the row is
drawn when the CLI takes the prompt (started), which can be inside the
running turn when the CLI absorbs it, so nothing carries an origin. A v26
client reads both fields as absent; its dispatch row and its echo are that
client’s own code, and a core-answered command leaves its echo standing
because that client has no answered-command set.
baselines/socket/26/ is the record a v26 server emitted.
The held Slack draft’s new fields did not need a v28. thread and
tagged are additive under the rule below: a v27 client ignores them and
draws the raw ts it always drew, so baselines/socket/27/ is re-recorded
in place rather than a v28 directory being cut.
v28 holds a vault call for the reader. respond_vault_ask is a new
command variant, and the vault family parks a call as a
vault_ask_pending update with a vault_ask_resolved ending that a v27
client has no vocabulary for: it would read the parked call as nothing,
and the agent’s call would wait on a dock nobody draws.
v28 also adds the terminal’s binary kinds and commands. A v27 client
reads tag 4 as an unknown binary frame, reports it and drops it, which is
a silent blank surface rather than a refusal - the same ground v4 named
for dictation’s binary kind. The attach, detach, resize, pause and close
messages, the respond_terminal_hand_off command and the terminal
field on the session record ride with it.
baselines/socket/28/ is the record a v28 server emitted.
v29 moves a held settings write to a batch. settings_write_pending’s
ask carries edits, one entry per key, where a v28 client reads the
flat key, current, proposed and unset and draws an empty card it
could approve blind. baselines/socket/29/ is the record a v29 server
emitted.
v30 adds the biometric proxy’s server surface. The app-level
biometric_enrol, the update-only biometric_rewrite, biometric_release,
biometric_revoke and vault_enrolment_material commands, the app-level
vault_lock, and the
slot-less biometric_enrolments_changed, vault_rotated and
vault_lock_changed updates. A v29 server cannot decode the commands at
all, and a v29 client has no vocabulary for the updates: a settings page
beside a v29 server would draw no enrolment list and would never learn one
changed, and no client would rewrite its sealed bytes or follow a lock.
baselines/socket/30/ is the record a v30 server emitted.
v31 names every ask kind. A roster row’s pending was question,
permission or hand_off; it is now one kind per ask source, so the
needs-you line can say what the seat actually waits on: slack_draft,
browser_hand_off, terminal_hand_off, document_hand_off,
settings_write and vault replace the shared hand_off. A v30 page
narrows each new spelling to permission and draws the wrong words, and
a v30 shell refuses the row outright and drops that seat’s notification;
the old hand_off is gone, so the two halves move together.
baselines/socket/31/ is the record record_dir() requires for the
current version - it is byte-identical to 30 because the census holds
enum and field names rather than values, so it does not itself evidence
the widened kind.
Additive fields do not bump. diff.base_error is one, carried on the
v16-era record: a client older than the field draws the vaguer line it
always drew, and nothing it sends changes.