OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-social commits / 927e34d

Replace profile rooms with DMs for social discovery
DMs already exist in keet-core (RoomType=2, 6 API methods, blind pairing, request/accept). Room shares as editable messages in DMs replace profile rooms. Better privacy (contacts can't see each other), per-person sharing, no new room type needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
927e34df41dbd350c622e7ee3e4f58632d280348
by plankatron <fleeky@gmail.com> · 2026-02-21T13:39:03.000Z

Changed files (1) +110 -56

docs/ROOMS-ARE-THE-COMPUTER.md +110 -56
……@@ -29,7 +29,7 @@ OLD (3+ Autobase types, hand-crafted):
2929NEW (1 Autobase type, all keet-core):
3030 Room ← Autobase (keet-core) ✓ works great
3131 Registry ← Room (it's just a room) ✓ reuses keet-core
32 Profile ← Room (it's just a room) ✓ reuses keet-core
32 DM ← Room (RoomType=2) ✓ already in keet-core
3333 Everything ← Room config + messages ✓ already exists
3434 Graph ← Local computation ✓ no storage needed
3535```
……@@ -109,46 +109,72 @@ room.config = {
109109- Chat history = listing history (searchable, versioned, auditable)
110110- No new Autobase. No writer key management. No view corruption.
111111
112### Profile Room
112### DMs as Social Graph Edges
113113
114Each user has a personal room that IS their public profile. They control it. Others follow by joining.
114keet-core already has DMs. They're `RoomType=2` — rooms with exactly 2 members, blind-pairing delivery, request/accept flow, read receipts. We don't need to build DMs. We need to use them for discovery.
115115
116```javascript
117room.config = {
118 type: "profile",
119 title: "alice0's profile",
120 description: "Rust developer, Berlin",
121 topics: ["rust", "berlin", "p2p"],
122 publicRooms: true // signals that this profile shares room listings
123}
116**A DM is both a conversation AND a social connection.** Room shares posted in DMs are how you discover each other's rooms. Each share is a separate editable message — update the invite token by editing, remove by deleting.
117
118**keet-core DM API (already implemented):**
124119
125// Sharing a room = posting a structured message:
120| Route | What it does |
121|-------|-------------|
122| `dm.request(roomId, memberId, message)` | Send DM request via blind pairing |
123| `dm.accept(roomId)` | Accept incoming DM request |
124| `dm.reject(roomId)` | Reject incoming DM request |
125| `dm.list()` | List accepted DMs (status=1) |
126| `dm.requests(status)` | List pending requests (status=3) |
127| `dm.fromContact(memberId)` | DM from contact info directly |
128
129**Room sharing in DMs — each share is one editable message:**
130
131```javascript
132// Share a room = post a structured message in the DM:
126133{
127134 type: "room-share",
128135 roomId: "def456...",
129136 title: "Hypercore Dev Chat",
130137 topics: ["hypercore"],
131 inviteToken: "abc...", // optional — only if room is open
138 inviteToken: "abc...",
132139 sharedAt: 1708402400000
133140}
141
142// Update the invite token = edit that message
143// Unshare = delete that message
144// List shared rooms = load DM history, filter by type: "room-share"
134145```
135146
136147**UX flow:**
1371. Alice clicks Bob's name in any shared room
1382. She sees his member info (already works)
1393. New: "Follow" button appears
1404. Follow = join Bob's profile room (invite auto-created, or discoverable)
1415. In Bob's profile room, she sees his shared rooms as messages
1426. She joins any that interest her via posted invite tokens
1437. Her local MI computation now has data about Bob's rooms
1448. Unfollow = leave the profile room
145
146**Why this solves user discovery:**
147- keet-core cannot store arbitrary fields on identity profiles (fixed schema)
148- Profile rooms work around this using existing room primitives
149- "Follow" is just room membership — no new concept
150- The profile room IS the user's public presence
151- Auto-created during identity setup (one extra `createRoom` call)
1481. Alice clicks Bob's name in a shared room → "Message"
1492. DM request sent via blind pairing (keet-core handles this)
1503. Bob accepts the DM request
1514. They can chat normally — AND share rooms as structured messages
1525. Alice sees Bob's shared rooms as joinable cards in the DM
1536. She joins one → meets Carol → DMs Carol → discovers more rooms
1547. Her local MI computation includes rooms shared via all her DMs
155
156**Why DMs beat profile rooms:**
157
158| Property | Profile Room | DM |
159|----------|-------------|-----|
160| Followers see each other | Yes (privacy leak) | No |
161| Per-person sharing | No (everyone sees same) | Yes (share different rooms with different people) |
162| New room type needed | Yes ("profile") | No (DMs already exist in keet-core) |
163| New concept for users | Yes ("follow") | No ("message" — already understood) |
164| Spam protection | Manual (invite-only) | Built-in (request/accept flow) |
165| Chat + sharing | Awkward | Natural (DMs have chat by design) |
166| Selective sharing | Impossible | Yes (share rust rooms with devs, gaming rooms with gamers) |
167| Already implemented | No | Yes (6 API methods in keet-core) |
168
169**Privacy properties:**
170- DM contacts don't know about each other (no shared member list)
171- You control what you share per-relationship
172- No broadcast — you think about who you're sharing with
173- Request/accept prevents drive-by following (no spam)
174- The client can offer "share to..." with a multi-DM contact picker for convenience
175
176**Sharing with multiple contacts:**
177The client provides a "Share Room" action: pick a room, pick contacts from your DM list, post the room-share message to each selected DM. This is explicit, intentional sharing — not broadcasting to an audience you can't see.
152178
153179## Room Metadata Vocabulary
154180
……@@ -187,7 +213,7 @@ Enables: DHT discovery, invite flow, privacy control.
187213### Type Metadata
188214
189215```
190type : string — "chat" | "registry" | "profile" | "wiki" | "board"
216type : string — "chat" | "registry" | "dm" (RoomType=2, set by keet-core)
191217```
192218
193219Enables: room type conventions, UI behavior switching.
……@@ -201,11 +227,16 @@ For each room you're a member of:
201227 - room.config (topics, type, related rooms, bridges)
202228 - room.members (member IDs)
203229
204For each profile room you follow:
205 - room-share messages (rooms the person has shared)
230For each DM you have:
231 - room-share messages (rooms this contact has shared with you)
232 - The DM itself is a social edge (you know this person)
206233```
207234
208All of this data is already on your machine. keet-core replicated it when you joined the rooms.
235All of this data is already on your machine. keet-core replicated it when you joined the rooms and accepted the DMs. Three signal types feed the graph:
236
237- **Direct** — rooms you're actually in (strongest signal)
238- **One-hop** — rooms your DM contacts shared with you (medium signal)
239- **Two-hop** — rooms shared by people in rooms your contacts shared (weak, optional)
209240
210241### Computation (local, in-memory)
211242
……@@ -285,6 +316,22 @@ The computation maps exactly to the OpenCog language learning pipeline:
285316 (ConceptNode "room:abc123")
286317 (ConceptNode "platform:irc")))
287318
319;; DM relationship — a social edge (RoomType=2, already in keet-core)
320(EvaluationLink
321 (PredicateNode "has-dm")
322 (ListLink
323 (ConceptNode "member:alice0")
324 (ConceptNode "member:bob0")))
325
326;; Room shared via DM — one-hop discovery
327(EvaluationLink
328 (PredicateNode "shared-via-dm")
329 (ListLink
330 (ConceptNode "member:bob0")
331 (ConceptNode "room:def456")
332 (ConceptNode "member:alice0")))
333;; "bob shared room def456 with alice"
334
288335;; COMPUTED ATOMS (local, ephemeral):
289336
290337;; Co-occurrence with MI value
……@@ -334,13 +381,13 @@ The hierarchy exists in the computation, not in stored data structures. Each use
334381
335382### How It Works With Rooms (organic, bottom-up)
336383
337**Path 1: Through people (social traversal)**
384**Path 1: Through people (DM-based social traversal)**
338385```
3393861. You're in room X with Bob
3402. You click Bob's name → "Follow"
3413. You join Bob's profile room
3424. You see rooms Bob has shared
3435. You join one → meet Carol → follow Carol → discover more rooms
3872. You click Bob's name → "Message"
3883. DM request sent (blind pairing), Bob accepts
3894. Bob shares rooms with you as editable messages in the DM
3905. You join one → meet Carol → DM Carol → discover more rooms
3443916. Your local MI computation clusters everything automatically
345392```
346393
……@@ -373,7 +420,7 @@ The hierarchy exists in the computation, not in stored data structures. Each use
3734205. Optionally: create a registry room for it → others can browse it too
374421```
375422
376All four paths feed the same local graph. The group bar shows the result: a mix of named groups (from registry rooms you've joined), computed clusters (from MI), and followed profiles (from profile rooms). The user doesn't need to know which mechanism discovered which group.
423All four paths feed the same local graph. The group bar shows the result: a mix of named groups (from registry rooms you've joined), computed clusters (from MI), and rooms shared via DMs. The user doesn't need to know which mechanism discovered which group.
377424
378425## What Changes in Code
379426
……@@ -386,20 +433,21 @@ index.js discovery plumbing — config, eager init, heartbeat (~170 lines)
386433router.js discovery routes — register, unregister, list, etc. (~200 lines)
387434```
388435
389**Add (~480 lines):**
436**Add (~440 lines):**
390437```
391438lib/registry-room.js (~80) — Post/read room-listing messages in registry rooms
392lib/profile-room.js (~60) — Create profile room on identity setup, post room-shares
439lib/dm-shares.js (~60) — Post/read room-share messages in DM rooms
393440lib/local-graph.js (~200) — MI computation on local membership data
394441lib/topic-announce.js (~60) — DHT announce/search for discoverable rooms
395router.js new routes (~80) — registry.*, profile.*, graph.*, topic.* routes
442router.js new routes (~40) — registry.*, graph.*, topic.* routes
443 (DM routes already exist: dm.request, dm.accept, etc.)
396444```
397445
398**Net: ~870 removed, ~480 added. Fewer lines AND simpler code.**
446**Net: ~870 removed, ~440 added. Fewer lines AND simpler code.**
399447
400The 480 new lines are trivial compared to the 870 they replace:
448The 440 new lines are trivial compared to the 870 they replace:
401449- `registry-room.js` calls existing room/chat APIs
402- `profile-room.js` calls existing room/identity APIs
450- `dm-shares.js` calls existing DM + chat APIs (DM infrastructure already built)
403451- `local-graph.js` is pure math on data already in memory
404452- `topic-announce.js` is a thin DHT wrapper
405453- No Autobase lifecycle management, no writer keys, no view corruption handling
……@@ -419,9 +467,12 @@ group_bar.gd (446 lines, same size, different logic)
419467
420468**Add:**
421469```
422keet_profile.gd (~100 lines)
423 — Follow/unfollow users, read shared rooms from profile rooms
424 — "Follow" button on member popup
470keet_dm.gd (~120 lines)
471 — DM lifecycle: create, list, accept/reject requests
472 — Room sharing: post/edit/delete room-share messages in DMs
473 — Read shared rooms from DM history
474 — "Message" button on member popup
475 — "Share Room" action with multi-contact picker
425476
426477keet_graph.gd (~150 lines)
427478 — Request MI computation results from daemon
……@@ -430,9 +481,10 @@ keet_graph.gd (~150 lines)
430481
431482**Modify:**
432483```
433keet_service.gd — add profile_mgr, graph_mgr (2 lines)
434member_panel.gd — add "Follow" button to member context (20 lines)
484keet_service.gd — add dm_mgr, graph_mgr (2 lines)
485member_panel.gd — add "Message" button to member context (20 lines)
435486chat_panel.gd — detect bridge message prefix, show badge (30 lines)
487room_list_panel.gd — show DM rooms in a "Messages" section (40 lines)
436488```
437489
438490### index.js (launcher)
……@@ -503,13 +555,13 @@ Each step is independently deployable. The existing app works at every stage.
503555
504556Set `topics`, `discoverable`, `type` on rooms via `setConfig`. No Autobase changes. No UI changes. Just establishing conventions.
505557
506### Step 2: Add profile rooms
558### Step 2: Add DM support to godot-keet
507559
508Create a profile room during identity setup. Add "Follow" button to member popups. Post room-share messages when user opts to share a room publicly. This is ~160 lines of new code total.
560keet-core already has DMs (6 API methods). Add `keet_dm.gd` to wrap them. Add "Message" button to member panel. Show DM rooms in room list. Add room-share message type for sharing rooms in DMs. This is ~120 lines of GDScript + ~60 lines of JS.
509561
510562### Step 3: Add local graph computation
511563
512Compute MI from membership data on a timer (every 60 seconds, or on room join/leave). Feed results to group bar for reordering. ~200 lines of JS, ~150 lines of GDScript. No Autobase changes.
564Compute MI from membership data on a timer (every 60 seconds, or on room join/leave). Include rooms shared via DMs as one-hop data. Feed results to group bar for reordering. ~200 lines of JS, ~150 lines of GDScript. No Autobase changes.
513565
514566### Step 4: Add registry rooms
515567
……@@ -536,7 +588,7 @@ Bridges set `bridgedTo` in room config when they connect. Chat panel detects bri
536588- **SOCIAL-GRAPH-NAVIGATION.md** — The math is correct. MI, MST, clustering, sheaf theory. All stays.
537589- **COMMUNITY-EMERGENCE.md** — The sociology is correct. Phase transitions, nucleation, three sovereignties. All stays.
538590- **AUTO-DISCOVERY.md** — The layered approach is correct (Layers 0-4). The implementation changes from "new Autobases" to "room conventions + local computation."
539- **ROADMAP.md** — The phased evolution is correct. The Hub wrapping keet-daemon is correct. The specific phases change (drop board panel, inline wiki, add profile rooms).
591- **ROADMAP.md** — The phased evolution is correct. The Hub wrapping keet-daemon is correct. The specific phases change (drop board panel, inline wiki, DMs instead of profile rooms).
540592- **ARCHITECTURE.md** — The fracture principle is correct. Independent projects composing into a system.
541593
542594## What the Existing Docs Got Wrong
……@@ -549,20 +601,22 @@ Bridges set `bridgedTo` in room config when they connect. Chat panel detects bri
549601
550602## Gaps Still Open
551603
5521. **Profile room discoverability** — How does Alice find Bob's profile room if they aren't in a shared room yet? Answer: she can't, and that's correct. Discovery happens through shared rooms, not through a global directory. This IS the privacy model.
6041. **DM initiation requires shared room** — `dm.request` needs a `roomId` where both members are present. You can't DM someone you've never been in a room with. This is correct for privacy but means cold-contact discovery requires at least one shared room, registry room, or out-of-band exchange. `dm.fromContact` may work without a shared room (needs testing).
553605
5546062. **Registry room migration** — Existing discovery registries (Global, testy) need to be migrated to registry rooms. One-time conversion: read all entries from the Autobase, create a room, post them as messages. The Autobase discovery key becomes the room's invite.
555607
5566083. **Bridge bot identity** — When a bridge connects to a room and sets `bridgedTo` in config, it needs admin access. Bridge bots should be added as room members with moderator role (not admin — they shouldn't be able to delete the room).
557609
5584. **Profile room spam** — If "Follow" is just joining a room, and the profile room is discoverable, bots could spam it. Mitigation: profile rooms default to invite-only. Following requires a mutual connection (you're both in at least one room).
6104. **DM room presentation** — DMs need to appear distinctly from group rooms in the room list. Either a separate "Messages" section in the room list, or a filter/tab. keet-core marks them as `RoomType=2` so filtering is straightforward.
559611
5606125. **MI computation cost** — For users in 100+ rooms with 1000+ total members, the pairwise MI computation is O(n² rooms × m members). Benchmark needed. May need sparse representation or incremental updates.
561613
5626. **Cross-platform identity linking** — COMMUNITY-EMERGENCE.md discusses it, ROADMAP.md Phase 6 plans it, but no spec exists. Likely: identity links are messages in profile rooms — "I am also alice on IRC Libera" — cryptographically signed by both identities. Implementation TBD.
6146. **Cross-platform identity linking** — COMMUNITY-EMERGENCE.md discusses it, ROADMAP.md Phase 6 plans it, but no spec exists. Likely: identity links are room-share messages in DMs — "I am also alice on IRC Libera" — signed by both identities. The DM is the trust channel. Implementation TBD.
563615
5646167. **Moderation service** — COMMUNITY-EMERGENCE.md describes moderation as a subscribable label service (Blacksky pattern). No implementation spec. Likely Phase 8. Could be: a room whose messages are moderation labels, subscribable by other rooms.
565617
6188. **Room-share message format** — Need a convention for structured messages. keet-core messages are text strings. Structured data must be JSON-encoded in the text field, with client-side parsing. Alternatively, messages may support metadata/attachments that could carry structured payloads. Needs investigation of what keet-core message fields support.
619
566620## The Principle
567621
568622The community already exists. The rooms already exist. The people already exist.