Metric Definition
When to use this skill
Use whenever a metric is being created, re-defined, or disputed. Triggers:
- "Define our North Star metric"
- "What counts as an active user?"
- "Write a spec for revenue per user"
- "Why is finance's revenue number different from ours?"
- "Document this metric"
Most metric arguments are actually definition arguments. Force the question into a spec.
Required inputs
| Input |
Why it matters |
| Metric name |
What stakeholders call it |
| Business question |
What decision the metric supports |
| Owner |
Who is accountable for accuracy |
| Source tables |
Where the underlying data lives |
| Grain |
Per user / session / day / order |
Workflow
Force the business question. "Why does this metric exist?" If the user can't answer, the metric shouldn't exist yet.
Pin down the grain. "Active users per what?" — per day, per week, per month. The same metric name with different grains is three different metrics.
Define the SQL. Even if the user doesn't ask for it, write the canonical query. Vague definitions become inconsistent dashboards.
Identify edge cases up front. For each metric, ask:
- What about deleted/banned users?
- Internal/test users?
- Refunded transactions?
- Multiple devices per user?
- Timezone (event time vs reporting time)?
Define guardrails. A primary metric without guardrails will get gamed. List 1-3 metrics that must not regress when this one moves.
Pick the canonical visualization. A line chart of weekly values? A cohort table? Specify so dashboards stay consistent.
Write the spec in the format below.
Output format
# Metric Spec: <Metric Name>
## Identifier
- **Canonical name:** <snake_case_name>
- **Display name:** <Human Readable>
- **Owner:** <name / team>
- **Last updated:** <YYYY-MM-DD>
- **Status:** <draft | active | deprecated>
## Definition
**Business question:** <What decision does this support?>
**Plain English:** <One sentence anyone in the company can understand.>
**Formula:**
Grain: <per user | per session | per day | per order>
Source
- Primary table:
<warehouse.schema.table>
- Event(s):
<event_name>
- Refresh cadence: <daily | hourly | streaming>
- Latency: <e.g., T+1 day>
Canonical SQL (Snowflake)
```sql
select
date_trunc('week', event_at) as week,
count(distinct user_id) as
from
where event_name = ''
and is_internal_user = false
and event_at >= ''
group by 1
order by 1;
```
Inclusions / Exclusions
- Includes: <e.g., paid + free users>
- Excludes: <e.g., internal users, bots, soft-deleted accounts, test orgs>
Edge cases
- <e.g., refunded transactions are excluded if refund occurred within reporting period>
- <e.g., multi-device users counted once via user_id>
- <e.g., all timestamps in UTC>
Guardrails
- : must not drop >
- : must not exceed
Known caveats
- <e.g., pre-2026 data uses a different event schema; do not compare>
- <e.g., mobile clients have a 24h sync delay>
Canonical visualization
<e.g., 12-week rolling line chart, weekly snapshots, with prior-year overlay>
Anti-patterns (do NOT do this)
- Do not redefine this metric in dashboards without updating this spec
- Do not aggregate this metric across teams that filter for different segments
- Do not present this metric without its guardrails
Related metrics
- : related but distinct, defined as
- : composes with this one for
Change log
- 2026-04-01 — Excluded test_org_ids per data-quality audit
- 2026-01-15 — Initial definition
## Validation checks
- [ ] One canonical SQL query exists and runs
- [ ] Owner is a specific person, not a team alias
- [ ] Grain is unambiguous (no "daily/weekly" or "user/account" hedging)
- [ ] Inclusions and exclusions are explicit
- [ ] At least one guardrail is listed
- [ ] Spec is linked from the dashboards that show this metric
## Edge cases & failure modes
- **Two teams need different filters.** Don't fork. Add a parameter to the canonical metric (e.g., `dau_b2b` and `dau_b2c` both derive from `dau_base`).
- **The metric is calculated differently in different tools.** Pick the canonical query, deprecate the others, migrate dashboards.
- **The metric was wrong yesterday.** Flag in the change log immediately. Backfill if possible. Add a banner in dashboards if not.
- **A new event changes the definition.** This is a v2 metric, not a redefinition. Run both for a transition period.
- **Vanity metrics.** If the business question is "looks good on a slide," reject. Push for a metric tied to a decision.
## Related skills
- `data-quality-audit` — verify source table quality before finalizing
- `modular-sql-ctes` — structure the canonical SQL cleanly
- `stakeholder-readout` — communicate metric definitions to stakeholders
1---2name: metric-definition3description: Writes precise metric specs with grain, owner, source, formula, guardrails, and known caveats. Use when the user mentions metric definition, metric spec, KPI definition, "what is a session", "define X", North Star metric, or needs to disambiguate a metric across teams.4---56# Metric Definition78## When to use this skill910Use whenever a metric is being created, re-defined, or disputed. Triggers:1112- "Define our North Star metric"13- "What counts as an active user?"14- "Write a spec for revenue per user"15- "Why is finance's revenue number different from ours?"16- "Document this metric"1718Most metric arguments are actually definition arguments. Force the question into a spec.1920## Required inputs2122| Input | Why it matters |23|---|---|24| Metric name | What stakeholders call it |25| Business question | What decision the metric supports |26| Owner | Who is accountable for accuracy |27| Source tables | Where the underlying data lives |28| Grain | Per user / session / day / order |2930## Workflow31321. **Force the business question.** "Why does this metric exist?" If the user can't answer, the metric shouldn't exist yet.33342. **Pin down the grain.** "Active users per *what*?" — per day, per week, per month. The same metric name with different grains is three different metrics.35363. **Define the SQL.** Even if the user doesn't ask for it, write the canonical query. Vague definitions become inconsistent dashboards.37384. **Identify edge cases up front.** For each metric, ask:39 - What about deleted/banned users?40 - Internal/test users?41 - Refunded transactions?42 - Multiple devices per user?43 - Timezone (event time vs reporting time)?44455. **Define guardrails.** A primary metric without guardrails will get gamed. List 1-3 metrics that must not regress when this one moves.46476. **Pick the canonical visualization.** A line chart of weekly values? A cohort table? Specify so dashboards stay consistent.48497. **Write the spec** in the format below.5051## Output format5253```markdown54# Metric Spec: <Metric Name>5556## Identifier57- **Canonical name:** <snake_case_name>58- **Display name:** <Human Readable>59- **Owner:** <name / team>60- **Last updated:** <YYYY-MM-DD>61- **Status:** <draft | active | deprecated>6263## Definition64**Business question:** <What decision does this support?>6566**Plain English:** <One sentence anyone in the company can understand.>6768**Formula:**69```70<pseudo-math or English formula>71```7273**Grain:** <per user | per session | per day | per order>7475## Source76- **Primary table:** `<warehouse.schema.table>`77- **Event(s):** `<event_name>`78- **Refresh cadence:** <daily | hourly | streaming>79- **Latency:** <e.g., T+1 day>8081## Canonical SQL (Snowflake)82\`\`\`sql83select84 date_trunc('week', event_at) as week,85 count(distinct user_id) as <metric_name>86from <table>87where event_name = '<event>'88 and is_internal_user = false89 and event_at >= '<start>'90group by 191order by 1;92\`\`\`9394## Inclusions / Exclusions95- **Includes:** <e.g., paid + free users>96- **Excludes:** <e.g., internal users, bots, soft-deleted accounts, test orgs>9798## Edge cases99- <e.g., refunded transactions are excluded if refund occurred within reporting period>100- <e.g., multi-device users counted once via user_id>101- <e.g., all timestamps in UTC>102103## Guardrails104- <guardrail_metric_1>: must not drop > <threshold>105- <guardrail_metric_2>: must not exceed <threshold>106107## Known caveats108- <e.g., pre-2026 data uses a different event schema; do not compare>109- <e.g., mobile clients have a 24h sync delay>110111## Canonical visualization112<e.g., 12-week rolling line chart, weekly snapshots, with prior-year overlay>113114## Anti-patterns (do NOT do this)115- Do not redefine this metric in dashboards without updating this spec116- Do not aggregate this metric across teams that filter for different segments117- Do not present this metric without its guardrails118119## Related metrics120- <metric>: related but distinct, defined as <how>121- <metric>: composes with this one for <decision>122123## Change log124- 2026-04-01 — Excluded test_org_ids per data-quality audit125- 2026-01-15 — Initial definition126```127128## Validation checks129130- [ ] One canonical SQL query exists and runs131- [ ] Owner is a specific person, not a team alias132- [ ] Grain is unambiguous (no "daily/weekly" or "user/account" hedging)133- [ ] Inclusions and exclusions are explicit134- [ ] At least one guardrail is listed135- [ ] Spec is linked from the dashboards that show this metric136137## Edge cases & failure modes138139- **Two teams need different filters.** Don't fork. Add a parameter to the canonical metric (e.g., `dau_b2b` and `dau_b2c` both derive from `dau_base`).140- **The metric is calculated differently in different tools.** Pick the canonical query, deprecate the others, migrate dashboards.141- **The metric was wrong yesterday.** Flag in the change log immediately. Backfill if possible. Add a banner in dashboards if not.142- **A new event changes the definition.** This is a v2 metric, not a redefinition. Run both for a transition period.143- **Vanity metrics.** If the business question is "looks good on a slide," reject. Push for a metric tied to a decision.144145## Related skills146147- `data-quality-audit` — verify source table quality before finalizing148- `modular-sql-ctes` — structure the canonical SQL cleanly149- `stakeholder-readout` — communicate metric definitions to stakeholders