Give the two graph stores GitHub's native version control — every curation a gist revision, with real
diffs, restore, and sync across machines — while keeping the library fully usable with no GitHub account.
What already exists (this epic does NOT rebuild it)
What is missing is the difference between sharing and syncing: today a gist is a one-shot export
someone chooses to publish. Nothing keeps a gist as the store's living remote, so the store's own evolution
has no remote history.
Why the in-app history is not already this
A component record carries rev + history, but a history entry is
{"at","by","changed":["composes","srcText"],"rev":9} — it records that a change happened and which
fields, never the previous content. So today you cannot diff a curation, see what a field used to hold,
or restore it. Gist revisions give exactly that, for free, and pair with the rev we already keep.
The principle this must not break
Local stays authoritative; the gist is a synced remote. #2444 established render local-first and never
token-gate. If a gist were the store, a user with no GitHub connection would have no algorithms library
and no component library — the Design Studio and the librarian would both stop working. Every write
therefore lands locally first and syncs when connected; disconnected behaviour is byte-identical to today.
Shape: ONE GIST PER STORE
algorithms.json — the algorithms library document.
components.json — the component store's JSON projection.
One gist per store gives a clean linear history (one revision per curation, one document to reconcile).
Per-RECORD gists would give finer history and conflict-free parallel edits, but that is ~120 algorithms +
~267 components = hundreds of remote objects and a rate-limit problem on every full sync. Start here;
per-record granularity is a later refinement if whole-document conflicts prove painful in practice.
Reuse the fingerprint we already have
#4192 put the sha256-of-body stamp contract in bsc-cli-util::vendored, shared by both emitters. The
same hash decides whether a remote revision is ahead, behind, or diverged from local — the sync must
reuse it rather than invent a second content comparison.
Slices
- Sync core — push the local document as a gist revision on change; pull on connect. Local wins on
write; a pull that would overwrite local changes stops and reports rather than clobbering (the
Diverged verdict, same shape as emit sync).
- Connection-aware, never gating — with no token the store behaves exactly as today, and the UI says
"not synced" rather than failing or hiding the library.
bsc graph gist / bsc ui gist — status · push · pull · url, so a live session (and the
librarian/designer) can see and drive sync from its own shell.
- History surfacing — the record inspector links its gist revisions, so "what did this look like
before" is one click. This is the payoff the in-app history cannot deliver alone.
- Conflict reporting — a diverged store is a stated, actionable state (which side is newer, what
differs), never a silent overwrite in either direction.
Acceptance for the epic
Give the two graph stores GitHub's native version control — every curation a gist revision, with real
diffs, restore, and sync across machines — while keeping the library fully usable with no GitHub account.
What already exists (this epic does NOT rebuild it)
gist_create/gist_updateTauri commands (src-tauri/src/github/api.rs).features/planner/lib/gist/, Distributable extensions: blueprint+pipeline CRUD, gist sharing, sandboxed code pipelines #598/App-state demo via a typed gist (kind: "app-state") #2272) alreadyused by blueprints and app-state.
kitGist.ts(Make the app's own components the first UI kit — generatereact-uifrom the manifest registry #2305) — publish a component KIT as a typed gist and import it back by URL/share code.What is missing is the difference between sharing and syncing: today a gist is a one-shot export
someone chooses to publish. Nothing keeps a gist as the store's living remote, so the store's own evolution
has no remote history.
Why the in-app history is not already this
A component record carries
rev+history, but a history entry is{"at","by","changed":["composes","srcText"],"rev":9}— it records that a change happened and whichfields, never the previous content. So today you cannot diff a curation, see what a field used to hold,
or restore it. Gist revisions give exactly that, for free, and pair with the
revwe already keep.The principle this must not break
Local stays authoritative; the gist is a synced remote. #2444 established render local-first and never
token-gate. If a gist were the store, a user with no GitHub connection would have no algorithms library
and no component library — the Design Studio and the librarian would both stop working. Every write
therefore lands locally first and syncs when connected; disconnected behaviour is byte-identical to today.
Shape: ONE GIST PER STORE
algorithms.json— the algorithms library document.components.json— the component store's JSON projection.One gist per store gives a clean linear history (one revision per curation, one document to reconcile).
Per-RECORD gists would give finer history and conflict-free parallel edits, but that is ~120 algorithms +
~267 components = hundreds of remote objects and a rate-limit problem on every full sync. Start here;
per-record granularity is a later refinement if whole-document conflicts prove painful in practice.
Reuse the fingerprint we already have
#4192 put the
sha256-of-body stamp contract inbsc-cli-util::vendored, shared by both emitters. Thesame hash decides whether a remote revision is ahead, behind, or diverged from local — the sync must
reuse it rather than invent a second content comparison.
Slices
write; a pull that would overwrite local changes stops and reports rather than clobbering (the
Divergedverdict, same shape asemit sync)."not synced" rather than failing or hiding the library.
bsc graph gist/bsc ui gist—status·push·pull·url, so a live session (and thelibrarian/designer) can see and drive sync from its own shell.
before" is one click. This is the payoff the in-app
historycannot deliver alone.differs), never a silent overwrite in either direction.
Acceptance for the epic
no prompt.
bsc-cli-util::vendoredhash contract rather than a second comparison.