Public: anyone can read this; the crew can change it.

Multiplayer and sync as forge primitives: an ordered change stream per app, rooms and presence, zero dependencies #1117

open deferred: behind the Later gate opened this
Held by the Later gate, set by trevato . The crew picks nothing here until it is lifted.
opened this

"The cs-engine is a great game but multiplayer isn't native, which is a major downfall." "It's almost like the forge just needs a global sync engine." The forge already has the parts: an event bus, server-sent streams, a git-backed store, grants that name a person to an app. What an app lacks is a primitive it can lean on: an ordered stream of changes with optimistic local writes, rooms, presence, and durability on the forge, in the forge's own zero-dependency shape (a Linear-style sync, not a Postgres-bound engine).

Done looks like:

  • [ ] A sync primitive for apps: POST /sync/:room appends a change (JSON, with a client id and a client sequence), GET /sync/:room?since= streams the ordered log over SSE or a WebSocket, presence is a heartbeat in the same stream; the log is durable on the forge and compacts with snapshots. Scoped by the app's grant: who may read, who may write.
  • [ ] A tiny client the app template ships (one file, no dependencies): local state, optimistic apply, rebase on the server's order, presence.
  • [ ] cs-engine is the proving app: two browsers, one room, both players see each other within a frame; friends tune a parameter while they play and the change lands in the repository as a tell.
  • [ ] Tests pin ordering, reconnection with since, grant scoping, and compaction.

Files I expect: src/apps/sync.ts (new), src/http/server.ts, the app template, docs/APPS.md.

commented

From the owner, 2026-10-12: "I like cs-engine and want to keep developing it eventually but don't want to waste tokens. It can be used to implement multiplayer now, because that is high priority. There is no reason everything can't be realtime by default if it can be done efficiently. I will want to build apps for my hydroponics eventually."

So: cs-engine is the proving app for this primitive and nothing else runs on it until the primitive exists. "Realtime by default" is the bar: the sync stream is what every app gets from the template, cheap when idle (no connection, no work), live the moment two people are in the same room. The hydroponics apps come later and will lean on the same stream for sensor readings; keep the change log shape generic (any JSON, ordered, compactable), not game-specific.

commented

Parked by the crew: the check failed ("the gate's list > every test/*.test.ts is in exactly one list, and every entry exists") and the decider saw no point in another try (pull #1366 closed). Planner: split this smaller, or rewrite what done looks like; a person can also say what to try.

commented

Parked by the crew: the check failed ("the gate's list > every test/*.test.ts is in exactly one list, and every entry exists") and the decider saw no point in another try (pull #1453 closed).

Parked twice since a person last spoke here, so it is the planner's now. Every reason:

  1. the check failed ("the gate's list > every test/*.test.ts is in exactly one list, and every entry exists") and the decider saw no point in another try (pull #1366 closed)
  2. the check failed ("the gate's list > every test/*.test.ts is in exactly one list, and every entry exists") and the decider saw no point in another try (pull #1453 closed)

The planner splits it, replaces it with a fresh issue, or defers it; a person can also say what to try. Nothing starts here until then, and the board lists it.

commented

Deferred behind the Later gate (#595): the sync primitive is a large new surface, and it waits behind /flow and Boards. Both pulls went red on the gate's list: any new test file needs a GATE entry in scripts/gate.ts.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs