Use when building or fixing a KPI dashboard decision-makers must read in one screen: which metrics earn a tile, how each tile is framed to answer a decision, and which chart fits it. NOT defining the metrics or their targets (that is kpi-framework), wiring the data (that is analytics), or writing a narrative status report (that is reporting).
Scanned 9/2/2026
Install to Claude Code
npx -y skills add ericrisco/rsc-harness --skill dashboard --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Dashboard?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ericrisco-dashboard)More formats (shields.io, HTML) on the badges page.
---
name: dashboard
description: "Use when building or fixing a KPI dashboard decision-makers must read in one screen: which metrics earn a tile, how each tile is framed to answer a decision, and which chart fits it. NOT defining the metrics or their targets (that is kpi-framework), wiring the data (that is analytics), or writing a narrative status report (that is reporting)."
tags: [kpi-dashboard, data-visualization, executive-dashboard, chart-selection, dashboard-design, at-a-glance]
recommends: [kpi-framework, analytics, reporting, forecasting, business-intelligence, ab-testing, design, spreadsheet-ops]
origin: risco
---
# dashboard
A dashboard is read in **5 seconds by someone who will not scroll**. If a busy reader cannot grasp business status that fast, the design failed — no matter how accurate the numbers are. Your job here is **arrangement, framing, and chart choice**, producing a checkable artifact:
- `dashboard.yaml` — a tile manifest (each tile: metric, chart, comparison, owner, refresh, decision).
- a one-screen layout sketch placing the north-star top-left.
You do **not** decide which metrics matter (that is [kpi-framework](../kpi-framework/SKILL.md)) and you do **not** wire the data source (that is [analytics](../analytics/SKILL.md)). You take a metric set that already exists and make it readable at a glance.
Run `scripts/verify.sh dashboard.yaml` before you hand off. It checks shape and discipline — tile count 1-9, exactly one `north_star: true`, the required keys on every tile, no banned charts — never whether the numbers are correct.
## The Decision Test gate
No tile exists until its metric names the **action it drives**. Ask: *what does someone do differently based on this number?* If the answer is vague ("good to know", "shows we're growing"), the metric is vanity — cut it or convert it. A tile that changes no decision is decoration.
| Vanity metric (Bad) | Actionable conversion (Good) | Decision it drives |
| --- | --- | --- |
| Total followers | Follower-growth rate WoW | Double down or change content cadence |
| Total page views | Conversion rate by source | Reallocate spend to the converting channel |
| Cumulative signups | Activation rate (signup → key action) | Fix onboarding if activation drops |
| Total revenue (all-time) | MRR + net revenue retention | Whether to hire / extend runway |
| App downloads | 7-day retention | Kill or scale the acquisition channel |
Rule: an always-up counter ("total X") is almost always vanity. Convert it to a **rate or ratio** that can go down. Why: a number that only ever rises never triggers an action.
## Tile budget: 5-9, exactly one north-star
Executive dashboards carry roughly **5 to 9 KPIs**. Human working memory caps near ~7 items; more tiles cause analysis paralysis and the screen stops being a glance.
- Exactly **one** tile flagged `north_star: true`. Why: a glance needs a single first read.
- 4-8 supporting tiles around it. Total ≤ 9.
When a stakeholder demands 20 metrics, do not cram them — **tier**:
- [ ] Does this metric drive a decision the leadership team makes weekly? → main screen.
- [ ] Is it a diagnostic you only check *after* a main tile turns red? → drill-down view, linked from the parent tile.
- [ ] Is it commentary / context that needs prose? → route to [reporting](../reporting/SKILL.md), not a tile.
- [ ] Is it a projection of a metric forward? → [forecasting](../forecasting/SKILL.md), not the live screen.
- [ ] Does the user want to slice it freely by dimension? → [business-intelligence](../business-intelligence/SKILL.md), not a fixed tile.
## Framing every tile
The minimum viable tile is **not** a number. It is a number plus the context that makes it actionable:
```text
value + comparison(target | prior | benchmark) + delta + units + date range
+ RYG status + owner + refresh cadence
```
Bad → Good:
```text
Bad: Churn: 4.1%
Good: Monthly logo churn — 4.1% ▲0.6pp vs prior month (target ≤3.0%) 🔴
Owner: Head of CS · Refresh: daily · Range: May 2026
```
Why each field earns its place:
- **comparison** — a number alone has no "is this good?"; target/prior/benchmark supplies it.
- **delta** — direction and magnitude of change is the second thing the eye wants.
- **units + date range** — "4.1%" of what, over what window; ambiguity kills trust.
- **RYG status** — lets the reader triage in the 5-second glance without reading the number.
- **owner** — every red tile needs an accountable human, or nothing happens.
- **refresh cadence** — tells the reader how stale the number can be; a "real-time" label on a weekly metric is a lie.
## Chart per metric: pick by shape
Choose the chart from the **shape of the question**, not from what looks impressive. Full matrix and edge cases in `references/chart-selection.md`.
| Metric shape | Chart | Why |
| --- | --- | --- |
| Single headline number | Big-number tile + delta | Fastest read; the north-star usually lives here |
| Trend over time | Line | Slope shows direction instantly |
| Category comparison | Sorted horizontal bar | Length is easy to compare; sorting answers "who's worst" |
| Target vs actual | **Bullet chart** | Compact, comparable; replaces gauges/dials |
| Part-to-whole (≤5 parts) | Stacked bar or treemap | Pie only legible to 3-5 slices |
| Correlation | Scatter | Shows relationship between two measures |
| Distribution | Histogram | Shape of spread, not just average |
Kill-list: no `pie` beyond 5 categories (sorted bar instead) and no `gauge` / `dial` (bullet chart instead) — verify.sh rejects both; no dual-axis, which invents correlations that aren't there; no 3D and no donut-with-center-number gimmicks.
## Layout & data-ink
Lay tiles out for the **Z / F scan pattern**: the eye starts top-left, sweeps right, drops down. Put the north-star top-left; group related KPIs together (acquisition cluster, revenue cluster, health cluster).
Apply the **data-ink ratio**: if a pixel shows no new information, remove it. Strip heavy borders, drop shadows, gradients, 3D, background textures — they raise cognitive load without adding meaning.
**Color is meaning, not decoration.** Use a status palette (red/yellow/green) only for status. A rainbow of tile colors with no semantic meaning makes the screen harder, not friendlier.
```text
Before: 9 boxed-and-shadowed tiles, each a different bright color,
3 pie charts, two gauges, no clear starting point.
After: north-star top-left (big number + sparkline);
flat tiles, hairline separators, neutral palette;
RYG reserved for status; bullets replace gauges;
sorted bar replaces the pies.
```
## The artifact: `dashboard.yaml`
Emit a manifest a BI tool, a web app, or a human can build from. Short schema here; full field reference in `references/tile-schema.md`.
```yaml
# dashboard.yaml — one screen, one north-star
title: SaaS Exec Dashboard
date_range: "2026-05"
tiles:
- id: waa
north_star: true
metric: Weekly Active Accounts
chart: big_number # + sparkline trend
value_source: warehouse.fct_active_accounts
units: accounts
comparison: { type: target, value: 1200 }
delta: vs_prior_week
status_logic: "green ≥ target; yellow ≥ 90%; red < 90%"
owner: VP Product
refresh: daily
decision: "If below 90% of target two weeks running, escalate activation work."
- id: nrr
metric: Net Revenue Retention
chart: big_number
comparison: { type: benchmark, value: 110 } # %
units: percent
owner: VP Sales
refresh: monthly
decision: "Below 100% triggers a save/expansion review."
- id: churn
metric: Monthly Logo Churn
chart: line
comparison: { type: target, value: 3.0 }
units: percent
owner: Head of CS
refresh: daily
decision: "Above target investigates cohort + reason codes."
- id: runway
metric: Cash Runway
chart: bullet # actual vs target months
comparison: { type: target, value: 18 }
units: months
owner: CFO
refresh: monthly
decision: "Under 12 months opens fundraise / cost review."
- id: pipeline
metric: New Pipeline by Source
chart: sorted_bar
comparison: { type: prior, value: last_month }
units: currency
owner: Head of Marketing
refresh: weekly
decision: "Shift spend toward the top-converting source."
layout:
north_star: top_left
scan: Z
groups: [growth, revenue, health]
```
The keys verify.sh requires on every tile: `metric`, `chart`, `comparison`, `owner`, `refresh`, `decision`.
## Anti-patterns
| Anti-pattern | Why it fails | Do instead |
| --- | --- | --- |
| 20 tiles on one screen | Past ~7, no one can read it in 5 seconds | Cut to 5-9; tier the rest to a drill-down |
| Vanity metrics (totals, followers) | Never trigger an action | Apply the Decision Test; convert to rates |
| Bare numbers, no comparison | No "is this good?" signal | Add target / prior / benchmark + delta |
| Pie chart with 8 slices | Slices become unreadable | Sorted horizontal bar |
| Gauges and dials | Waste space, resist comparison | Bullet chart |
| Rainbow tile colors | Color reads as meaning when it isn't | Neutral tiles; RYG for status only |
| "Real-time" on everything | False precision; refresh-cost theater | Match refresh to decision cadence |
| It's actually a report | Prose + commentary isn't a glance | Move narrative to reporting |
| No north-star | Reader has no entry point | One `north_star: true` tile, top-left |
## Handoff
Beyond the routes named above: reading out an experiment or variant significance → [ab-testing](../ab-testing/SKILL.md); visual polish, spacing and type scale of the rendered screen → [design](../design/SKILL.md); pulling or joining the underlying numbers in a sheet → [spreadsheet-ops](../spreadsheet-ops/SKILL.md).
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!