Install any skill in seconds. Free to start, no credit card required.
Get Started Free →How to author, edit, and adapt PostHog Signals scouts — the scheduled agents that scan a project and emit findings into the Signals inbox. Use when a user wants to customize a canonical scout for their own setup (narrow its scope, retune its thresholds, add disqualifiers), tweak a scout's schedule or dry-run posture, or write a brand-new scout from scratch for a specific use case (a custom event,
.claude/skills/kunanonj-cursor-plugin-posthog-authoring-signals-scouts/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-13 | ✗→✓ | ▲ Improved | 69% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 14% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 39% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 107% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 161% | 0% |
A scout is a scheduled agent that wakes on its own interval, looks at one PostHog project, decides what's genuinely worth surfacing, and emits it as a finding into the Signals inbox — or closes out empty, which is a real outcome. PostHog ships a fleet of canonical scouts (a cross-product generalist plus per-surface specialists). This skill helps you and your agent adapt those canonical scouts to a specific project, or author new scouts from scratch for a use case the fleet doesn't cover.
A scout is just an LLMSkill whose name starts with signals-scout-. The harness discovers scouts by globbing signals-scout-* over the project's skills, loads the body verbatim as the agent's system prompt, and progressively reads any bundled reference files on demand. The signals-scout- name prefix is load-bearing: a skill named anything else will never run as a scout.
Don't write a scout in the abstract. Ground it in the target project first — a scout is only as good as its fit to the data it watches.
posthog:signals-scout-project-profile-get returns thedeterministic snapshot the scout itself cold-starts from: products in use, top events with reach/burst metrics, integrations, existing inbox counts. If the scout watches a specific event, confirm it exists and check its shape with posthog:read-data-schema. A scout for an event the project doesn't capture is dead on arrival.
posthog:signals-scout-config-list lists every existingscout on the project with its schedule, enabled, and emit posture. Don't duplicate a surface a canonical scout already covers — adapt that one instead.
it with posthog:llma-skill-get {"skill_name": "signals-scout-<x>"} (per-team rows) or read it from the repo at products/signals/skills/signals-scout-*/. The generalist (signals-scout-general) is the broad template; pick a specialist (-error-tracking, -ai-observability, -logs, -revenue-analytics, -surveys, -csp-violations, -observability-gaps) if your scope is domain-tight.
posthog:inbox-reports-list shows what findings are actuallylanding — calibrate so your scout adds signal, not noise.
There are two independent decisions: what you're building, and where it lives.
| Situation | Approach | | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | A canonical scout is close but too broad / too noisy / missing a disqualifier for this project | Adapt it — narrow the scope, add disqualifiers, retune thresholds. | | You want a surface no canonical scout covers (a custom event, a product-specific funnel) | New scout from scratch — copy the closest canonical scout as scaffolding, replace the domain discriminator + explore patterns. | | You only want to change _when_ / _whether_ a scout runs | No authoring — just tune the config (see Run posture). |
| Path | Mechanism | Use when | | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | | Per-team (the common user path) | Create/edit a signals-scout-* LLMSkill row in the project's skills store via posthog:llma-skill-create / -update / -file-create. | Customizing for one project. The harness globs the row in on the next tick; canonical sync leaves your edited ("diverged") row alone. | | Canonical (PostHog contributors) | Edit disk under products/signals/skills/signals-scout-*/, lint/build, open a PR. | Improving a scout for _every_ enrolled project. lazy_seed mirrors it onto all enrolled teams on the next tick. |
Adapting-in-place tradeoff: editing a canonical scout's row for your team marks it diverged — you stop receiving upstream improvements to that scout. If you only need an _additional_ behavior, prefer authoring a new, differently-named scout (signals-scout-<your-scope>) and leaving the canonical one intact.
See references/lifecycle-and-testing.md for the exact skills-store calls, the build/lint commands, and how seeding works.
Follow references/scout-anatomy.md — it has the frontmatter schema, the canonical body structure (quick close-out → orient → domain discriminator → explore patterns → save-memory → decide → disqualifiers → close-out), the lean-body rule, and copy-ready skeleton templates for both a specialist and the generalist.
Two craft references the whole fleet reasons in terms of — a good scout's Decide and memory sections are built on them, so read them before writing those sections:
references/emit-contract.md — what emit-signal takes,the weight vs. confidence rubrics, severity, dedupe keys, finding_id, the description prose contract, and a worked example. This is how your scout decides _what clears the bar_ and _how to write the finding_.
references/dedupe-and-memory.md — the four-statesclassifier (net-new / material-update / already-covered / addressed-or-noise), the scratchpad key-prefix vocabulary, and the cross-project noise patterns. This is how your scout avoids re-emitting and learns across runs.
The single most important design decision in any scout is its signal-vs-noise discriminator — the cheap profile-shape read that separates "worth investigating" from "baseline". For error tracking it's the count vs distinct_users ratio; for CSP it's reach over raw count. Your new scout needs its own. Name it explicitly near the top of the body so every run anchors on it.
A scout's schedule and emit behavior live on its SignalScoutConfig, separate from the skill body. Tune with posthog:signals-scout-config-update (find the id via -config-list):
run_interval_minutes — 10 to 43200. Default 60 (hourly). Slow a chatty or expensivescout by raising this.
enabled — false pauses the scout entirely (coordinator skips it).emit — false = dry-run: the scout runs and logs its reasoning but writes nothingto the inbox. New and freshly-edited scouts should run dry-run first.
You can't force a synchronous run as a user — scouts fire on their schedule. The feedback loop is dry-run + inspect:
emit=false and a short run_interval_minutes so it fires soon.posthog:signals-scout-runs-list (run summaries),-runs-retrieve (full reasoning for one run), and -scratchpad-search (the durable memory it wrote). In dry-run, runs show what it _would_ have emitted.
false-positived on, fix the emit calibration.
emit=true. Restore the interval tosomething sustainable (hourly+).
Repo contributors get a faster loop — hogli sync:skill and the harness's local run path; see references/lifecycle-and-testing.md.
To read what your scouts are doing rather than change them — surveying the fleet, inspecting individual runs, the scratchpad memory, and assessing performance — use the read-only companion skill exploring-signals-scouts. Keep the two in sync when the scout config / run / scratchpad surfaces change.
watched surface is at baseline or absent).
points, not a rigid checklist.
bursts, allowlisted entities).
below that, write memory).
references/) — every line is a recurring token cost onevery run.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-13 | fail→pass | 9,069 | 1,502 | -83% | 1 | 1 | 0% | 1,478 | 2,503 | +69% | 0 | 0 | — |
case-07 | fail→pass | 11,828 | 1,475 | -88% | 1 | 1 | 0% | 2,231 | 2,539 | +14% | 0 | 0 | — |
case-01 | fail→fail | 13,536 | 6,386 | -53% | 1 | 1 | 0% | 2,348 | 2,863 | +22% | 0 | 0 | — |
case-02 | fail→fail | 19,543 | 5,198 | -73% | 1 | 1 | 0% | 3,070 | 2,317 | -25% | 0 | 0 | — |
case-03 | fail→pass | 14,868 | 8,942 | -40% | 1 | 1 | 0% | 2,995 | 4,156 | +39% | 0 | 0 | — |
case-04 | fail→pass | 11,841 | 12,512 | +6% | 1 | 1 | 0% | 2,278 | 4,721 | +107% | 0 | 0 | — |
case-05 | pass→fail | 10,810 | 10,203 | -6% | 1 | 1 | 0% | 2,114 | 4,062 | +92% | 0 | 0 | — |
case-06 | pass→pass | 12,861 | 12,997 | +1% | 1 | 1 | 0% | 2,595 | 4,928 | +90% | 0 | 0 | — |
case-08 | fail→pass | 6,201 | 2,330 | -62% | 1 | 1 | 0% | 1,016 | 2,648 | +161% | 0 | 0 | — |
case-09 | fail→pass | 12,811 | 2,052 | -84% | 1 | 1 | 0% | 2,239 | 2,687 | +20% | 0 | 0 | — |
case-10 | fail→pass | 8,004 | 3,523 | -56% | 1 | 1 | 0% | 1,517 | 2,917 | +92% | 0 | 0 | — |
case-11 | fail→pass | 11,514 | 6,949 | -40% | 1 | 1 | 0% | 1,902 | 3,473 | +83% | 0 | 0 | — |
case-12 | fail→pass | 15,724 | 7,051 | -55% | 1 | 1 | 0% | 3,119 | 3,518 | +13% | 0 | 0 | — |
case-14 | fail→pass | 5,859 | 1,643 | -72% | 1 | 1 | 0% | 1,236 | 2,558 | +107% | 0 | 0 | — |
case-15 | fail→pass | 9,779 | 2,241 | -77% | 1 | 1 | 0% | 1,551 | 2,736 | +76% | 0 | 0 | — |
case-16 | fail→pass | 14,105 | 2,435 | -83% | 1 | 1 | 0% | 2,316 | 2,688 | +16% | 0 | 0 | — |
case-17 | pass→pass | 8,922 | 4,847 | -46% | 1 | 1 | 0% | 1,383 | 3,144 | +127% | 0 | 0 | — |
case-18 | fail→pass | 13,899 | 1,420 | -90% | 1 | 1 | 0% | 2,684 | 2,495 | -7% | 0 | 0 | — |
case-19 | pass→pass | 10,173 | 5,335 | -48% | 1 | 1 | 0% | 1,598 | 3,023 | +89% | 0 | 0 | — |
case-20 | fail→pass | 8,364 | 1,370 | -84% | 1 | 1 | 0% | 1,504 | 2,411 | +60% | 0 | 0 | — |
case-21 | pass→pass | 8,246 | 2,971 | -64% | 1 | 1 | 0% | 1,479 | 2,786 | +88% | 0 | 0 | — |
case-22 | fail→pass | 13,229 | 4,441 | -66% | 1 | 1 | 0% | 2,243 | 3,044 | +36% | 0 | 0 | — |
case-23 | fail→pass | 7,642 | 2,282 | -70% | 1 | 1 | 0% | 1,169 | 2,496 | +114% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted, and 21 counted toward the lift figure. The other 2 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +65 percentage points is the difference between those two pass rates over the 21 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.