Skip to main content
The Business Hub is RStack’s live, local dashboard on port 3008 — a company-wide view of every governed run across every project on the machine, rendered from the same .rstack/ files the CLI and the agents read. There is no database and no telemetry leaves the machine. This page is the front door: how to launch it, how the six-destination navigation shell (issue #278) is structured, and how the freshness indicator keeps every page honest about how live its data is. The rest of the Business Hub section covers each destination’s real content in depth.

Launch it

The hub opens automatically when a governed session starts (Pi, the Claude Code SessionStart hook, and Operator all launch it). You can also bring it up manually:
Or run the server directly:
Default port is 3008 (override with RSTACK_BUSINESS_PORT). Disable auto-launch with RSTACK_NO_BUSINESS_HUB=1. The legacy rstack-observer command is a compatibility alias that opens the same hub.

How it works

Six destinations, not a flat page list

The shell (src/observability/dashboard/ui/navigation.js) is built from a small fixed list of destinations, each holding one or more children (pages). Only a destination’s non-hidden children render as secondary-nav links; hidden children are still routable (a URL or deep link still opens them) but don’t clutter the nav: Each destination has a defaultPage — the child it opens on when you click the primary nav button — and clicking a destination’s primary link expands its secondary nav (navigationGroups in navigation.js). The mobile nav (mobileNavigationMarkup) renders the same groups inside a role="dialog" panel with focus trapping and Escape-to-close.
Approvals was promoted into the visible nav in #537: it had been hidden alongside the legacy review pages even though it is the only surface where a human can approve or reject a gate. Action Inbox still triages first; Approvals is where you act.

Routing: hash + query params, shareable

parseDashboardRoute({ hash, search }) reads ?page= from the query string and #page=…&run=…&section=… from the hash (a bare hash like #traceability with no = is treated as a page id directly, for backward compatibility). formatDashboardHash writes it back. This means every page — and, for the Run Workspace, every tab section (summary | work | timeline | artifacts | metrics) — has a shareable URL; showPage() calls history.pushState/replaceState on every navigation, and the popstate handler restores both the page and the run scope from the URL on back/forward.

Page-switch motion is a live-DOM fade, not the View Transitions API

showPage() toggles .page.active and lets CSS handle the fade. The comment in navigationScript documents a deliberate rejection (issue #521): the View Transitions API suppresses painting and hit-testing of the live page for ~160–250ms during the transition, so a click landing right after a navigation would vanish. The plain CSS fade keeps the page interactive on every frame instead.

Page bodies are static shells; data fills them in later

pages/index.js’s pageMarkup() renders one <section class="page" id="page-<id>"> per entry in navigation.js’s pages list, each with a shared head (page-title, a <div class="last-updated"> slot) and a per-page body from pageBody(id). The bodies here are empty containers — KPI tiles, <table> skeletons, panel <div>s with ids like command-attention, overview-proof-rail, ops-transport-body — that the client-side data layer fills once a snapshot arrives. The Command Center body (the Overview destination’s only child) is the richest: a delivery-outcome banner fed by the server-owned readiness projection, a Proof Rail (overview-proof-rail), an executive mission brief, KPI grid, and Needs Attention / Stage Health / Active Delivery / Recent Activity panels — all real .rstack data, never invented placeholder numbers.

Freshness: the topbar never claims data is live when it isn’t

freshness.js’s classifyFreshness(opts) is a pure function evaluated both server- and client-side against { hasData, now, lastSnapshotAt, wsConnected, staleMs, disconnectMs } (defaults: 10s stale, 30s disconnect):
  • no data yet → loading
  • snapshot older than disconnectMsdisconnected, regardless of what the socket reports
  • socket down but a poll or push still landed recently → reconnecting
  • socket up but no snapshot inside staleMsstale (the server-side poll stalled)
  • otherwise → live
freshnessLabel() turns that into the topbar text (“Live · updated HH:MM:SS”, “Stale · data as of HH:MM:SS”, etc.) and freshnessDotClass() maps it to the existing status-dot styling. The dashboard is built to never silently show stale data as if it were current.

Scope: project → run, shareable

A project/run switcher in the top bar scopes every page to the run you care about; SCOPE.run and SCOPE.project persist across reloads and are restored from the URL’s run param (restoreScopeFromRoute) — so a link like #page=run-workspace&run=<runKey> deep-links straight into a specific run’s workspace, handy for sharing in Slack.

Multi-project aggregation

The hub reads a global registry at ~/.rstack/known-projects.json that every rstack-agents init and hub call updates, so one running hub instance shows runs across every project on the machine. Multiple people can point the same hub (or the same notification channel) at it.

Try it

Open the hub, then try the shell mechanics directly:
Both are real, bookmarkable URLs — parseDashboardRoute/formatDashboardHash round-trip them, and popstate will restore the same page + run + section on browser back/forward.
Some children exist and are fully routable but are deliberately not shown in the nav (hidden in navigation.js) — e.g. Workflow Map, Run Analytics, Security, Compliance, Team & Presence. They’re superseded-in-nav, not removed; deep links and internal cross-links still open them.

Cockpit Controls

Authenticated, audited actions the Hub can take against a run (resume, checkpoint restore).

Approvals & Governance

The Action Inbox and Approvals destination in depth.

Data Visualizations

Quality/risk dials, the stage subway strip, and Spend Center charts.

Operations Center

Transport freshness, integrations, recovery, and context/memory health in one page.