Spec: docs/superpowers/specs/2026-08-23-web-ui-rewrite-design.md § Server, § The data contract.
Depends on #533 (the serialisation contract).
What ships
GET /api/* endpoints covering the data behind the eight routes keel/web/server.py serves today — /, /setup, /activity, /insights, /rules, /venues, /gates, /glossary(*) — using #533's serialiser.
(*) /glossary has no API counterpart. It becomes an outbound link (#539) and its renderer is deleted.
The API is a further consumer of the same frozen report dataclasses the console already builds. It never computes.
Server-side sort
Tables sort by query parameter; Python orders with Decimal. Sub-millisecond on loopback, zero client arithmetic to audit.
GET /api/config
Exposes the running version. Consumed by:
Engine-not-running is a first-class state
The payload carries "engine": "running" | "stopped" and an as_of timestamp. The client must be able to say "keel isn't running" rather than render an empty view or, worse, a stale figure. This is the same requirement the service worker enforces from the other side.
Writes stay exactly as gated as they are
POST continues to route only through keel.commands.setup.ACTIONS, and the existing test asserting that set is disjoint from the eleven capability-increasing actions in keel/capabilities.py must keep passing unchanged. Nothing in this issue widens what the browser may do.
Acceptance
Spec:
docs/superpowers/specs/2026-08-23-web-ui-rewrite-design.md§ Server, § The data contract.Depends on #533 (the serialisation contract).
What ships
GET /api/*endpoints covering the data behind the eight routeskeel/web/server.pyserves today —/,/setup,/activity,/insights,/rules,/venues,/gates,/glossary(*) — using #533's serialiser.(*)
/glossaryhas no API counterpart. It becomes an outbound link (#539) and its renderer is deleted.The API is a further consumer of the same frozen report dataclasses the console already builds. It never computes.
Server-side sort
Tables sort by query parameter; Python orders with
Decimal. Sub-millisecond on loopback, zero client arithmetic to audit.GET /api/configExposes the running version. Consumed by:
?v=so version skew is visible rather than silent.Engine-not-running is a first-class state
The payload carries
"engine": "running" | "stopped"and anas_oftimestamp. The client must be able to say "keel isn't running" rather than render an empty view or, worse, a stale figure. This is the same requirement the service worker enforces from the other side.Writes stay exactly as gated as they are
POSTcontinues to route only throughkeel.commands.setup.ACTIONS, and the existing test asserting that set is disjoint from the eleven capability-increasing actions inkeel/capabilities.pymust keep passing unchanged. Nothing in this issue widens what the browser may do.Acceptance
Decimal, with a test on a case where float ordering would differ.GET /api/configreturns the running version.ACTIONS-disjointness test is untouched and green.test_console_thinness.pypins the API layer.