A collection of PostHog skills for enhancing AI-assisted workflows. Add this repo as a Claude Code plugin marketplace to get access to all PostHog skills: Then install individual plugins: Or browse available plugins: Copy any skill directory to .claude/skills/ in your project: Any directory under skills/ that contains a .claude-plugin/plugin.json is automatically discovered and added to the market
Add this skill
npx mdskills install PostHog/investigate-metric@PostHog? Sign in with GitHub to claim this listing.Comprehensive root-cause diagnostic framework with playbooks, helper scripts, and clear evidence collection workflow
1---2name: investigate-metric3description: >4 Diagnose why a product metric changed (dropped, spiked, or plateaued) by5 orchestrating breakdowns, actors, paths, lifecycle, retention, and annotations6 queries. Use when the user reports an anomaly, asks "why did X change?", or7 needs root-cause analysis for a trend, funnel, retention, stickiness, or8 lifecycle metric.9---1011# Investigating a metric change1213For "why did X change?" questions about a saved insight, dashboard tile, or pasted query.14Don't load this skill for plain "what is X?" questions — only when there's an observed15change to explain.1617## Tools1819Targets PostHog MCP v2. Typed query tools accept the query body directly — pass20`kind`, `series`, `dateRange` as top-level fields, do not wrap in `InsightVizNode`.2122| Tool | Purpose |23| -------------------------------- | ------------------------------------------------ |24| `posthog:query-trends` | Trends (count over time) |25| `posthog:query-funnel` | Funnels (multi-step conversion) |26| `posthog:query-retention` | Retention (cohort return rates) |27| `posthog:query-stickiness` | Stickiness (active days per user) |28| `posthog:query-lifecycle` | Lifecycle (new/returning/resurrecting/dormant) |29| `posthog:query-paths` | Paths (navigation flow) |30| `posthog:query-trends-actors` | Users behind a trend bucket (trends source only) |31| `posthog:execute-sql` | HogQL — when no typed tool fits |32| `posthog:read-data-schema` | Discover events, properties, sample values |33| `posthog:insight-get` / `-query` | Fetch a saved insight's metadata / data |3435Plus the standard PostHog tools the playbooks reference by name (`feature-flag-get-all`,36`experiment-get-all`, `annotations-list`, `query-error-tracking-issues-list`, `query-logs`,37`query-session-recordings-list`, `cohorts-list/-create`, `annotation-create`,38`insight-create`).3940## Helper scripts4142- [`compare_to_prior_periods.py`](./scripts/compare_to_prior_periods.py) — auto-detects43 interval and compares recent values to the natural cycle (day-of-week, hour-of-week,44 or sequential). Use to resolve step 2.2 cheaply.45- [`breakdown_attribution.py`](./scripts/breakdown_attribution.py) — ranks breakdown46 segments by absolute delta and flags offsetting moves.4748```bash49python3 scripts/compare_to_prior_periods.py < query_result.json50WINDOW=7 python3 scripts/breakdown_attribution.py < breakdown_result.json51```5253## Step 1 — Classify the metric5455Read `query.kind` from the source the user pointed at:5657- Saved insight (URL, `short_id`): `posthog:insight-get` → `query.kind`. Use58 `posthog:insight-query` if you also need the numbers.59- A query you already ran or the user pasted: read `kind` directly.60- Nothing pointed at: ask for the URL or short_id. Don't guess.6162| kind | Playbook |63| ----------------- | ------------------------------------------------------------- |64| `TrendsQuery` | [trend-playbook.md](./references/trend-playbook.md) |65| `FunnelsQuery` | [funnel-playbook.md](./references/funnel-playbook.md) |66| `RetentionQuery` | [retention-playbook.md](./references/retention-playbook.md) |67| `StickinessQuery` | [stickiness-playbook.md](./references/stickiness-playbook.md) |68| `LifecycleQuery` | [lifecycle-playbook.md](./references/lifecycle-playbook.md) |69| `PathsQuery` | [paths-playbook.md](./references/paths-playbook.md) |70| `HogQLQuery` | route by what the SQL aggregates (see below) |7172If `kind === "TrendsQuery"` and `trendsFilter.display === "BoxPlot"`, use73[box-plot-playbook.md](./references/box-plot-playbook.md) — distribution metric, no74breakdowns.7576For `HogQLQuery` insights, classify by the SQL's shape: count over time → trend77playbook, multi-step conversion → funnel playbook, cohort return → retention playbook.78Run the SQL through `posthog:execute-sql` to get the data, then follow the closest79playbook's steps. See **HogQL insights** in shared-patterns.md.8081If the user's question spans multiple kinds, run the playbooks in sequence.8283## Step 2 — Common opening moves8485### 2.1 Confirm the anomaly8687Run the primary tool. Record baseline, current, delta (absolute and %), and the start88of the anomaly window.8990### 2.2 Variance check9192Widen to 3–4× the user's interval (or use `compareFilter: {"compare": true}` on93TrendsQuery / StickinessQuery; for other kinds run two date ranges).94Pipe the widened result through95[`compare_to_prior_periods.py`](./scripts/compare_to_prior_periods.py) — it flags96seasonality, partial right-edge buckets, and real anomalies. If the movement is97normal variance, report that and stop.9899### 2.3 Known changes in the window100101In rough order of signal:102103- `posthog:feature-flag-get-all` → flags with `updated_at` near the anomaly start.104- `posthog:experiment-get-all` → `start_date` / `end_date` near the start.105- `posthog:annotations-list` → `date_marker` near the start.106- `git log` for the window if the repo is reachable (highest signal when available).107108Any match is a hypothesis to confirm in the playbook (usually via breakdown on109`$feature/<flag_key>`, `app_version`, or `utm_source`).110111## Step 3 — Run the playbook112113Open the playbook for the kind from Step 1 and follow its numbered steps. Carry the114record from 2.1 and any candidates from 2.3 into it.115116## Step 4 — Cross-check117118Pick a segment the suspected cause should **not** have affected and rerun there. Stable119in the control = strong hypothesis; moved too = expand the investigation. Skip when1202.2 already explained the movement.121122## Step 5 — Write findings123124Use the format below. Offer to save key charts via `posthog:insight-create`. If a125cause is found and no annotation marks it, offer `posthog:annotation-create`. See126[common-causes.md](./references/common-causes.md) for the cause taxonomy.127128```markdown129# Investigation: <metric>130131**Anomaly**: <baseline> → <current> (<delta>) starting <date>132133## Likely cause134135<one sentence>136137**Confidence**: low | medium | high — <one-line reason>138139**Evidence**140141- <query result>142- <flag / experiment / annotation / commit if applicable>143144## Possible causes (ruled out)145146- <hypothesis>: <why>147148## Affected segment149150- <shared properties of affected users/events>151152## Data gaps153154- <checks skipped and why>155156## Suggested follow-ups157158- <concrete next action>159- <offer to save chart / create annotation>160```161162**Confidence** rule of thumb:163164- **high** — multiple independent signals corroborate (e.g. a segment isolates the165 delta _and_ a flag/version aligns _and_ an error or annotation matches).166- **medium** — one corroborating signal, or strong pattern-match without a167 cross-check.168- **low** — pattern matches a known cause but no corroboration, or the data only169 rules things _out_.170171Link insights and dashboards inline: `[Name](/insights/short_id)`.172173## Reference files174175- Playbooks: [trend](./references/trend-playbook.md),176 [box-plot](./references/box-plot-playbook.md),177 [funnel](./references/funnel-playbook.md),178 [retention](./references/retention-playbook.md),179 [stickiness](./references/stickiness-playbook.md),180 [lifecycle](./references/lifecycle-playbook.md),181 [paths](./references/paths-playbook.md)182- [shared-patterns.md](./references/shared-patterns.md) — recipes used across playbooks183- [common-causes.md](./references/common-causes.md) — cause taxonomy with confirming queries184
Full transparency — inspect the skill content before installing.