Dashboard & steering
Watch the org work — live panels, drill-downs into agents, tasks and agent runs, the requests it raises for you, and the HTTP API behind it.
Last updated
The org runs itself; the dashboard is where you watch it work. It’s an
inspection surface, deliberately read-only — every aspect of the org is visible
(goals, tasks, spend, revenue, meetings, memory, every agent run, every file),
and steering happens through exactly two verbs: chat with the org, and
answer the requests it raises for you. Quorum’s terminal is output-only —
it prints activity and takes no commands; the browser at http://localhost:3000
is where you look.
It’s a zero-dependency HTTP server that renders a fixed set of panels — the layout ships in the binary, so upgrading the CLI brings new panels to every org — and adds a chat at the top.
The panels
Whatever the spec declares, rendered live:
- Org chart — the reporting tree.
- Roster — the employed agents (hires and departures show up here), each with its model, spend, budget use, and a working/idle pulse.
- Goals and the task board — what’s planned and in flight. Each goal
shows its task tally (done / total) beside the progress bar, so real
movement is legible at a glance — and a goal with no tasks planned yet, or two
goals covering the same work, stand out rather than hiding behind a bare
0%. The task board is a dependency graph: tasks are laid out in topological stages (each task one column to the right of its latest dependency), with lines running from every task to the work that builds on it, and colour marking status. A task whose brain is executing right now pulses green and readsrunning— the live pulse, since a task’s stored status staystodofor the whole time an agent works it. Each node also shows the collaboration lineage: its assignee, a⇩ <manager>tag when the work was delegated down, and anintegratetag on a manager’s integration step — so who-handed-what-to-whom reads straight off the board. Click any node for its detail view: status (with a “running now” marker), assignee, goal, attempts, review score, who delegated it, dependencies, the reviewer’s feedback, and the full result. - Requests — pending questions agents have raised for you, including outbound messages held for your approval.
- Live Services — what the org has published and operates, with clickable URLs — see Acting in the world.
- Triggers — every schedule, webhook, inbox, and job, with how many times each has fired.
- CRM — shared contacts.
- Recent meetings — click one and the minutes open right in the file browser.
- Status / spend — today’s and this month’s cost, plus a spend-by-day chart of the last two weeks.
- Revenue — money in: payments the org has booked, per currency, this month and all time — the counterpart to the spend meter.
- Agent runs — every metered run of an agent’s brain with its tokens and
cost; click one for its detail. A row is one run — a
claudesubprocess that, for a task, makes many model and tool calls internally — not a single API call. (The prompt shown there is held in memory for the live view only — it’s never written to disk.) - Health — a read-only failure pulse: how many blocks, cycle errors,
timeouts, force-accepts, and deferrals happened recently, with the latest
few and their class (
quota/auth/transient/…). It’s the one place a deferral shows: provider weather (an API overload or rate-limit) is retried quietly rather than escalated, so without this panel that recovery would be invisible outside the terminal. Empty means healthy. - Audit feed — a live stream of every bus message and system action (SSE), with a filter box to narrow by actor or action.
When the org verifies its mission complete and stands down, the header status
changes from live to mission accomplished and a green banner pins above
the panels with the lead’s final report — so a finished org reads as done,
not as if it were merely paused.
Click an agent anywhere and its drawer opens: an overview, its current work, its memory, recent activity, and your direct-message history with it — the quickest way to see what one agent is actually doing.
Chat — steer the org
From the chat box you do two distinct things:
Message the whole org
A general directive that steers the org: it’s folded into the next cycle as a directive and becomes a goal. This is how you redirect priorities — “Ship the pricing page before outreach” — mid-run.
Message a specific agent
Pick an agent from the dropdown; that agent replies directly, in character.
The whole conversation is logged (logs/chat/messages.jsonl) and shown live.
Requests — answer what agents can’t do themselves
Agents ask you only for things no one inside the org can provide — a human outside it: provision a Gmail account, grant access or credentials, authorize a spending increase, or sign off on a real-world action. Decisions that are the org’s to make — priorities, re-scopes, quality judgments — go to a manager up the chain, never to you. An agent raises a request during its work by emitting a line:
REQUEST[<kind>]: <what it needs>
which the runtime turns into a pending request. Requests are the one moment the autonomous org depends on you, so they’re impossible to miss: a banner pins above the panels whenever any are pending — who’s asking, what kind, the related task — and the tab title carries a count with a dot on the favicon, visible from another tab. Each request has Approve / Deny / Answer… — “Answer…” takes free text (paste the account details, give a decision). Your answer is written into the requesting agent’s memory and inbox, and the originating task is re-opened, so the agent actually receives what it asked for and uses it next cycle.
Handing over a credential? Include lines of the form
SECRET[<name>]: <value> in your answer. Each one is stored in the org’s
secrets store and granted to the
requesting agent — it receives the credential as an env var in its sessions
(github-token → GITHUB_TOKEN), and the value never lands in its memory, the
chat, or the logs.
Approving an outbound message? When a channel is set to ask, an agent’s
outgoing message (a Slack post, an email) waits here with its exact text —
yes sends it as written, no drops it. See
Acting in the world.
Capability ask decisions surface the same way — as a
REQUEST[capability:<x>] for you to grant. See Permissions.
Browse files — inspect what the org produced
Browse files in the header opens a read-only file browser rooted at the org
home. Navigate the whole tree — each agent’s working directory and MEMORY.md,
the shared workspace/ systems, logs/, the QUORUM.md itself — click a folder
to descend, click a file to read it inline. Markdown files render formatted —
headings, lists, tables, links, with any frontmatter set apart at the top — and
a View raw toggle shows the exact text. The current directory refreshes live,
so new files an agent writes appear as they land.
It’s strictly read-only and confined to the org home: paths that try to escape
(../, symlinks out of the tree) are refused. Credential material is never
served — the secrets/ store and dotenv files are hidden from listings and
refused on read, symlinks included — so the browser upholds the same
names-never-values rule as every
other surface. Files are served up to 512 KB; binary files are flagged rather
than dumped.
The HTTP API
The dashboard is a thin client over a small API — useful if you want to build your own view or automate steering.
| endpoint | purpose |
|---|---|
GET / |
the dashboard HTML |
GET /api/state |
current org state (chart, roster, goals, tasks, requests, …) |
GET /api/spec |
the dashboard layout (panel list) the binary ships |
GET /api/metrics |
spend and counters |
GET /api/call?ts= |
one agent run’s detail (tokens, cost, prompt — live view only) |
GET /api/files?path= |
list a directory in the org home (path relative, "" = root) |
GET /api/file?path= |
read one file — { content, size, truncated, binary } |
GET /api/events |
live server-sent events (the audit feed) |
POST /api/message |
{ to, text } — to is "all" or an agent id |
POST /api/request |
{ id, decision, note } — answer a pending request |
The POST endpoints honor the control secret (below) as a Bearer token
or X-Quorum-Secret header when one is set; bound beyond loopback, the GETs
require it too.
Binding & exposure
The dashboard exposes full org state and the org’s files, so it binds to
loopback (127.0.0.1) by default. Bind beyond loopback and quorum requires
a control secret on every endpoint — reads included, since agent memory,
prompts, and workspace files are all served: your own via
QUORUM_DASHBOARD_SECRET, or one generated at boot and printed once in the
terminal. The dashboard prompts for it once, then remembers it in the browser.
On loopback, the steering POSTs honor a secret if you set one explicitly and
reads stay open.
quorum --host 0.0.0.0 # every endpoint demands the control secret
QUORUM_DASHBOARD_SECRET=s3same quorum # pin your own secret (any host)
quorum --port 3001 # run several orgs on different ports
quorum --headless # no dashboard server at all
The secret is a single shared token, not user accounts — for anything more than a trusted LAN, put a real proxy or tunnel in front.