bd12d5ef72
Edits across all 13 EGGs to remove implementer guesswork. After this an
implementer can build a listener and speaker without reading our source.
README:
- Conventions section: hex casing rule (lowercase, 64 chars, no 0x),
NIP-01 foundations, `a`-tag form, created_at tie-break, JSON / time.
- Joining sequence: numbered end-to-end walkthrough from `kind:30312`
to first audio frame, referencing each EGG.
EGG-01 (room event):
- `relays` tag is one tag with multiple values (not multi-tag).
- `service` URL trailing-slash normalization.
- `private` status: gate is implementation-defined, not "render as open".
- `d`-tag charset locked to [A-Za-z0-9._-] so it interpolates safely
into the moq-auth namespace.
- Relay-discovery rule: publish to `relays` tag ∪ NIP-65 outbox.
- Tie-break on identical created_at via smallest event id.
EGG-02 (auth):
- JWT signing pinned: ES256 over P-256, JWKS at /.well-known/jwks.json,
5-minute relay cache.
- NIP-98 tags pinned: u / method / payload, base64 RFC 4648 standard
(not base64url).
- Error taxonomy: full HTTP status + `error` slug table for /auth, plus
WebTransport CONNECT 200/401/403/404 table.
EGG-03 (audio):
- Pin moq-lite Lite-03 to kixelated/moq-rs `rs/moq-lite/src/lite/`.
- One Opus packet per moq Frame (no container, no timestamp).
- Pubkey hex casing reaffirmed at the suffix / broadcast slots.
- AnnouncePlease prefix="" for speaker discovery.
- Mute = stop publishing (not silence frames, not Announce Ended).
- Mid-stream join: discard pre-skip per RFC 7845.
EGG-04 (presence):
- Heartbeat jitter ±5 s required (anti-thundering-herd).
- "0"/"1" are strings, not booleans.
- Single-room rule via replaceable-event semantics.
EGG-05 (chat): 8 KB suggested, 64 KB hard cap, 3 msg/s render rate.
EGG-06 (reactions): 30s window measured against created_at, drop-on-arrival
if already stale.
EGG-07 (moderation): replay protection — dedupe kicks by id within 120 s.
EGG-08 (scheduling): planned rooms MUST 403 at the auth sidecar.
EGG-10 (theming): bg image caps (1 MB / 4096 px soft, 8 MB / 8192 px hard).
Deferred (per review): EGG-00 (Conventions as a standalone spec), EGG-13
(capability advertisement), EGG-14 (discovery), test vectors corpus.
The "Conventions" section in README covers EGG-00's most urgent content
inline.
https://claude.ai/code/session_01RDpuki4t8StSg1CZcXnV5b
82 lines
2.6 KiB
Markdown
82 lines
2.6 KiB
Markdown
# EGG-05: In-room chat (`kind:1311`)
|
|
|
|
`status: draft`
|
|
`requires: EGG-01`
|
|
`category: optional`
|
|
|
|
## Summary
|
|
|
|
In-room text chat reuses NIP-53's `kind:1311` "live activities chat message"
|
|
event, addressed to the room via an `a`-tag. No new event kind, no new
|
|
relay convention.
|
|
|
|
A peer that does not implement EGG-05 simply does not render or emit chat;
|
|
all other EGGs continue to interop.
|
|
|
|
## Wire format
|
|
|
|
```json
|
|
{
|
|
"kind": 1311,
|
|
"pubkey": "<author pubkey hex>",
|
|
"tags": [
|
|
["a", "30312:<host pubkey hex>:<room d>", "<relay hint>"]
|
|
],
|
|
"content": "<plaintext message>",
|
|
...
|
|
}
|
|
```
|
|
|
|
The `content` field carries the plaintext (UTF-8) message.
|
|
|
|
## Behavior
|
|
|
|
1. Senders MUST emit chat events with `kind:1311` and exactly one `a`-tag
|
|
pointing at the room (EGG-01).
|
|
2. Receivers MUST subscribe to relays declared on the room's `relays` tag
|
|
(EGG-01) with filter `{kinds:[1311], "#a":["30312:<host>:<d>"]}`.
|
|
3. Receivers MUST de-duplicate by event id when the same message arrives
|
|
from multiple relays.
|
|
4. Receivers MUST sort the chat panel by `created_at` ascending so the
|
|
newest message is at the bottom.
|
|
5. Senders MUST NOT include private content. The chat plane is public;
|
|
any peer subscribed to the room's relays sees every message.
|
|
6. Senders MAY include other NIP tags (`p` mentions, `e` quotes, `q`
|
|
embeds). Receivers MAY render these per the relevant NIP; lacking
|
|
support MUST NOT cause the message to be hidden.
|
|
7. A peer SHOULD NOT publish chat events while `status` of the
|
|
`kind:30312` is `closed` — but receivers MUST tolerate them gracefully
|
|
in case of a race against the host's close.
|
|
8. **Content size.** Senders SHOULD keep `content` under 8 KB of UTF-8.
|
|
Receivers MUST tolerate up to 64 KB and MAY truncate or drop messages
|
|
above that threshold (with a visible "[message truncated]" marker).
|
|
9. **Rate limiting.** Receivers SHOULD render at most 3 messages per
|
|
second per author in the live chat panel; over-quota messages remain
|
|
visible on scroll-back but do NOT animate / scroll the panel.
|
|
|
|
## Example
|
|
|
|
```json
|
|
{
|
|
"kind": 1311,
|
|
"pubkey": "def...co",
|
|
"created_at": 1714003205,
|
|
"tags": [
|
|
["a", "30312:abchost:office-hours-2026-04", "wss://relay.example"]
|
|
],
|
|
"content": "Hi everyone, glad to be here!",
|
|
"id": "...",
|
|
"sig": "..."
|
|
}
|
|
```
|
|
|
|
## Compatibility
|
|
|
|
EGG-05 events flow on Nostr relays, not the audio plane. A relay that
|
|
implements only the audio half of nests can be paired with any NIP-01
|
|
relay to provide the chat half.
|
|
|
|
EGG-06 (reactions) targets `kind:7` events at the same `a`-tag. Chat and
|
|
reactions are independent: a peer MAY render reactions without rendering
|
|
chat or vice versa.
|