🦞🎬 Architecture & Protocol Specification

flowchart TD
  subgraph CLIENTS["Surfaces"]
    SPA["Web SPA (SvelteKit)"]
    EXT["Chrome Extension (WXT)"]
    PWA["Mobile PWA"]
  end
  subgraph GATEWAY["StoryFlow Gateway (Bun 1.4 :7540)"]
    WSS["Bun.serve WebSocket Server"]
    REST["REST Endpoints (/snapshot, /api)"]
    DB[(bun:sqlite SSOT)]
    JQ["Job Queue & Scheduler"]
    REG["Registry (capabilities.yml)"]
  end
  subgraph OMP["omp Runtime (omp --mode rpc)"]
    RPC["RPC v2 stdio Bridge"]
    PROD["Production Session"]
    SUB["Subagents Swarm"]
  end

  SPA <-->|WebSocket: deltas / ui.request| WSS
  EXT <-->|WebSocket in SW| WSS
  PWA <-->|WebSocket| WSS
  SPA -->|GET /snapshot?since=seq| REST

  WSS <--> JQ
  JQ <--> DB
  JQ <--> REG
  JQ <--> RPC
  RPC <--> PROD
  PROD <--> SUB

1. Repository Layout (§2.3 SSOT)

The repository follows a clean monorepo structure:

storyflow/
  apps/
    gateway/          # Bun daemon: omp rpc bridge, WS/REST, SQLite SSOT, job queue, registry
    face/             # SvelteKit SPA (adapter-static + fallback), PWA manifest
    panel/            # WXT: sidepanel, background SW (WebSocket), flow content scripts
  packages/
    protocol/         # Zod envelopes: events, jobs, shots, contributions (written first)
    ui/               # Svelte 5 + daisyUI 5 shared component library (Vite lib mode)
    plugins/          # First-party departments: film, game, app medium adapters
  evidence/           # Audit evidence, receipts, screenshots
  CHEATSHEET.md       # Human bible
  sum.yml             # Machine SSOT twin (wins on conflict)
  old-flow-files/     # Frozen archive (Flow2API, FlowTurbine, Arcade Cabinet)

2. Gateway ↔ omp RPC Specification (§2.4 SSOT)

The gateway interacts with omp using the documented RPC v2 protocol over JSONL stdio:

ConcernImplementation Rule
Spawnomp --mode rpc --profile storyflow, lazy per production, idle-disposed.
FramesSend negotiate_protocol v2 on receiving the ready frame. Reassemble rpc_chunk frames (maxFrameBytes 1 MiB, reassembled ceiling 64 MiB) with RpcFrameDecoder.
ResumeRespawn process + switch_session { sessionPath } + get_messages_page replay. Never trust process liveness. On session_busy or stale_cursor, discard partial page and retry.
Turn CompletionA turn is complete only on agent_end with isTerminal !== false. The prompt response is merely an acknowledgement.
Extension UIextension_ui_request (select, confirm, input, editor) renders as a <dialog> on connected clients. Answered with extension_ui_response.
Agent WritesRegister storyflow:// via set_host_uri_schemes (writable) so agent shot edits route through the gateway daemon, eliminating two-writer drift.
Todos & MirroringMirror the production plan into omp using set_todos. Subscribe to subagent events using set_subagent_subscription: "events" to feed the Agents crew tree.
SSOT BoundarySQLite owns productions, shots, jobs, asset_index. External files like LEDGER.md, vault bible, and session JSONL are agent-owned and imported as snapshots.
Spend TrackingThe Wall’s $ metric is calculated from our own job ledger. Broker usage is labelled “≤5 min stale”.
Job QueueConcurrency controlled per-provider from the registry; exponential retry backoff; idempotent resume; provenance sidecar per asset; preflight cost calculation required.

3. Protocol Envelopes (§2.5 SSOT)

Communication across the single WebSocket connection uses strictly typed JSON envelopes:

Envelope Schema

{
  "v": 2,
  "t": "shot.update",
  "prod": "prod_01a0be9f",
  "seq": 42,
  "data": { ... }
}
  • v (number): Protocol version (currently 2).
  • t (string): Envelope kind / topic.
  • prod (string): Target production ID.
  • seq (number): Monotonically increasing sequence number for state synchronization.
  • data (object): Typed payload.

Envelope Kinds

  1. snapshot: Full state transfer for client catch-up.
  2. shot.*: Shot CRUD and state transitions (shot.created, shot.updated, shot.deleted).
  3. job.*: Queue execution states (job.queued, job.started, job.completed, job.failed).
  4. asset.*: Produced media and provenance sidecars (asset.created, asset.promoted).
  5. agent.*: Swarm status, plans, and subagent tree updates (agent.event, agent.todo).
  6. ui.request: Server-to-client dialog prompts (e.g., bible veto, approval modals).
  7. ui.response: Client-to-server responses to UI prompts.
  8. ping / pong: Heartbeat keepalive.

Keepalive & Reconnect

  • Daemon Ping: The gateway pings every 20 seconds. This is critical for Chrome MV3 service workers which terminate on idle sockets even on Chrome 116+.
  • Reconnect Handshake:
    1. Client detects disconnect or visibilitychange event.
    2. Client issues REST GET /snapshot?since=<seq>.
    3. Client reconnects WebSocket and resumes receiving deltas from seq.
  • Optimism Principle: Optimistic UI is permitted only when local and reversible (e.g. text entry, ordering). Run actions, cost deductions, and approvals must wait for the server echo.