/investigate-metric
Diagnose why a product metric changed (dropped, spiked, or plateaued) by orchestrating breakdowns, actors, paths, lifecycle, retention, and annotations queries. Use when the user reports an anomaly, asks "why did X change?", asks to explain or walk them through a chart, or needs
Claude Code
$ npx -y skills add PostHog/ai-plugin --skill investigate-metric --agent claude-code
Codex
$ npx skills add PostHog/ai-plugin --skill investigate-metric -a codex -y
Cursor
$ npx skills add PostHog/ai-plugin --skill investigate-metric -a cursor -y
Gemini CLI
$ npx skills add PostHog/ai-plugin --skill investigate-metric -a gemini-cli -y
GitHub Copilot
$ npx skills add PostHog/ai-plugin --skill investigate-metric -a github-copilot -y
OpenCode
$ npx skills add PostHog/ai-plugin --skill investigate-metric -a opencode -y
Windsurf
$ npx skills add PostHog/ai-plugin --skill investigate-metric -a windsurf -y
SKILL.md
investigate-metric.SKILL.mdname: investigate-metric
description: >
Diagnose why a product metric changed (dropped, spiked, or plateaued) by
orchestrating breakdowns, actors, paths, lifecycle, retention, and annotations
queries. Use when the user reports an anomaly, asks "why did X change?", asks
to explain or walk them through a chart, or needs root-cause analysis for a
trend, funnel, retention, stickiness, or lifecycle metric.
Investigating a metric change
For "why did X change?" questions about a saved insight, dashboard tile, or pasted query, and for "explain this chart" or "walk me through this" when the user names no change. Don't load this skill for plain "what is X?" questions — only when there's a chart or an observed change to explain.
Tools
Targets PostHog MCP v2. Typed query tools accept the query body directly — pass `kind`, `series`, `dateRange` as top-level fields, do not wrap in `InsightVizNode`.
| Tool | Purpose | | -------------------------------- | ------------------------------------------------ | | `posthog:query-trends` | Trends (count over time) | | `posthog:query-funnel` | Funnels (multi-step conversion) | | `posthog:query-retention` | Retention (cohort return rates) | | `posthog:query-stickiness` | Stickiness (active days per user) | | `posthog:query-lifecycle` | Lifecycle (new/returning/resurrecting/dormant) | | `posthog:query-paths` | Paths (navigation flow) | | `posthog:query-trends-actors` | Users behind a trend bucket (trends source only) | | `posthog:execute-sql` | Existing SQL insights and custom analysis | | `posthog:read-data-schema` | Discover events, properties, sample values | | `posthog:insight-get` / `-query` | Fetch a saved insight's metadata / data | | `posthog:explain-chart` | Walk the user through a trends chart (Step 5) |
Plus the standard PostHog tools the playbooks reference by name (`feature-flag-get-all`, `experiment-list`, `annotations-list`, `query-error-tracking-issues-list`, `query-logs`, `query-session-recordings-list`, `cohorts-list/-create`, `annotation-create`, `insight-create`).
Helper scripts
- [`compare_to_prior_periods.py`](./scripts/compare_to_prior_periods.py) — auto-detects
interval and compares recent values to the natural cycle (day-of-week, hour-of-week, or sequential). Use to resolve step 2.2 cheaply.
- [`breakdown_attribution.py`](./scripts/breakdown_attribution.py) — ranks breakdown
segments by absolute delta and flags offsetting moves.
python3 scripts/compare_to_prior_periods.py < query_result.json
WINDOW=7 python3 scripts/breakdown_attribution.py < breakdown_result.json
Step 1 — Classify the metric
Read `query.kind` from the source the user pointed at:
- Saved insight (URL, `short_id`): `posthog:insight-get` → `query.kind`. Use
`posthog:insight-query` if you also need the numbers.
- A query you already ran or the user pasted: read `kind` directly.
- A metric the user only names, such as "signups", or shows in a screenshot: find its event
with `posthog:read-data-schema` and run it as one series over time with `posthog:query-trends`. That query is your `TrendsQuery`. When `query-trends` cannot express the metric, such as a warehouse-only metric or a custom SQL join, run it with `posthog:execute-sql` and treat it as a `HogQLQuery`.
- Nothing pointed at, or several events could be the metric: ask which one. Don't guess.
| kind | Playbook | | ----------------- | ------------------------------------------------------------- | | `TrendsQuery` | [trend-playbook.md](./references/trend-playbook.md) | | `FunnelsQuery` | [funnel-playbook.md](./references/funnel-playbook.md) | | `RetentionQuery` | [retention-playbook.md](./references/retention-playbook.md) | | `StickinessQuery` | [stickiness-playbook.md](./references/stickiness-playbook.md) | | `LifecycleQuery` | [lifecycle-playbook.md](./references/lifecycle-playbook.md) | | `PathsQuery` | [paths-playbook.md](./references/paths-playbook.md) | | `HogQLQuery` | route by what the SQL aggregates (see below) |
If `kind === "TrendsQuery"` and `trendsFilter.display === "BoxPlot"`, use [box-plot-playbook.md](./references/box-plot-playbook.md) — distribution metric, no breakdowns.
For `HogQLQuery` insights, classify by the SQL's shape: count over time → trend playbook, multi-step conversion → funnel playbook, cohort return → retention playbook. Run the SQL through `posthog:execute-sql` to get the data, then follow the closest playbook's steps. See **HogQL insights** in shared-patterns.md.
If the user's question spans multiple kinds, run the playbooks in sequence.
Choose how you will show the findings
Decide this now, before the investigation, because it changes which queries you keep.
When the user gave you a saved insight or a query that is a `TrendsQuery` over time (not a box plot, 2D heatmap or scatter plot), or named a metric you ran as one, the investigation ends with a chart explanation from `posthog:explain-chart`. `posthog:explain-chart` exists only where chart explanations are enabled, so check for it now and read its schema. Where PostHog tools run through `exec`, it is not in your own tool list: run `info explain-chart` before you decide it is missing. When it does not exist, the findings go in a written report. The chart explanation is the answer, in place of a notebook or a long reply. Write a notebook as well only when the user asks for one. For anything else, such as a metric that only SQL can express, the findings go in a written report.
When it is a chart explanation:
- Add "Show the chart explanation (Step 5)" as the
Read more
name: investigate-metric description: > Diagnose why a product metric changed (dropped, spiked, or plateaued) by orchestrating breakdowns, actors, paths, lifecycle, retention, and annotations queries. Use when the user reports an anomaly, asks "why did X change?", asks to explain or walk them through a chart, or needs root-cause analysis for a trend, funnel, retention, stickiness, or lifecycle metric.
Investigating a metric change
For "why did X change?" questions about a saved insight, dashboard tile, or pasted query, and for "explain this chart" or "walk me through this" when the user names no change. Don't load this skill for plain "what is X?" questions — only when there's a chart or an observed change to explain.
Tools
Targets PostHog MCP v2. Typed query tools accept the query body directly — pass `kind`, `series`, `dateRange` as top-level fields, do not wrap in `InsightVizNode`.
| Tool | Purpose | | -------------------------------- | ------------------------------------------------ | | `posthog:query-trends` | Trends (count over time) | | `posthog:query-funnel` | Funnels (multi-step conversion) | | `posthog:query-retention` | Retention (cohort return rates) | | `posthog:query-stickiness` | Stickiness (active days per user) | | `posthog:query-lifecycle` | Lifecycle (new/returning/resurrecting/dormant) | | `posthog:query-paths` | Paths (navigation flow) | | `posthog:query-trends-actors` | Users behind a trend bucket (trends source only) | | `posthog:execute-sql` | Existing SQL insights and custom analysis | | `posthog:read-data-schema` | Discover events, properties, sample values | | `posthog:insight-get` / `-query` | Fetch a saved insight's metadata / data | | `posthog:explain-chart` | Walk the user through a trends chart (Step 5) |
Plus the standard PostHog tools the playbooks reference by name (`feature-flag-get-all`, `experiment-list`, `annotations-list`, `query-error-tracking-issues-list`, `query-logs`, `query-session-recordings-list`, `cohorts-list/-create`, `annotation-create`, `insight-create`).
Helper scripts
- [`compare_to_prior_periods.py`](./scripts/compare_to_prior_periods.py) — auto-detects
interval and compares recent values to the natural cycle (day-of-week, hour-of-week, or sequential). Use to resolve step 2.2 cheaply.
- [`breakdown_attribution.py`](./scripts/breakdown_attribution.py) — ranks breakdown
segments by absolute delta and flags offsetting moves.
python3 scripts/compare_to_prior_periods.py < query_result.json WINDOW=7 python3 scripts/breakdown_attribution.py < breakdown_result.json
Step 1 — Classify the metric
Read `query.kind` from the source the user pointed at:
- Saved insight (URL, `short_id`): `posthog:insight-get` → `query.kind`. Use
`posthog:insight-query` if you also need the numbers.
- A query you already ran or the user pasted: read `kind` directly.
- A metric the user only names, such as "signups", or shows in a screenshot: find its event
with `posthog:read-data-schema` and run it as one series over time with `posthog:query-trends`. That query is your `TrendsQuery`. When `query-trends` cannot express the metric, such as a warehouse-only metric or a custom SQL join, run it with `posthog:execute-sql` and treat it as a `HogQLQuery`.
- Nothing pointed at, or several events could be the metric: ask which one. Don't guess.
| kind | Playbook | | ----------------- | ------------------------------------------------------------- | | `TrendsQuery` | [trend-playbook.md](./references/trend-playbook.md) | | `FunnelsQuery` | [funnel-playbook.md](./references/funnel-playbook.md) | | `RetentionQuery` | [retention-playbook.md](./references/retention-playbook.md) | | `StickinessQuery` | [stickiness-playbook.md](./references/stickiness-playbook.md) | | `LifecycleQuery` | [lifecycle-playbook.md](./references/lifecycle-playbook.md) | | `PathsQuery` | [paths-playbook.md](./references/paths-playbook.md) | | `HogQLQuery` | route by what the SQL aggregates (see below) |
If `kind === "TrendsQuery"` and `trendsFilter.display === "BoxPlot"`, use [box-plot-playbook.md](./references/box-plot-playbook.md) — distribution metric, no breakdowns.
For `HogQLQuery` insights, classify by the SQL's shape: count over time → trend playbook, multi-step conversion → funnel playbook, cohort return → retention playbook. Run the SQL through `posthog:execute-sql` to get the data, then follow the closest playbook's steps. See **HogQL insights** in shared-patterns.md.
If the user's question spans multiple kinds, run the playbooks in sequence.
Choose how you will show the findings
Decide this now, before the investigation, because it changes which queries you keep.
When the user gave you a saved insight or a query that is a `TrendsQuery` over time (not a box plot, 2D heatmap or scatter plot), or named a metric you ran as one, the investigation ends with a chart explanation from `posthog:explain-chart`. `posthog:explain-chart` exists only where chart explanations are enabled, so check for it now and read its schema. Where PostHog tools run through `exec`, it is not in your own tool list: run `info explain-chart` before you decide it is missing. When it does not exist, the findings go in a written report. The chart explanation is the answer, in place of a notebook or a long reply. Write a notebook as well only when the user asks for one. For anything else, such as a metric that only SQL can express, the findings go in a written report.
When it is a chart explanation:
- Add "Show the chart explanation (Step 5)" as the
Official PostHog plugin for AI clients. Access PostHog products directly from your AI coding tool.
Other skills on ai-plugin.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about investigate-metric.
- Which coding agents can use investigate-metric?
- investigate-metric installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

