Summary
Replace the current global-lobby + room-code model with a friend-centric social layer. The lobby becomes a friends list, challenges flow through friendship, and matchmaking gains a quick-play option.
Motivation
- The global lobby scales as O(N) presence fan-out and has already needed perf patches (e.g. dropping the user list from pong to cut O(N²) bandwidth).
- Room codes are friction for the common case — two people who already know each other want to play. They're also a discoverability dead-end and have no persistence.
- A friend graph is the natural primitive for the social-AI pillar and unlocks future features (notifications, shared skills/themes, async invites) that don't fit a transient lobby.
Proposed scope
Friend system (new)
- Add-friend flow by GitHub username (identity parity with the current lobby).
- Persistent friend list stored server-side (PartyKit durable object or a small backend) and mirrored client-side.
- Friend presence: online / in-game / offline, pushed only to accepted friends — no global broadcast.
- Accept / decline / remove friend.
Challenges through friendship
- Challenge a friend directly from the friends list. No room code required.
- Replaces the existing
challenge / challenge-response flow that currently resolves via lobby-wide message relay.
- Incoming-challenge UI surfaces in-app (and ideally as a system notification) regardless of which view the user is on.
Quick-play
- One-tap matchmaking for users who don't have friends online (or don't want to wait).
- Matchmaker pairs against another quick-play seeker with compatible game + skill band.
- Timeout fallback: offer an AI opponent or suggest adding a friend.
Remove room codes
- Retire
ROOM_CREATED / JOINING_GAME code-entry UI once friend-challenge + quick-play cover both paths.
- Keep a migration window where existing in-flight rooms still resolve, then remove.
Touchpoints (rough, not a plan)
partykit/src/lobby-room.ts → split into friends-room + matchmaking-room, or move friends to a separate backend.
desktop/src/renderer/hooks/usePartyLobby.ts → rename/restructure; lobby becomes friends socket.
desktop/src/renderer/state/game-reducer.ts → new friends, friendRequests, quickPlayStatus slices; retire onlineUsers as a global presence list (keep only for quick-play matchmaking pool if still needed).
desktop/src/renderer/components/game/GameLobby.tsx → rebuilt around friends list + quick-play button; room-code inputs removed.
- Android parity:
app/... UI + any WebSocket wiring follows the same remote-shim protocol.
docs/superpowers/specs/2026-03-27-partykit-game-backend-design.md → supersede / update.
Open questions
- Friend identity: GitHub only, or also allow display-name aliases?
- Where does the friend list live — extend PartyKit DO storage, or a separate small service (Cloudflare Worker + D1, reusing the marketplace-worker stack)?
- Do we keep any form of open-lobby browse for discovery (e.g. "players near you by region"), or is friends + quick-play the entire surface?
- Incognito — how does it compose with a friend graph? (Probably: stop broadcasting presence to friends while keeping friendship records intact.)
Non-goals (for this issue)
- Full cross-device chat / DM between friends — separate feature, can build on the same graph later.
- Guilds / groups / tournaments.
- Spectator mode.
Summary
Replace the current global-lobby + room-code model with a friend-centric social layer. The lobby becomes a friends list, challenges flow through friendship, and matchmaking gains a quick-play option.
Motivation
Proposed scope
Friend system (new)
Challenges through friendship
challenge/challenge-responseflow that currently resolves via lobby-wide message relay.Quick-play
Remove room codes
ROOM_CREATED/JOINING_GAMEcode-entry UI once friend-challenge + quick-play cover both paths.Touchpoints (rough, not a plan)
partykit/src/lobby-room.ts→ split into friends-room + matchmaking-room, or move friends to a separate backend.desktop/src/renderer/hooks/usePartyLobby.ts→ rename/restructure; lobby becomes friends socket.desktop/src/renderer/state/game-reducer.ts→ newfriends,friendRequests,quickPlayStatusslices; retireonlineUsersas a global presence list (keep only for quick-play matchmaking pool if still needed).desktop/src/renderer/components/game/GameLobby.tsx→ rebuilt around friends list + quick-play button; room-code inputs removed.app/...UI + any WebSocket wiring follows the same remote-shim protocol.docs/superpowers/specs/2026-03-27-partykit-game-backend-design.md→ supersede / update.Open questions
Non-goals (for this issue)