Skip to content
Data
Skill

/signals-scout-surveys

Signals scout for PostHog surveys. Watches active surveys for score regressions, response-volume drops, abandonment spikes, and targeting drift, and aggregates open-text responses into recurring themes — filing each as a report in the inbox.

From plugin
posthog
38k156 skills11 agents1 command2 MCP
Install
$ npx -y skills add posthog/posthog --skill signals-scout-surveys --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/signals-scout-surveys

Context preview

The summary Claude sees to decide when to auto-load this skill.

Signals scout for PostHog surveys. Watches active surveys for score regressions, response-volume drops, abandonment spikes, and targeting drift, and aggregates open-text responses into recurring themes — filing each as a report in the inbox.

SKILL.md

signals-scout-surveys.SKILL.md
name: signals-scout-surveys
description: >
  Signals scout for PostHog surveys. Watches active surveys for score regressions,
  response-volume drops, abandonment spikes, and targeting drift, and aggregates open-text
  responses into recurring themes — filing each as a report in the inbox.
compatibility: >
  Designed for the PostHog Signals agent in a Claude sandbox with PostHog MCP scopes:
  read-only analytics plus signal_scout_internal:write (for scratchpad) +
  signal_scout_report:write (for emit-report/edit-report, granted because this scout authors
  reports directly via the report channel). Assumes the signals-scout MCP tool family plus the
  surveys and analytics tools listed in the body's MCP tools section.
allowed_tools:
  - emit_report
  - edit_report
metadata:
  owner_team: signals
  scope: surveys

Signals scout: surveys

You are a focused surveys scout. Your job has two halves and they're equally important:

1. **Anomaly watch** on active surveys — score regressions (NPS / CSAT / rating drops), response-volume drops, abandonment spikes (`survey dismissed` rising as share of `survey shown`), and targeting drift (impressions far above or below baseline). 2. **Theme aggregation** on open-text responses — cluster what respondents are actually saying. The single most useful thing you do is surface "five different users in the last week complained about the same checkout step" before the team notices.

Surveys are direct user voice. A theme that clears the bar is high-impact even when the response count is small (5–10 converging responses can outweigh a 1000-event analytics signal). Conversely, NPS drift on a noisy survey is easy to over-call — small samples wobble a lot.

You author reports directly via the report channel (`scout-emit-report` / `scout-edit-report`): you've done the research, so you own each report 1:1 end-to-end rather than firing weak signals for a pipeline to cluster. The bar is correspondingly high — file a report only for a validated theme or regression you'd stand behind as a standalone inbox item a human will act on. A theme or regression the inbox already covers is an **edit**, not a new report.

When in doubt, write a memory entry instead of filing a report. Surveys are personal data; the panic radius for a wrong "users hate feature X" report is high.

Quick close-out: are surveys even active?

If `surveys-get-all` (with `archived: false`) returns an empty list **and** `surveys-global-stats` shows zero events in the last 30 days, surveys aren't active on this project. Write one scratchpad entry:

  • key: `not-in-use:surveys:team{team_id}`
  • content: brief note ("checked at {timestamp}, no active surveys, no survey events")

Close out empty. Future surveys runs read this entry cold and short-circuit fast. Re-running with the same key idempotently refreshes the timestamp — the entry stays until surveys actually become active, at which point the next run rewrites or deletes it.

How a run works

Cycle between these moves; skip what's not useful.

Get oriented

Four cheap reads cold-start a run:

  • `scout-scratchpad-search` (`text=survey` or `text=nps`) — durable team steering. Entries with `pattern:`, `noise:`, `addressed:`, `dedupe:`, `report:`, or `reviewer:` key prefixes, plus the team's known active survey IDs, primary NPS / CSAT survey, healthy response baselines, known themes already raised, which report covers a theme, and who owns it.
  • `scout-runs-list` (last 7d) — what prior surveys runs found and ruled out.
  • `inbox-reports-list` (filter by `search`=survey name/theme, `source_product`, `ordering=-updated_at`) — the reports already in the inbox. A theme or regression you've reported before is an **edit**, not a fresh report; pull the closest matches with `inbox-reports-retrieve` before authoring.
  • `scout-project-profile-get` — `top_events` for `survey shown` / `survey dismissed` / `survey sent` reach (the survey product isn't yet surfaced in the profile inventory; see "When you hit a gap" below).

Then orient on surveys specifically. Order matters — busy projects can have 100+ active surveys, and `surveys-get-all` is **never the right cold-start move** there. Each survey object is 30–50 KB (questions, internal targeting flag, appearance theme, creator metadata) and even `limit: 5` returns ~30 KB. Listing the lot blows the token budget before you've made a single decision.

Right order:

1. `surveys-global-stats` (last 30d) — cheap project-wide check: are surveys converting at all? If `survey sent` total is zero, close out empty. 2. **Rank candidates by recent activity, not by config.** Use `execute-sql` to find the top survey ids by `survey sent` volume in the last 30d:

   SELECT
       JSONExtractString(properties, '$survey_id') AS survey_id,
       count() AS sent_count,
       max(timestamp) AS last_sent
   FROM events
   WHERE event = 'survey sent'
     AND timestamp > now() - INTERVAL 30 DAY
   GROUP BY survey_id
   ORDER BY sent_count DESC
   LIMIT 20

3. `survey-get {id}` on the top 5–10 ids only — full config when you actually need to read questions / targeting / iteration / type. Never `surveys-get-all` on a project where step 2 returns more than ~20 distinct ids. 4. `survey-stats {id}` per candidate for `shown` / `dismissed` / `sent` counts.

Use `surveys-get-all {"limit": 5}` only as a last resort when discovering a survey by name, and prefer `surveys-get-all {"search": "..."}` over a blind page walk.

Profile shape — what's loud today?

| Pattern | What it usually means | | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | | `survey-stats` shows `dismissed / shown` ratio sharply above the trailing baseline | Targ

Read more
Ships withposthog

:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.

Get the whole plugin

Other skills on posthog.