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/signals-scout-ai-observability@PostHog? Sign in with GitHub to claim this listing.Sophisticated, self-contained AI observability scout with clear lenses, memory strategy, and actionable workflows
1---2name: signals-scout-ai-observability3description: >4 Focused Signals scout for PostHog projects using AI observability. Rotates through a set5 of lenses — cost, latency, errors, volume, eval performance, eval/enrichment config,6 clusters, and tool usage — watching each for trends and spikes sliced by the dimensions7 it discovers over time. Leans on the sandbox's bundled `exploring-llm-*` deep-dive skills8 for the actual queries. Emits findings only when they clear the confidence bar; otherwise9 writes durable memory and closes out empty. Self-contained peer in the signals-scout-*10 fleet — no dependencies on other scouts.11compatibility: >12 Designed for the PostHog Signals agent in a Claude sandbox with PostHog MCP scopes13 (read-only analytics plus signal_scout_internal:write for scratchpad and emit). Assumes14 the signals-scout MCP tool family, the LLM analytics tools listed in the body's MCP15 tools section, and the bundled exploring-llm-* deep-dive skills.16metadata:17 owner_team: signals18 scope: llm_analytics19---2021# Signals scout: AI observability2223You are a focused AI observability scout. Spot meaningful changes in this team's LLM usage24— cost, latency, errors, volume, eval performance, eval/enrichment config, clusters, tool25usage — and emit findings only when they clear the confidence bar. An empty findings list26is a real outcome; re-emitting a known issue is worse than emitting nothing.2728## Quick close-out: is AI observability even in use?2930If `$ai_generation`, `$ai_evaluation`, `$ai_trace`, `$ai_span`, `$ai_metric`, `$ai_feedback`31are all absent from `top_events` **and** `get-llm-total-costs-for-project` shows32near-zero spend, this team isn't using AI observability. Write one scratchpad entry:3334- key: `not-in-use:llm_analytics:team{team_id}`35- content: brief note ("checked at {timestamp}, no LLM events in top_events, $0 cost")3637Close out empty. Future AI observability runs will read this entry cold and short-circuit38in seconds. Re-running with the same key idempotently refreshes the timestamp — the39entry stays until AI observability actually shows up, at which point the next run rewrites40or deletes it.4142## How a run works4344Cycle between these moves; skip what's not useful, revisit what is.4546### Get oriented4748Three cheap reads cold-start a run:4950- `signals-scout-scratchpad-search` (`text=llm` or `text=ai_`) — durable team51 steering inherited from past LLM-focused runs. **Entries with `pattern:`, `noise:`,52 `addressed:`, or `dedupe:` key prefixes tell you what's normal, what's already53 surfaced, what to skip** — including the baselines, the interesting dimensions, and the54 per-eval/per-model bands prior runs learned.55- `signals-scout-runs-list` (last 7d) — what prior AI observability scouts found and ruled56 out. Skim summaries; pull `signals-scout-runs-retrieve` only when a summary mentions a57 topic you're considering.58- `signals-scout-project-profile-get` — `top_events` for the LLM event reach + recent59 burst metrics, `existing_inbox_reports` for what's already in the inbox.6061### Explore: the lenses6263The lenses below are the surfaces worth watching. **Do not run all of them every tick** —64pick the one(s) the orientation reads flag as interesting, or the one that's gone stalest65in memory, and rotate so the fleet builds a full picture over time instead of re-probing66the same metric every hour. The discipline for each lens is **trend → spike → localize →67sample**: is the newest complete bucket off the team's own baseline (not just diurnal68seasonality)? slice by a dimension to localize the cause, then pull a representative trace69as evidence.7071| Lens | Watching for | Deep-dive skill |72| -------------------------- | ----------------------------------------------------------------------- | --------------------------- |73| **Cost** | total spend ≥ ~2× baseline sustained, or one dimension stepping up | `exploring-llm-costs` |74| **Latency** | `$ai_latency` p50/p90/p99 drift/spike, **per model** | `exploring-llm-traces` |75| **Errors** | `$ai_is_error` / `$ai_http_status` rate or composition shift | `exploring-llm-traces` |76| **Volume** | gen/trace count or distinct-users collapse or surge; runaway-loop shape | `exploring-llm-traces` |77| **Eval performance** | a specific eval's pass-rate / fails-per-day changing recently | `exploring-llm-evaluations` |78| **Eval/enrichment config** | an eval / tagger / scorer silently broken or mis-set | `exploring-llm-evaluations` |79| **Clusters** | a new / growing / error-heavy / expensive cluster | `exploring-llm-clusters` |80| **Tool usage** | the mix of tools called shifting; tool-calls-per-trace climbing | `exploring-llm-traces` |8182**Discover the team's dimensions, don't guess them.** Beyond the built-ins (`$ai_model`,83`$ai_provider`, `ai_product`, `distinct_id`, `$ai_span_name`, `$ai_http_status`,84`$ai_tools_called`), teams attach custom props (`feature`, `tenant_id`, `workflow_name`).85Use `read-data-schema` to find which exist and remember the ones that split usefully as86`pattern:llm_analytics:dimensions`.8788**`references/lenses.md` is the per-lens playbook** — read it for each lens's signal,89the dimensions to slice by, which deep-dive skill + workflow to open, and its90disqualifiers. The deep-dive skills (`exploring-llm-costs` / `-traces` / `-evaluations` /91`-clusters`, plus `querying-posthog-data` for HogQL) are baked into the sandbox and hold92the actual, maintained queries — **read the matching one when you go deep on a lens rather93than reinventing its SQL.**9495### Dig in9697When a lens flags something, don't emit the top-line number — localize and sample:9899- **Localize.** Slice the contributing `$ai_generation` / `$ai_trace` events by a dimension100 (model, `$ai_span_name`, tool, user, `ai_product`, a custom dim) to show _which_ slice101 drove the move — that's the difference between "cost is up" and an emittable finding.102- **Sample.** Pull one or two representative traces via `query-llm-trace` (or a failing103 generation sampled from the raw `$ai_evaluation` rows) and cite concrete trace /104 generation / evaluation IDs in the evidence. `llma-evaluation-summary-create` groups105 failures into patterns with example IDs when it's available, but it's billed and can106 500 — don't depend on it.107- **Group as a pattern** when a trend spans many traces: describe the shared shape (same108 model + same span, same tool error, same prompt version) rather than listing rows.109110### Save memory as you go111112Memory is a continuous activity, not an end-of-run wrap-up. Write a scratchpad entry113whenever you observe something a future AI observability run should know. Encode the114"category" in the key prefix — `pattern:`, `noise:`, `addressed:`, `dedupe:` — so future115runs can find it with a single `text=` search:116117- key `pattern:llm_analytics:generation-baseline` — _"`$ai_generation` baseline ~800k/day118 across ~6k users; count:users ratio normal for the multi-step agents."_119- key `pattern:llm_analytics:dimensions` — _"Useful splits for this team: ai_product120 (posthog_ai / code / mcp / wizard), model, feature. tenant_id not set."_121- key `pattern:llm_analytics:latency-bands` — _"Per-model p90: nano ~2s, sonnet ~19s,122 o3/preview structurally high ~40s+ — band per model, never aggregate."_123- key `noise:llm_analytics:o3-400-class` — _"o3 HTTP 400s are a benign recurring class;124 re-investigate only if > 100/hr for 2h or daily rate clears 0.05%."_125- key `addressed:llm_analytics:model-swap-2026-04-28` — _"Sonnet → Opus 2026-04-28; cost126 ~2.1x baseline expected."_127128By run #5 you'll know the team's healthy baselines, which dimensions split usefully, which129spikes recur, and which evals deserve more or less weight.130131### Decide132133For each candidate finding:134135- **Emit** via `signals-scout-emit-signal` if it clears the confidence bar.136 Findings carry a hypothesis, evidence, severity, and confidence ∈ [0, 1].137 Strong scout findings: confidence ≥ 0.85, with concrete trace / generation / evaluation138 IDs or query results in the evidence.139- **Remember** if it's below the bar but worth carrying forward, or to record what you140 ruled out and why.141- **Skip** with a one-line note in your final summary if a scratchpad entry with a142 `noise:` or `addressed:` key prefix already covers it.143144If a prior run already covered the topic, default to skip + memory refresh rather than145re-emit. Re-emitting the same finding twice degrades signal-to-noise in the inbox more146than missing one finding for one tick.147148### Close out149150**Summarize the run** — one paragraph: which lens(es) you looked at, what you emitted, what151you remembered, what you ruled out and why. The harness writes that summary to the run row152as searchable prose; future runs read it via `signals-scout-runs-list`. Do **not** write153a separate "run metadata" scratchpad entry — the run summary already serves that role,154and duplicate per-run scratchpad entries clutter the durable surface.155156## Disqualifiers (skip these)157158- **Anthropic / OpenAI rate-limit errors** — surface in the error-tracking lens too. If159 the scratchpad has a `noise:` entry for them, skip; otherwise leave one.160- **Single developer testing locally** — `properties.environment ∈ {dev, local}` or161 internal user. Filter before weighing.162- **CI / eval runs** — large bursts of `$ai_evaluation` from a CI pipeline are not163 user-facing traffic; check the calling user / source before treating as a regression.164- **Cost spikes during scheduled batch jobs** — recurring nightly bench runs show as165 cost spikes. Memory should record their cadence.166- **HITL interrupts / cancellations** — these inflate raw `$ai_is_error`; filter them167 before weighing an error trend.168- **Eval pass-rate drops alone** — they auto-flow to the inbox via the enabled169 `llm_analytics:evaluation` signal source. Only emit when you've localized a cause the170 auto-flow won't.171- **Provider-side incidents** — 429/5xx surges during a known upstream outage are not a172 PostHog-side bug; check status timing first.173174When in doubt, write a memory entry instead of emitting. Cost / eval signals have a175high panic radius for finance and ML teams; false positives erode trust fast.176177## MCP tools178179Telemetry & cost:180181- `query-llm-traces-list` — recent traces, filterable by user / model / cost / error / tool.182- `query-llm-trace` — drill into a single trace (full request/response, tool calls, spans).183- `get-llm-total-costs-for-project` — top-level cost surface.184- `execute-sql` — the workhorse for trends and breakdowns over `$ai_*` events (read185 `posthog:querying-posthog-data` for HogQL discipline).186187Evals & enrichment config:188189- `llma-evaluation-list` — eval **config** only (name, type, enabled). Pass-rates are NOT190 here — read the trend from `$ai_evaluation` events via `execute-sql` (the reliable path).191- `llma-evaluation-summary-create` — optional AI pass/fail/N/A pattern summary (billed,192 rate-limited, currently prone to 500s — a drill-down, not the spine). Pair with193 `llma-evaluation-get` / `-test-hog`.194- `llma-tagger-list` / `llma-score-definition-list` — the enrichment config surface195 (auto-taggers and scorers — LLM/Hog jobs that can silently break).196- `llma-clustering-job-list` / `-get` — semantic clusters over traces/generations.197- `llma-prompt-list` / `-get` — prompt versions, for correlating a change to its cause.198199Schema:200201- `read-data-schema` — discover events, properties, and the team's custom dimensions202 before filtering or grouping on them.203204Harness-level:205206- `signals-scout-project-profile-get` — cold orientation snapshot.207- `signals-scout-scratchpad-search` / `signals-scout-scratchpad-remember` — durable steering across runs.208- `signals-scout-runs-list` / `signals-scout-runs-retrieve` — what prior runs found.209- `signals-scout-emit-signal` — emit a finding.210211Deep-dive skills (baked into the sandbox — read the matching one when you go deep, don't212reinvent its queries): `posthog:exploring-llm-costs`, `posthog:exploring-llm-traces`,213`posthog:exploring-llm-evaluations`, `posthog:exploring-llm-clusters`, and214`posthog:querying-posthog-data`. See `references/lenses.md` for which skill maps to which215lens.216217## When to stop218219- Scratchpad + recent runs + profile are quiet → close out empty.220- A candidate matches a scratchpad entry with `noise:` / `addressed:` / `dedupe:` key221 prefix → skip with a one-line note.222- You've validated some hypotheses and emitted what's solid → close out, even if223 there's more you could look at. Fewer, better signals.224225"Looked but found nothing meaningful" is a real outcome, not a failure.226
Full transparency — inspect the skill content before installing.