3-RRC: Wire Encoding, Constants, and Numeric Assignments¶
Version: 0.1.1
This document exists so that two people, writing two separate RRC implementations, do not accidentally invent two different protocols while both claiming success.
1-RRC explained what the system is. 2-RRC explained what messages exist and how sessions behave. This document locks down the numbers, field keys, and expectations that appear on the wire so that CBOR blobs mean the same thing everywhere.
If you skip this document, your implementation will still work, but only with itself. That is not a victory.
Canonical Encoding Rules¶
All RRC messages are encoded as CBOR maps. The map keys are unsigned integers. String keys are not allowed. This is not because strings are evil, but because numeric keys are smaller, faster to parse, and harder to misspell.
All integer values are encoded as unsigned integers unless explicitly stated otherwise. Binary values are encoded as CBOR byte strings. Human-readable text is encoded as CBOR text strings using UTF-8.
Ordering of keys in the CBOR map does not matter. Receivers must not assume any specific ordering and must not reject messages solely because the sender arranged keys differently.
Unknown keys must be ignored. This is not optional. If your implementation explodes because it saw a field it did not understand, that is your fault.
Envelope Structure¶
Every RRC message shares the same top-level envelope. This envelope is a CBOR map containing the following fields.
Field 0 - Protocol Version¶
This value identifies the RRC protocol version used to encode the message. For this specification, the value must be 1. Messages with other versions may be ignored or rejected.
Field 1 - Message Type¶
This is an unsigned integer identifying what kind of message this is. The numeric values for message types are defined later in this document.
Field 2 - Message Identifier¶
This is a byte string chosen by the sender. It must be unique within the scope of the sender’s current session. It does not need to be globally unique, cryptographically strong, or persistent across reconnects. It exists so implementations can correlate messages if they care to.
Field 3 - Timestamp¶
This is an unsigned integer representing milliseconds since the Unix epoch, according to the sender’s clock. It is advisory only. No one is expected to agree on time.
Field 4 - Sender Identity¶
This is a byte string containing the Reticulum identity hash of the sender. This field is mandatory even though the Link already authenticates the peer, because forwarded messages need an explicit source identifier.
Field 5 - Room Name¶
This is a text string identifying the room the message applies to. If a message does not apply to a room, this field may be omitted.
Field 6 - Body¶
This field contains the payload of the message. Its structure and meaning depend entirely on the message type.
Field 7 - Nickname¶
This is an optional text string containing a human-readable nickname for the sender.
It is advisory only. It may be omitted, empty, ridiculous, or all three. The hub may ignore it, sanitize it, replace it, or drop it on the floor entirely. Clients may display it if present, or may choose to rely on identity hashes, locally cached labels, or whatever else they think is a good idea.
If both sides send this field, they are not negotiating. They are making suggestions.
No other top-level fields are defined by this document.
Envelope field keys 0 through 39 are reserved for core protocol use. Extensions may define additional top-level fields using keys 40 through 63. Keys 64 and above are reserved for future specifications, which is a polite way of saying “don’t squat there unless you enjoy avoidable pain.”
Message Type Assignments¶
Message type values are fixed. They are not suggestions.
Type |
Name |
|---|---|
1 |
HELLO |
2 |
WELCOME |
10 |
JOIN |
11 |
JOINED |
12 |
PART |
13 |
PARTED |
20 |
MSG |
21 |
NOTICE |
30 |
PING |
31 |
PONG |
40 |
ERROR |
0 - 9: Link Control Messages¶
Type 0 - RESERVED¶
Type 0 is reserved and must not be used.
Type 1 - HELLO¶
The HELLO message uses type 1. This message is sent by the client to announce
itself after a Link is established.
Type 2 - WELCOME¶
The WELCOME message uses type 2. This message is sent by the hub to
acknowledge and accept the session.
10 - 19: Room Membership Messages¶
Type 10 - JOIN¶
The JOIN message uses type 10. This message is sent by the client to request
entry into a room.
Type 11 - JOINED¶
The JOINED message uses type 11. This message is sent by the hub to confirm
room membership.
Type 12 - PART¶
The PART message uses type 12. This message is sent by the client to leave a
room.
Type 13 - PARTED¶
The PARTED message uses type 13. This message is sent by the hub to confirm
that a client has left a room.
20 - 29: Messages Intended for Rooms and People¶
Type 20 - MSG¶
The MSG message uses type 20. This message carries chat content intended for a
room.
Type 21 - NOTICE¶
The NOTICE message uses type 21. This message carries informational or
non-conversational content.
30 - 39: Link Management Messages¶
Type 30 - PING¶
The PING message uses type 30. This message checks whether the peer is still
responsive.
Type 31 - PONG¶
The PONG message uses type 31. This message is the response to a PING.
40 and Up: Error and Status Messages¶
Type 40 - ERROR¶
The ERROR message uses type 40. This message reports a failure or refusal.
Values from 0 to 63 are reserved for core protocol use. Values from 64 upward are available for extensions, experiments, and future specifications. If you collide with yourself there, that is your own adventure.
Message Body Definitions¶
The body field exists so message-specific data does not leak into the envelope and turn everything into a special case.
For HELLO, the body is a CBOR map with unsigned integer keys. It may contain
session-specific data used for exchanging version information or program
capabilities, as well as human-facing metadata.
All body fields are advisory and optional. Any human-facing metadata is considered an extension of the protocol and is outside the scope of this specification.
HELLO body key assignments:
Key |
Name |
Type |
Description |
|---|---|---|---|
0 |
Client Name |
text string |
Client software name (optional) |
1 |
Client Version |
text string |
Client version string (optional) |
2 |
Capabilities |
map/array |
Capability hints (optional) |
For WELCOME, the body is also a CBOR map with unsigned integer keys. It may
contain session-specific data used for exchanging version information or program
capabilities, as well as human-facing metadata.
All body fields are advisory and optional. Any human-facing metadata is considered an extension of the protocol and is outside the scope of this specification.
WELCOME body key assignments:
Key |
Name |
Type |
Description |
|---|---|---|---|
0 |
Hub Name |
text string |
Human-friendly hub name |
1 |
Hub Version |
text string |
Hub version string (optional) |
2 |
Capabilities |
map/array |
Capability hints (optional) |
Unknown body keys must be ignored. Keys 0 through 63 are reserved for core body fields defined by this document. Keys 64 and above may be used for extensions.
For JOIN, the body is empty or omitted. The room name is taken from the
envelope field.
For JOINED, the body may contain a list of current members. If present, this
list is advisory and not guaranteed to be complete or current.
For PART, the body is empty or omitted.
For PARTED, the body may be empty, omitted, or may contain a list of remaining
members. If you are hoping for perfect presence, you are in the wrong document.
For MSG, the body contains the message payload. The simplest and most common
form is a text string. Implementations may choose to use structured payloads,
but hubs must treat the body as opaque data and forward it unchanged.
For NOTICE, the body follows the same rules as MSG but carries a different
semantic meaning.
For PING and PONG, the body may be omitted or may contain arbitrary data to
allow round-trip correlation. Receivers must echo the body back unchanged in the
corresponding response if it is present.
For ERROR, the body should be a text string describing the error in plain
language. It may optionally be a CBOR map if structured error information is
desired, but clients must handle simple text at minimum.
Room Name Normalization¶
Room names are encoded as text strings. Hubs should normalize room names internally, typically by converting them to lowercase. The exact normalization method is an implementation detail, but the observable behavior should be case-insensitive room matching.
Clients should not assume that room names preserve original casing.
Identity Encoding¶
The sender identity field contains the Reticulum identity hash encoded as a CBOR byte string. No additional structure is imposed by RRC.
Clients and hubs must not reinterpret, truncate, or re-encode this value. It is passed through as-is and treated as opaque data.
Error Handling on the Wire¶
Malformed messages may be ignored. Messages with unknown message types must be ignored. Messages with missing required envelope fields may be ignored or may trigger an ERROR, at the receiver’s discretion.
If a hub sends an ERROR and then closes the Link, that is considered valid behavior. Clients should not attempt to argue with a closed socket.
Forward Compatibility Rules¶
Implementations must follow three simple rules to remain compatible over time.
They must ignore unknown envelope keys. They must ignore unknown message types. They must not repurpose existing numeric assignments.
Breaking any of these rules means you are no longer speaking RRC, regardless of how confident you feel.
Tabular Examples¶
The following table summarizes the structure of RRC messages.
Field Number |
Field Name |
Description |
|---|---|---|
0 |
Protocol Version |
Unsigned integer identifying the protocol version |
1 |
Message Type |
Unsigned integer identifying the message type |
2 |
Message ID |
Byte string chosen by the sender |
3 |
Timestamp |
Unsigned integer representing milliseconds since the Unix epoch |
4 |
Sender Identity |
Byte string containing the Reticulum identity hash |
5 |
Room Name |
Text string identifying the room (optional) |
6 |
Body |
Message-specific payload (structure depends on message type) |
7 |
Nickname |
Optional, advisory human-readable sender nickname |
The following table summarizes the message type assignments (Field 1).
Type |
Name |
Description |
|---|---|---|
0 |
RESERVED |
Reserved; must not be used |
1 |
HELLO |
Client announces itself to the hub |
2 |
WELCOME |
Hub acknowledges and accepts the session |
10 |
JOIN |
Client requests entry into a room |
11 |
JOINED |
Hub confirms room membership |
12 |
PART |
Client leaves a room |
13 |
PARTED |
Hub confirms room departure |
20 |
MSG |
Chat message intended for a room |
21 |
NOTICE |
Informational message |
30 |
PING |
Check whether the peer is responsive |
31 |
PONG |
Response to a PING |
40 |
ERROR |
Report a failure or refusal |
The following table is an example of a client sending a chat message to a room.
Field Number |
Field Name |
Value |
|---|---|---|
0 |
Protocol Version |
1 |
1 |
Message Type |
20 (MSG) |
2 |
Message ID |
b”\x01\x02\x03\x04” |
3 |
Timestamp |
1700000000000 |
4 |
Sender Identity |
b”\xAA\xBB\xCC\xDD\xEE\xFF” |
5 |
Room Name |
“#general” |
6 |
Body |
“Hello, world!” |
7 |
Nickname |
“alice” |