3.6 Binding

3.6.1 One conversation per connection #

A connection carries at most one conversation, for its whole life. There is no multiplexing: a surface that wants two conversations opens two connections, and closing the connection is how a surface detaches. What a connection may send depends only on which of three states it is in: expecting-hello, unbound, or bound.

3.6.2 Greeting #

The first message on a connection MUST be the surface's Hello:

FieldMeaning
element_typesThe element types this surface can render.
surfaceOptional observability string ("install-tui/0.1").

element_types is a statement of capability. The daemon MUST NOT send this connection an element whose type is absent from it, and MUST refuse a binding whose conversation needs more than the surface declared (unsupported_elements) — refusing at bind time is what makes an unrenderable page unreachable, rather than a failure mid-flow. surface is for logs; the daemon MUST NOT vary behaviour on it.

The daemon replies Welcome, carrying the conversation kinds it offers and its own optional observability string.

3.6.3 The unbound connection #

After WELCOME the connection is unbound. It may send exactly three things:

  • List — the daemon replies Listing: the conversations this caller could attach to, each with its identifier, kind, and current seq. A daemon with nothing listable replies with an empty listing.
  • Start — open a conversation of a kind.
  • Attach — join the conversation named by identifier.

Anything else on an unbound connection is a protocol error, as is a second binding attempt on a bound one.

3.6.4 Binding #

A successful Start or Attach binds the connection and is answered by Bound, carrying the conversation's identifier, its current seq, and attached — true when the caller joined a conversation that already existed. Immediately after a Bound, if a turn is outstanding, the daemon MUST send it to the new connection in its current state (§3.3).

A daemon MAY answer a Start by attaching: a daemon whose policy admits one conversation of a kind answers a second Start with Bound { attached: true } for the existing one. The surface learns what happened from attached and nothing else changes.

A conversation's identifier is assigned by the daemon at creation: 32 lowercase hexadecimal characters encoding 128 bits that MUST come from a cryptographically secure source. It names the conversation in Attach, Bound and Listing, and nowhere else.

A binding that is refused is answered by Refused and leaves the connection unbound:

reasonMeaning
access_deniedThe access check of §3.4 failed.
unknown_kindStart named a kind this daemon does not offer, or Attach named a conversation that does not exist or has ended.
unsupported_elementsThe conversation needs element types the surface did not declare.

A daemon SHOULD prefer unknown_kind over access_denied for a conversation the caller may not know exists, and MUST NOT use Refused for anything but a binding attempt.

Edit this page