Dashboards¶
A dashboard is a presentation surface over your derivations. It holds no data logic of its own: each widget binds to a certified derivation by name, supplies parameters, and declares how that derivation's already-verified, already-cached result is rendered. The derivation is the semantic layer; the dashboard is the layout.
That separation is what you trust. A published dashboard can only bind certified derivations, so every number a viewer sees has been verified, not merely rendered from whatever SQL happened to sit behind a tile.
The shape of a dashboard¶
A dashboard is a declarative DashboardSpec, validated against a JSON
Schema the same way a derivation manifest is. It has variables (the filter controls),
pages, and, on each page, a grid of widgets:
{
"specVersion": "2.0",
"kind": "Dashboard",
"name": "revenue_health",
"title": "Revenue Health",
"variables": [
{
"name": "region",
"type": "string",
"control": "multiselect",
"default": ["west"],
"options": { "derivation": "regions", "column": "region" }
}
],
"pages": [
{
"name": "overview",
"widgets": [
{
"id": "mrr",
"type": "metric",
"gridPos": { "x": 0, "y": 0, "w": 6, "h": 4 },
"bind": {
"metric": "mrr",
"filters": [{ "column": "region", "op": "in", "value": "$region" }]
}
},
{
"id": "trend",
"type": "chart",
"gridPos": { "x": 6, "y": 0, "w": 18, "h": 8 },
"bind": { "derivation": "revenue_trend", "params": { "region": "$region" } },
"viz": { "mark": "line", "encoding": { "x": {"field": "month"}, "y": {"field": "revenue"} } },
"interactions": { "crossFilter": { "emit": { "month": "datum.month" } } }
}
]
}
]
}
Binding widgets to derivations¶
Every data-bound widget names a derivation and passes it parameters:
"bind": { "derivation": "monthly_revenue", "params": { "region": "$region" } }
A parameter value is a literal, or the string "$name", which resolves to the current
value of dashboard variable name (a leading $$ escapes a literal dollar sign). This
is the only way a widget consumes a variable; wiring is explicit, so a spec is as
reviewable as code, and there is no hidden magic matching a filter to a column.
Because a derivation is already cached and content-addressed, loading a page is a set of cheap cached reads, and changing a filter re-runs only the widgets whose parameters moved.
Widget types¶
| Type | Renders |
|---|---|
metric |
A KPI/stat card showing one shared metric's value, in the metric's format. |
chart |
A grammar-of-graphics spec over the derivation's rows. |
map |
A geographic layer over a spatially-gated derivation. |
table |
The derivation's rows, with paging and conditional formatting. |
text |
Markdown: either its own content (with $name variable interpolation) or the output of a binded derivation that returns markdown. The one freeform surface. |
filter |
A control bound to a variable. |
There is deliberately no arbitrary-code widget: a bespoke visual belongs in a
derivation that returns markdown, bound to a text widget, so it stays governed and
sandboxed like everything else:
{ "id": "verdict", "type": "text", "gridPos": {"x": 0, "y": 0, "w": 12, "h": 8},
"bind": { "derivation": "cost_fixed_share" } }
A text widget takes content or bind, never both — otherwise which one renders would
be decided somewhere other than the spec.
Metric tiles bind shared metrics¶
A metric tile never computes its own number. It binds a metric from the
semantic layer, the same definition the Metrics page, the agent, and
every other dashboard read, and shows that metric's value in the metric's own format:
{ "id": "mrr", "type": "metric", "gridPos": {"x": 0, "y": 0, "w": 6, "h": 4},
"bind": { "metric": "mrr", "filters": [{ "column": "region", "op": "in", "value": "$region" }] } }
So "MRR" means one thing wherever it appears, and changing its definition changes it
everywhere at once (lineage lists every dashboard that displays it). A filter value
of "$name" follows a dashboard variable; clearing that control drops the filter. To
slice a metric by a dimension or over time, bind it to a chart or table with
groupBy and grain; a metric tile is one number.
A dashboard saved before 0.2.0 may have number tiles that added up a derivation's rows themselves. Those open as notes saying what each one showed, until you define the metric and bind a tile to it; see Upgrading.
Filters, variables, and interactions¶
- Variables are the dashboard's inputs. A
filterwidget renders a control for one; its options are a static list or the distinct values of a derivation's column. - Scope confines a variable to
global(all pages) or a single page. - Cross-filter:
interactions.crossFilter.emitsets variables from a clicked datum, re-resolving every non-immune widget that references them. - Drill-down:
interactions.drillDownsteps through a hierarchy of grouping columns by rebinding a parameter, within the same widget. - Drill-through:
interactions.drillThroughnavigates to a detail page or another dashboard, carrying the current variable state.
Lifecycle: draft and published¶
A dashboard starts as a draft: edits auto-save and are invisible to viewers. When you publish, the current draft is snapshotted as the version viewers see. Publishing runs the certification gate: it refuses if any bound derivation is missing or not yet certified, listing the offenders. This is the guarantee: a published dashboard cannot show a number the oracle has not verified.
Every save appends a revision, so a dashboard has the same diffable, roll-back-able history as code.
What a spec is not¶
The spec defines what renders, and nothing about it decides what the data may say. A widget's numbers come from running the derivation it binds, so a dashboard can only show what that derivation returns, so publishing is gated on every bound derivation being certified.
Scheduled delivery¶
A dashboard can carry subscriptions: a page is snapshotted on a cron cadence under a saved filter state and delivered as an image, PDF, or CSV over email or a webhook. The same scheduler that reruns notebooks fires them.
Authoring from the agent¶
Because a dashboard is a validated declarative spec, the chat agent can compose one the
way it authors a derivation: it builds any missing derivations through the usual
propose → verify → certify loop, then lays them out as a DashboardSpec. An
agent-built dashboard is trustworthy by construction, because it can only publish over
certified building blocks.
See the Dashboard Spec for the normative schema.