Skip to content

Kickoff handoff

open file (chess) — a file (column) with no pawns of either color. A clear lane through the position; the rook’s natural habitat. Also: a file, open for collaboration — a document that multiple people can read and write at the same time.

This document seeds a future kickoff session. OpenFile doesn’t exist yet beyond this folder; the chess-shaped collaboration layer is an idea worth doing carefully, and that session is where the real design work starts. Read this for context, then we’ll dig in.


The real-time collaborative chess content layer for the PROMOTE stack. A wire protocol + sync engine that lets multiple people work on the same chess data (annotated games, opening prep, studies, lessons) simultaneously, with their edits flowing across clients and attributed to them by handle.

Think of it as: Lichess Studies for the whole stack — not just one platform, but a primitive that any chess app on PROMOTE can plug into.

Position in the stack:

PROMOTE
├── P Priyome (content primitives for the web)
├── R Rabbit (board renderer)
├── O OpenFile (collaboration / sync — this project)
├── M Motif (chess app design system)
├── O ? (still open)
├── T Tabia (chess UX runtime + data)
└── E Engine (future bespoke chess engine)

Tabia’s multi-source merge model is already the collaboration model. That’s not a coincidence — it’s why OpenFile fits the stack so cleanly.

graph LR
PGNS["N PGNs · different annotators<br/>(batch — today)"] --> MERGE
EDITS["live edits over time · N clients<br/>(streaming — OpenFile)"] --> MERGE
MERGE["Tabia merge model<br/>commutative · per-author attribution"] --> TREE["one attributed tree<br/>variations · comments · NAGs, per author"]
classDef key fill:#2563eb,color:#fff,stroke:#93c5fd,stroke-width:2px;
class MERGE key;

The two modes differ only on the temporal axis; they converge on the same merge model and the same attributed tree.

Tabia’s current merge (mergeGames) takes N PGN records authored by different annotators and produces ONE attributed tree. The data shape:

  • Mainline comments are per-author comment_segments with stable attribution.
  • Variations are owned wholesale via variationOwner — same-author sub-trees stay quiet under one label, different-author sub-trees stand out at the depth where they diverge.
  • NAGs track per-source contributions; conflict-only migration preserves attribution when authors disagree.

This is the same data shape that real-time collaboration would produce — except the temporal axis differs:

  • Merge (current): batch — N PGNs arrive, merge produces one tree.
  • OpenFile: streaming — edits arrive over time from N clients, applied incrementally to a shared tree.

The data structure doesn’t change. The algorithm doesn’t fundamentally change either: an incremental edit (“Alice adds a variation after move 14”) is just a single-source merge step (“graft Alice’s variation as a sibling, stamped variationOwner: alice”). The same code path Tabia already runs, just driven by an event rather than a batch.

This means OpenFile’s role is delivery, not data model. The protocol ships deltas; Tabia applies them; the merged tree updates in place.

graph LR
U["Alice edits<br/>add variation @ move 14"] --> OPT["optimistic<br/>local apply"]
OPT --> WIRE["delta event<br/>over the wire"]
WIRE --> APPLY["peers apply-event<br/>single-source merge step"]
APPLY --> TREE["shared tree updates<br/>stamped variationOwner: alice"]
classDef key fill:#2563eb,color:#fff,stroke:#93c5fd,stroke-width:2px;
class APPLY key;

Why the merge model is commutative (and why that matters)

Section titled “Why the merge model is commutative (and why that matters)”

For two independent annotators, the merge is order-independent: applying Alice’s edits then Bob’s produces the same result as Bob’s then Alice’s, because they’re attributed to different segments and own different sub-trees. This is what makes conflict-free collaboration possible.

Within a single annotator’s contributions, edits need ordering (Alice’s second edit may rely on her first). Within-author ordering is a much narrower concurrency problem than full-CRDT-on-arbitrary-document.

Practical implication: OpenFile probably doesn’t need a heavyweight CRDT library. The merge model’s natural commutativity carries most of the weight; only same-author-same-segment conflicts need ordering, and those can be handled with last-write-wins + per-author edit sequence numbers.


1. Coach + student session. A coach is reviewing a student’s game. The student is the original annotator (their prose comments). The coach adds their own variations and prose. Both work in real time. Output: the student’s game + the coach’s analysis, side-by-side, attributed.

2. Tournament prep with a partner. Two players prepping the same opening explore variations together. Each adds their own analysis; overlapping ideas appear as parallel sibling variations under one parent move. Disagreements surface naturally.

3. Multi-author opening repertoire. A team maintains an opening book. Each contributor’s authorship is preserved per-variation. Edits flow through the team; merge conflicts are rare because authors work in different variations.

4. Live broadcast commentary. Multiple commentators annotating a running game. Their commentary appears attributed to each, in real time. Replay viewers see “Carlsen said X here, Caruana said Y.”

5. Public collaborative study. Like Lichess Studies but platform-independent — any PROMOTE-based app can host or join one.


Architectural decisions already implied by Tabia’s current shape

Section titled “Architectural decisions already implied by Tabia’s current shape”

These choices are load-bearing for collaboration, and they’re already made — building OpenFile on Tabia means inheriting them.

  • Identity = annotator string. Each user has a stable handle. The same string flows through merge, attribution, filter, presence indicators. Identity is opaque to the data layer; consumers resolve it via their own identity layer (DB lookup, federated identity, etc.).
  • Non-destructive edits. Each user’s contributions are additive. No user overwrites another. Within-author destructive edits (Alice deletes her own variation) are fine; cross-author destruction is application policy, not data model.
  • Read-time identity resolution. Raw annotator strings live in the data; display normalization (URL-to-handle, Last,First→First Last) happens at read time. This makes identity changes trivially apply retroactively.
  • Permissions live in the app shell, not the data layer. Tabia + OpenFile produce and consume the data shape. Whether user X can write to study Y is the app’s policy. Same for moderation (“Alice deleted Bob’s variation”): app-level rule enforcement.
  • Variations are owned wholesale. A variation is one author’s analysis line, not a collaborative substrate. Two authors with parallel analysis = two parallel sibling variations. This is what makes per-author attribution clean during real-time editing too.

For the kickoff session to evaluate seriously:

  • Plain WebSocket + JSON events. Simplest. Each client sends discrete edit events ({type: 'add-variation', parent: nodeId, sourceMoves: [...]}) to a server, which broadcasts to peers. Server holds canonical state. Trade-off: requires server; no offline editing.

  • WebRTC + peer-to-peer. No server needed for sync; clients negotiate directly. Trade-off: discovery still needs a signaling server; scaling beyond a few peers is awkward.

  • CRDT (Yjs / Automerge). Off-the-shelf CRDT libraries handle the conflict resolution. Trade-off: heavyweight; the merge model’s natural commutativity makes most of this unnecessary; would impose a generic document shape on chess-specific data.

  • Custom CRDT-flavored protocol. Tabia’s tree + per-author attribution is already commutative. A lightweight protocol could exploit this with simple last-write-wins + per-author sequence numbers, without pulling in a generic CRDT library.

My current intuition: plain WebSocket + chess-shaped events, with the chess-shaped events deliberately mapped to Tabia’s existing operations (add variation, add segment, NAG, etc.). The merge model handles commutativity for free. Custom CRDT only if specific use cases force it.


What Tabia would need to expose to support OpenFile

Section titled “What Tabia would need to expose to support OpenFile”

Currently Tabia’s Game produces a static tree. Mutations happen via methods (playMove, setComment, etc.) and fire an onChange callback. OpenFile would need:

  • A delta event stream. Instead of “the whole tree changed,” fine-grained events: “node N added,” “segment added to node M by author A,” “NAG migrated on node K,” “variation owner stamped.”
  • Apply-event API. The receiving side needs a way to apply a delta event to its local Game state. Essentially the same operations mergeMoves already performs, but exposed as discrete callable steps.
  • Optimistic local writes. Edits apply immediately to the local client’s tree, then sync over the wire. If the server / peers reject or modify, the local state reconciles.
  • Identity-aware edit attribution. Every mutation is stamped with the current user’s annotator string before it enters the tree.

These are additive — Tabia’s current static-tree API continues to work. The delta layer is a layer over it, not a replacement.


  1. Wire protocol pick. WebSocket + chess events vs. WebRTC vs. CRDT library. Probably plain WebSocket + chess events; confirm.
  2. Server vs serverless. Does OpenFile mandate a server, or can it work P2P? The latter is simpler operationally but trickier UX for “drop in any time” use cases.
  3. Offline support. Should edits made offline merge cleanly when the client reconnects? (Probably yes — the merge model handles it.)
  4. Identity / auth integration. OpenFile is identity-agnostic, but consumer apps will need to inject identity. What’s the contract?
  5. Permissions model. Most basic: owner + contributors + viewers. More elaborate: per-variation permissions, moderation queues, etc. Probably ship basic; layer more later.
  6. Presence indicators. Who’s viewing right now, who’s actively editing, “Alice is looking at move 14.” Probably real but not v1.
  7. Replay / history. Should OpenFile store edit history for playback? (“Show me how this study evolved.”)
  8. Visual integration with Motif. The annotator filter we’re about to build is one half — presence pills, “Alice is editing” badges, live cursor indicators are visual companions. Where do they live?

What the annotator filter (Motif, in progress) means for OpenFile

Section titled “What the annotator filter (Motif, in progress) means for OpenFile”

The filter component we’re about to build in Motif is foundational for both modes:

  • Local merge case (now): filter which annotators’ content is visible in a viewed merged PGN.
  • Real-time case (future): same filter UI, same per-author state. As collaborators join, new pills appear; as they edit, content updates in place under their attribution.

No filter design change is required for the future. Building it now serves both use cases.


~/chess/
├── PROMOTE/ ← the stack (this project lives here)
│ ├── Tabia/
│ ├── Motif/
│ ├── Rabbit/
│ ├── Priyome/
│ └── OpenFile/ ← this project
├── TNMP/ ← reference implementation
└── ...other apps

Independent git history per project (workspace convention). OpenFile consumes Tabia (for the merge model and tree shape). Apps that want collaboration consume OpenFile + Tabia + their preferred UI layer.


  • Not a roadmap (no timelines or commitments).
  • Not a spec (no API definitions, no protocol details).
  • Not exhaustive (the kickoff session will go far deeper).

It captures the connective tissue between Tabia’s existing merge model and the future collaboration layer — enough that the kickoff session can start with the architectural insight already grounded, instead of re-deriving it.


One-sentence pitch (for when this becomes a real project)

Section titled “One-sentence pitch (for when this becomes a real project)”

OpenFile turns chess content into a shared document — multiple contributors, real-time edits, per-author attribution preserved end to end, built on the same merge model Tabia uses for static multi-source PGNs.