Realtime dashboards
developerz.ai dashboards are JSON-defined, SSE-pushed boards you create from any MCP client — Claude Code, Claude Desktop, or directly via the REST API. Every widget is a read-only query: write-shaped queries are rejected at parse time, so agents can define dashboards without mutation risk.
Creating a board
# MCP — create (or replace) a board
dashboard upsert \
--name "PR throughput" \
--widgets '[
{ "kind": "metric", "title": "Open PRs", "query": { "entity": "prs", "filter": {"status": "open"}, "agg": "count" }, "span": 4 },
{ "kind": "timeseries", "title": "PRs merged / day", "query": { "entity": "prs", "filter": {"status": "merged"}, "agg": "count", "bucket": "1d" }, "span": 8 }
]'
upsert is idempotent by name — re-running replaces the board in full (old
widgets dropped, new ones minted in order). Returns the board id (dsh_…) and
the assembled widget list.
Widget kinds
| Kind | Description | Required query fields |
|---|---|---|
metric |
Single number with trend arrow | entity, agg: count|sum |
timeseries |
Time-bucketed line chart | entity, agg, bucket: 1h|1d|7d |
table |
Tabular list, newest-first | entity, fields |
markdown |
Static text / Mermaid diagram | content (string) |
heatmap |
Activity heatmap (e.g. commit cadence) | entity, time_field, bucket |
Layout
Boards use a 12-column grid. Each widget has a span (1–12). Widgets wrap
to the next row automatically — no explicit row/column offsets required.
{ "kind": "metric", "title": "Active boxes", "query": { "entity": "runners", "filter": {"status": "online"}, "agg": "count" }, "span": 3 }
Query grammar
The widget query grammar is intentionally constrained to reads only:
| Field | Values | Notes |
|---|---|---|
entity |
prs, issues, tasks, runners, sessions, ci_jobs, audit_events |
What to query |
filter |
{ field: value } map |
Equality filters only |
agg |
count, sum, avg |
Aggregation function |
bucket |
1h, 1d, 7d, 30d |
Time bucket (timeseries / heatmap only) |
fields |
["field1", "field2"] |
Columns (table only) |
content |
Markdown string | Markdown widget only |
Write-shaped queries (INSERT, mutations, entity: "api_tokens") fail schema
validation and are rejected before reaching the database.
Live updates via SSE
The dashboard app opens one multiplexed SSE stream per account — a single connection fans in several topics, each authorized by its own scope:
GET /v1/streams?topics=tasks,ci
Authorization: Bearer dzai_live_…
When a relevant event lands (new PR, task status change, CI job completed), the server pushes a patch for the affected widget cells. The SolidJS renderer applies patches in place — no full page reload.
Listing and managing boards
# List all account-shared boards
dashboard list
# Get a board + all widget specs
dashboard get --dashboard-id dsh_…
# Delete a board
dashboard delete --dashboard-id dsh_…
Board scopes
| Scope | Who sees it |
|---|---|
custom (default) |
Account-shared — all logged-in members |
| Personal | Dashboard app only — your user-scoped session |
Boards created via the MCP API are always custom (account-shared). Personal
boards are created in the dashboard UI and are visible only to the creator.
PWA and push notifications
Install the dashboard as a PWA (Add to Home Screen) for an app-like experience. Notification preferences are in Settings → Notifications. Supported triggers:
- Task completed / failed
- PR needs review
- CI job failed
- Escalation raised
Full verb reference: MCP verb reference → dashboard.