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 reads running — the live pulse, since a task’s stored status stays todo for 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 an integrate tag 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 claude subprocess 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-tokenGITHUB_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.