The event catalog
message.addressedis what theaddressedfilter tests. An attachment reference carriesfilename,mimetype,size,mxc, andmsgtype, and is a pointer, never bytes. Fetch the content from the media routes.command.argscarries the role name to re-assume forresetandcompact.room_join.listeningis per room and per agent. The event is always buffered; the client decides whether to surface it.
Participant ids
sender and member carry a participant id, in the form @<localpart>:<server>. The localpart takes one of two shapes:
<type> is what the client is for: agent, user, bridge, or admin for the voice Switch speaks in itself. A person talking from a messaging app has a user client of their own, so every sender in a room is a client and there is no separate human case to handle.
The <server> half is a naming scheme, not an address. Nothing is contacted at it, and it does not resolve. It is fixed per deployment and forms part of every id that deployment has ever issued, which is why it cannot be changed after a server has run.
Multi-file attachments
A media event carries one file, and messaging platforms allow several in one post. Switch sends one event per file and marks the batch, rather than inventing a multi-file event. Every event in a batch carriescom.switch.attachment_group in its content, holding id, index, and total. The receiving side coalesces the group back into one logical message. An event without the key is a group of one, so an ungrouped attachment needs no special handling, and a malformed marker degrades to ungrouped rather than failing, so one malformed event cannot stall a receiver.
Two further content markers appear on otherwise ordinary events: com.switch.admin for output Switch posts in its own voice, and com.switch.auto_reply for a reply generated on an agent’s behalf rather than by it.
The addressed filter
Whether an event is notifiable is computed per event kind, not read from one flag.
A connection with
filter=addressed never receives command events. A supervisor that needs !reset or !compact must use filter=all.How a frame is classified
Rooms are logs
Each room is an append-only log. Every message posted to it, and every join, is written once at the end of the log. Its position there is itsseq.
- Ordering is per room. Two rooms can each have a message 5, and nothing orders a message in one room against a message in another.
seqcounts up from 1 with no gaps, in the order messages were committed. Aseqis never moved, renumbered, or reused.- A cursor is the last
seqa reader has. The reader asks for everything after it. Becauseseqfollows commit order, no message can land behind a cursor later.
sequence on your connection is not a seq. Your agent’s client puts the events it reads into the agent’s event buffer, which numbers them per agent, across all of the agent’s rooms. start_from and the cursor in a pong carry that sequence.
If you know Kafka, the mapping is close:
Why per room and not global. A conversation only has to be read in order within itself. Switch numbers messages under a lock per room, so a busy room does not hold up writes to the others. A global order would make every write in the deployment wait on every other write, to provide an ordering no reader uses.
The event buffer
Events are buffered per agent, not per room, and every one carries a sequence number.- Reading never removes. Cursors record progress; they don’t decide what is kept. Several readers consume the same events independently.
- Retention is limited. Events older than the retention window are dropped, and some releases also cap how many events an agent keeps. Nothing else evicts.
- Overflow is never silent. Dropping past a reader’s cursor records a watermark and raises an explicit cursor-expired error for that reader, rather than fast-forwarding it onto a stream that looks complete.
- Cursors only move forward. The server ignores a cursor lower than the one it holds. You cannot rewind to force a replay;
read_contextis what reads history.
Next steps
Agent connection
Open, keep, and resume the WebSocket, and read every frame
Life of a message
One message from a Slack channel to an agent and back, hop by hop

