Skip to content

Cockpit v2 foundation: /api/state JSON snapshot + zero-dep client-rendered SPA shell #206

Description

@robercano

Context

The cockpit today is server-rendered: cockpit.sh (~1.3k lines of bash emitting HTML) builds one static snapshot, and cockpit-serve.sh wraps it with an SSE refresh client and the worker-inspector drawer. Every new feature lands as more string-concatenated HTML inside cockpit.sh, which is at the limit of what it can absorb. The v0.5.0 theme — cockpit as the main interface — needs client-side interactivity (a milestone release board, an interactive dependency graph, a model-routing editor) that server-rendered snapshots can't reasonably deliver.

Constraint that STAYS: zero dependencies. No npm packages, no build step, no CDN/external assets — node built-ins on the server, vanilla JS/CSS/SVG in the browser, self-contained files shipped in the plugin.

Proposal

  1. Split data assembly from rendering in cockpit.sh: a --json mode that emits the full state model as one JSON document — issues (with blocking edges via the existing --parse-blocking seam, labels, priority, milestone), PRs (review + CI state), live worker progress (the same derived task state the HTML panel computes: normalized identity, done-collapse, stale detection), loop health/tick history, needs-human items, model/skill routing, worktrees. One data assembly, two renderers during the transition.
  2. cockpit-serve.sh: add GET /api/state returning that JSON, with the same short-lived cache + /api/refresh bypass semantics as today's HTML cache.
  3. New static SPA page (a single self-contained HTML file with inline JS/CSS, no framework) served at /, rendering everything client-side from /api/state; the existing /events SSE stream triggers re-fetch. The current server-rendered HTML stays reachable at /legacy (and as cockpit.sh's no-server output) until the SPA reaches data parity; retiring it is a follow-up, not this issue.
  4. Keep the fixtures seam end-to-end: --fixtures <dir> must drive --json and /api/state too, so cockpit.test.sh can assert on the JSON shape offline with no gh/network.
  5. Document the state-JSON contract (docs section or a _README top-level key) so the board/graph/editor issues in this milestone build against a stable schema.

Acceptance criteria

  • cockpit.sh --json emits the full state model; schema covers everything the current HTML shows (issues + edges, PRs, workers, loop health, needs-human, routing, worktrees); --fixtures works with it.
  • GET /api/state serves it with caching matching today's HTML cache; /api/refresh still busts it.
  • / serves the SPA shell rendering at least today's sections (issues by module, PRs, live workers, loop health, needs-you strip) from the JSON — data parity required, pixel parity not.
  • No new runtime dependencies, no build step, no external network fetches from the page; degrades to placeholders (not crashes) when gh/network is unavailable, exactly like today.
  • Existing tests keep passing; new fixture-driven tests cover --json and /api/state.

Notes

Metadata

Metadata

Assignees

No one assigned

    Labels

    backlogFiled, not yet approved by the owner - the loop must NOT pick it upenhancementNew feature or requestmodule:harnessOrchestrator machinery under .claudepriority:criticalDrop everything

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions