Wire-protocol specs for nostrnests-style audio rooms, in the style of Nostr NIPs and Blossom BUDs. Each spec documents one self-contained capability that a client or relay can implement; two compliant peers implementing the same set of EGGs round-trip without further coordination. Layout: README.md cover, status table, conformance levels EGG-01.md Room event (kind:30312) required EGG-02.md Auth + WebTransport handshake required EGG-03.md Audio plane (moq-lite) required EGG-04.md Presence (kind:10312) required EGG-05.md In-room chat (kind:1311) optional EGG-06.md Reactions (kind:7) optional EGG-07.md Roles & moderation (kind:4312) optional EGG-08.md Scheduling (status=planned) optional EGG-09.md User server list (kind:10112) optional EGG-10.md Theming (c/f/bg tags) decorative EGG-11.md Recording decorative EGG-12.md Catalog track (catalog.json) optional Conformance levels (Listener / Speaker / Host) defined in the README so a deployment can declare "we implement EGG-01..EGG-04" and other peers know exactly what to expect. Each spec follows the same shape (Summary / Wire format / Behavior numbered MUST/SHOULD/MAY rules / Example / Compatibility) and fits on a single printed page. Wire formats are documented exactly as nostrnests + amethyst implement them on this branch — no hypothetical capabilities, no "future" tags without an EGG number.
3.6 KiB
EGG-04: Presence (kind:10312)
status: draft
requires: EGG-01
category: required
Summary
Each participant in a room periodically broadcasts a kind:10312 event
declaring their state: which room they are in, whether their hand is raised,
whether they are muted, whether they are actively pushing audio, and whether
they currently hold a stage seat.
Presence is the source of truth for the audience-side participant grid, the hand-raise queue, the listener counter, and the home-screen "live" bubble.
Wire format
kind:10312 is a NIP-01 replaceable event with a fixed d-tag (one
presence-state per pubkey, regardless of how many rooms a user joins; see
"Behavior" below).
{
"kind": 10312,
"pubkey": "<participant pubkey hex>",
"tags": [
["a", "30312:<host pubkey hex>:<room d>", "<relay hint>"],
["hand", "0" | "1"],
["muted", "0" | "1"],
["publishing", "0" | "1"],
["onstage", "0" | "1"],
["alt", "Room Presence tag"]
],
"content": "",
...
}
The a tag is REQUIRED and points at the room defined in EGG-01.
Behavior
- A participant MUST emit a
kind:10312event:- on entering the room,
- every 30 s while in the room,
- immediately when any flag (
hand,muted,publishing,onstage) changes, - one final time on leaving, with
publishing="0"andonstage="0".
- Receivers MUST treat a participant as departed if no presence has been
observed in
> 6 minutes. (One missed heartbeat plus a 5 minute tolerance window.) - The
handflag is the participant's request-to-speak. Hosts and admins read it to populate a queue (EGG-07). - The
mutedflag is set ONLY by speakers who are also publishing. Pure audience members SHOULD omit it. - The
publishingflag means "I currently have an openaudio/databroadcast on the relay" (EGG-03). It MUST be0whenever the speaker has stopped publishing, regardless of mute state. - The
onstageflag means "I currently hold a speaker slot in the room'sp-tag list (EGG-01) AND I have not voluntarily stepped off". A speaker who steps off the stage without losing the role tag MUST emitonstage="0". - The
d-tag MUST be the FIXED stringnests-room-presence(chosen so that one presence event represents a participant's CURRENT room across all clients). A participant MUST NOT be in two rooms simultaneously. - Every flag MUST be present in every emitted event. Receivers MAY assume
omitted flags default to
0, but emitters that omit are non-conformant. - Hosts and clients displaying the participant grid MUST hide presences
from
kind:10312events whosecreated_atis older than the staleness window in rule (2).
Example
{
"kind": 10312,
"pubkey": "def...co",
"created_at": 1714003231,
"tags": [
["a", "30312:abchost:office-hours-2026-04", "wss://relay.example"],
["hand", "0"],
["muted", "0"],
["publishing", "1"],
["onstage", "1"],
["alt", "Room Presence tag"]
],
"content": "",
"id": "...",
"sig": "..."
}
Compatibility
EGG-07 (moderation) reads hand to drive the host's promote queue.
EGG-03 (audio plane) is the source of truth for whether a speaker IS
broadcasting; presence's publishing flag is a Nostr-side reflection that
clients use as a hint when they cannot subscribe to the audio plane (e.g.
listeners on weak networks rendering the home bubble).
The kind:10312 shape here intentionally mirrors kind:10311 from
NIP-53 streaming so that a generic Nostr client can render audience
indicators for both protocols without code-paths.