Skip to main content

Module: dashboard / widgets

The "one-stop" landing surface — common status widgets at a glance (backend health, recent agent sessions, tasks, feeds, metrics).

Status: implemented — frontend in packages/core/src/modules/dashboard/. The dashboard is no longer a grid panel: it is the default seeded workspace (see ../architecture/windowing.md), a layout of common widget-panes. This module's job is now to (1) contribute its own widgets and (2) provide the command to jump to the Dashboard tab. It has no backend surface — workspace layouts persist through backend/modules/workspace/.

Contributions to the layout shell

  • Widgets: dashboard.welcome (intro card, defaultPlacement: left) and dashboard.backendStatus (polls /api/health every 10s, defaultPlacement: right). Other modules contribute more widgets (clubhouse.account, observability.io).
  • Commands: dashboard.open — selects the Dashboard workspace tab (registry.switchWorkspace('dashboard')).

The default Dashboard is seeded on first run by the workspace (DASHBOARD_PRESET in Workspace.tsx): dashboard.welcome, dashboard.backendStatus, observability.io opened as panes in a 2-column arrangement.

The widget contract

A widget is a registry contribution (id, title, React component, optional requiredCapabilities, optional defaultPlacement). Widgets are opened as panes in the workspace — dockable, resizable, floatable like panels (one level, no separate board). Every widget is openable from the command palette (synthesized widget.open:<id> → "Open widget: <title>") and from the "Add widget…" picker in the workspace tab strip. Capability-gated widgets are filtered by the capability service before they appear in the picker.

Widget data comes from each owning module's own backend routes; the dashboard module knows nothing about other widgets' internals — the same inversion as panels-in-the-shell.

Browser vs desktop

Widgets behave identically in both layouts. Differences come only from individual widgets' capability requirements:

ConcernBrowserDesktop
Capability-gated widgets (e.g. a local system-metrics widget needing desktop APIs)hidden from the picker, slot shows nothingavailable
Backend-sourced widgets (sessions, tasks, feeds)identicalidentical

A widget that is available in one layout and not the other must come from a requiredCapabilities declaration — never from platform sniffing inside the widget. When adding a capability-gated widget, list it in the table above.

Agent context

The backend-status widget exposes a getAgentContext() snapshot (reachability plus the app name/version when reachable), so the agent can answer "is the backend up?" without its own tool. See agent tools.