Skip to content

The UI

The hub UI is the observability console, served at <hub>/ui. That is the one the fleet runs and the one make run-gui shows you.

There is a second browser surface in the tree — the Fleet IDE in ide/ — but no hub serves it. It is a local prototype, and it is documented below as one. ADR 0025 records that decision and why the tree used to claim the opposite.

Note that <hub>/ and the /dashboard/* API routes require a bearer token, so an unauthenticated browser hitting the bare host sees 403, not the UI. The front door is /ui.

graph LR
    subgraph "Observability Console — /ui (the hub UI)"
        C1["Live movement"]
        C2["Stuck work"]
        C3["Agents · Projects"]
        C3b["Mission Control"]
        C4["Pipelines"]
        C5["Telemetry"]
        C6["Task drill-down"]
    end
    subgraph "Fleet IDE — ide/ (prototype, not served)"
        I1["Task Kanban"]
        I2["Task Inspector"]
        I3["Project tree"]
    end
    API["hub API"]
    C1 & C2 & C3 & C3b & C4 & C5 & C6 -->|GET only| API
    I1 & I2 & I3 -->|GET + mutations| API

The observability console (/ui) — the hub UI

Served at /ui and /ui/console. Built from observe/ (React + Vite) into src/mac/ui/console/, which is committed — so serving it needs no Node.js at runtime. Rebuild with make build-gui (or npm --prefix observe run build); CI fails if the committed bundle drifts from source.

Run it locally against a hub with make run-gui, which starts the same source tree's dev server on http://127.0.0.1:5274 and proxies to $MAC_API_URL. tests/ui/test_hub_ui_is_one_tree.py asserts that what run-gui runs and what the hub serves stay one tree.

It is read-only, and that is the design. observe/tests/readonly.test.ts asserts it. The command-and-control dashboard that used to live here was retired: it called /dispatch/tick, /agents/bulk, /roles/seed, /notifier/deliver and /secrets, and a UI whose job is to observe cannot also be the one that commands.

Views

view answers
Live what is moving right now — transitions per time bucket, stacked by the state work moved into
Stuck work what has not moved, oldest first
Agents who is registered, and whether the hub's belief is supported by evidence
Projects per-project counts and repository registration; names open Mission Control
Mission Control one project's live dependency DAG — explorer, viewport, inspector
Pipelines publication and review progress
Telemetry model and command usage
Task drill-down: history with detail, evidence, reviews, transcripts

Two properties it will not trade

A section it could not read is absent, not zero. If the hub fails to answer for one section, that section is omitted and named in degraded — never rendered as a plausible empty result. A section showing "0 failures" because a table is missing is exactly the failure the console exists to catch.

Unknown is not a default. A land rate with no attempts shows —, not 0%. Never-happened and happened-badly are different facts.

A useful next action

The Task view separates reported tests, operator acceptance, publication, and recorded deployment evidence. Missing evidence stays unknown. It also shows state-specific CLI commands to inspect, answer, stop, or diagnose the task, plus the required authority. Run them using an authenticated profile for the same hub. The hub rereads state and enforces permissions when the command runs; a command displayed earlier may no longer be applicable.

This is an actionable handoff while the console remains read-only. See the trust workflow for acceptance and recovery.

The live view

The Live chart is the one worth understanding. A count tells you 360 tasks are blocked. Only a series over time tells you whether they are arriving or draining — which is the difference between a backlog and a leak.

Mission Control

Mission Control is the additional view ADR 0018 reserved and ADR 0034 accepted: a project-scoped SVG DAG in this same console, not a board and not the Fleet IDE.

It answers "what is waiting on what in this project". The hub sends a bounded graph (GET /dashboard/observe/projects/{project}/graph): live tasks fill the cap first, each edge carries join policy and a dead/pending/satisfied verdict, and a section the hub could not read is omitted rather than drawn as an empty canvas. Deep-link with ?view=mission-control&project=NAME. Click a project name on the Projects view to open it.

The table spine (Live, Stuck, Projects) stays the way to scan the whole fleet. A 6,000-task project will say what was omitted; it will not pretend to have laid out every row.

The Fleet IDE (ide/) — prototype, not deployed

No hub serves this. It runs only from a checkout, against a hub it reaches through a local Vite proxy. It is not what you see at <hub>/ui, and nothing in make install, make build, or a deploy produces it.

The mutating surface it prototypes: a task Kanban laned by state, a task inspector, and a project tree — answering a parked task, directing an agent, working a queue.

The Kanban lanes are task states, and it deliberately has no drag-and-drop: task states are a control-plane state machine with legal-move rules, leases and evidence requirements, so most lane-to-lane drags would be illegal. A board that offers a move it cannot make teaches you the UI lies about what it can do.

Run it with make ide-run after mac admin login. It has its own ide-* targets precisely so no generic "gui" target can hand it to you by mistake.

Which one am I in?

If you reached it at <hub>/ui, it is the console: read-only, and that is a guarantee rather than an oversight. If you started it yourself from ide/ and it offers to change something, it is the prototype.

Getting a token in

The console reads a bearer token from ?t=<token> on first load and moves it into session storage, stripping it from the URL. It shares the storage key with the IDE, so a session in one carries into the other.