Authoring Signals scouts
SkillFiles & storageHow to author, edit, and adapt PostHog Signals scouts, the scheduled agents that scan a project and file what they find. Use to customize a canonical scout (narrow its scope, retune thresholds, add disqualifiers), tweak a scout's schedule or dry-run posture, write a new scout for a surface the fleet doesn't cover, build a measurement scout that records structured output (an LLM-judge scoring a sample on a schedule, a custom metric no query can compute), or steer a scout without editing it by leaving it a note. Covers the scout SKILL.md anatomy, the report contract, the structured-output channel, the dedupe + scratchpad-memory conventions, scout notes, the per-team skills-store path vs the canonical in-repo path, and the test loop. Trigger on "write/edit/customize a signals scout", "new scout for X", "tune my scout schedule", "make a scout that watches <event>", "score/judge/measure X with a scout", "structured output from a scout", "scout output to Slack", "leave a note for / give feedback to a scout".
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Authoring Signals scouts skill
What this skill tells your AI
The instructions your AI receives, as published by posthog/skills in skills/omnibus/authoring-scouts/SKILL.md and read by ahel’s review.
A scout is a scheduled agent that wakes on its own interval, looks at one PostHog project, decides what's genuinely worth surfacing, and writes it into the Signals inbox as a report — 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's output is the report channel: it lists emit_report / edit_report in its frontmatter allowed_tools and authors or edits full inbox reports 1:1 directly.
The canonical fleet runs this way, and every new scout should too — always include the allowed_tools opt-in when authoring one.
Where that output lands is a separate, per-scout config decision: the report goes to the Signals inbox, and the same report can be delivered to a Slack channel or DM at the same time (output_destinations under Run posture) — so don't rule a scout out of a job because the user wants the result in Slack.
(A historical signal-emitting channel — weak emit-signal findings a pipeline consolidated — still exists in the harness for scouts that never opted in, but it is deprecated: don't author new scouts on it, and opt an old one in rather than extending it.)
A scout is an LLMSkill that holds a SignalScoutConfig.
The harness loads the body verbatim as the agent's system prompt, and progressively reads any bundled reference files on demand.
The config row is what makes a skill a scout. Any valid skill name works, so the signals-scout- prefix is optional.
The prefix controls one thing: the coordinator globs signals-scout-* to auto-register a config for a skill that has none.
A skill with any other name needs its config created alongside it, which is what scout-create does.
The job before the writing
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.
(The scout tools were recently renamed from signals-scout-* to scout-*; if a scout-* name comes back unknown, the server may still expose it under the legacy signals-scout-* name — search the tool catalog and call whichever name it returns.)
- Read the project.
posthog:scout-project-profile-getreturns the deterministic 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 withposthog:read-data-schema. A scout for an event the project doesn't capture is dead on arrival. - See what already runs.
posthog:scout-config-listlists every existing scout on the project with its schedule,enabled, andemitposture, plus each scout'sdescription(pulled from the skill's frontmatter) so you can tell what a scout watches without loading its body. Don't duplicate a surface a canonical scout already covers — adapt that one instead. - Read the closest canonical scout. It's your template and your reference shape.
Pull it with
posthog:skill-get {"skill_name": "signals-scout-<x>"}(per-team rows) or read it from the repo atproducts/signals/skills/signals-scout-*/. The generalist (signals-scout-general) is the broad template; if your scope is domain-tight, pick the specialist closest to your surface — list the live roster withposthog:skill-list {"search": "signals-scout"}(specialists exist for most product surfaces: error tracking, logs, AI observability, experiments, feature flags, session replay, web analytics, surveys, and more). - Skim the inbox.
posthog:inbox-reports-listshows what reports are actually landing — calibrate so your scout adds signal, not noise.
Choose the path
There are two independent decisions: what you're building, and where it lives.
What
| 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). |
| You have one-off feedback, a pointer, or short-lived context for a scout | No authoring — leave a note (see Steering with notes). |
Where
| Path | Mechanism | Use when |
|---|---|---|
| Per-team (the common user path) | Create a new runnable scout via posthog:scout-create; edit its prompt or files later via posthog:skill-update / -file-create, and tune its runtime config via posthog:scout-config-update. | 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.
Write the scout
First pick the shape.
references/scout-patterns.md is a cookbook of the reference architectures scouts fall into — anomaly watcher, liveness/absence watcher, zero-result/unmet demand, watchlist explore/exploit, cross-product correlation, recommendation/gap, warehouse-backed source, custom single-event, open-text theme, adversarial/abuse concentration, external-tool/code, state∩code intersection, custom issue-tracker/work-queue, daily digest/roll-up, triage over a pre-detected stream, first-person dogfooding/probe, recurring measurement/LLM-judge, maintainer/steward, owner-scoped book/queue, trigger-to-brief enrichment, dispatcher/campaign, fleet meta-scout/reviewer — each mapped to a canonical scout or a proven custom shape you can copy as scaffolding.
It also makes the key point that a scout can watch any source PostHog ingests into the data warehouse, not just analytics events (a Slack channel sync, a billing system, a CRM, a support inbox), plus external systems reachable from the sandbox, other agents' output, and the scout fleet itself.
And where a built-in signals source already covers the surface (GitHub and Linear issues), the issue-tracker pattern says where that source stops and a scout starts paying for itself.
A scout does not have to stop at describing a fix: the maintainer / steward pattern is how a scout holding write_scopes keeps a family of dashboards, alerts, warehouse views, or scanner prompts healthy itself, with a write ladder that says which changes it applies, which it verifies and reports, and which it hands to a human.
Find the closest pattern, then write the body.
Follow references/scout-anatomy.md — it has the frontmatter schema (including the allowed_tools report-channel opt-in every scout needs), 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/report-contract.md— the report tools (scout-emit-report/scout-edit-report), the report bar (author 1:1 only for a finding you'd own end-to-end),suggested_reviewersrouting, the dedup-via-report_iddiscipline (the channel isn't idempotent — reconcile against existing reports via the vanillainbox-reports-list/inbox-reports-retrievebefore authoring), and the accepted caveat that the pipeline may later rewrite an authored title/summary. This is how your scout decides what clears the bar and how to file it.references/dedupe-and-memory.md— the four-states classifier (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-filing 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.
(The one exception: a measurement scout on the structured-output channel holds no bar — it applies a rubric to every sampled item, and the rubric takes the discriminator's slot as the design surface to name, dogfood, and calibrate. See the recurring measurement / LLM-judge pattern in references/scout-patterns.md.)
A second design rule binds any metric-shaped scout — one that scores, ranks, or reports a named, reusable measure, whether a business measure (MRR, churn risk, usage revenue, activation) or operational telemetry it computes every run to monitor or report (cost per run, failure or error rates, latency, throughput).
When the project's metrics catalog is enabled, it may hold a governed definition of that measure in system.information_schema.metrics, and the harness tells every run to prefer it — so write the body to cooperate rather than compete: have the run check the catalog for an approved, non-drifted metric before its own derivation, and run a match through data-catalog-metric-run.
Where a governed metric exists, reference it by name in any references/queries.md you ship, and label every hand-written derivation there a noncanonical fallback — an unlabeled "validated query" outranks the harness's catalog-first rule at run time, which is exactly how a scout ends up re-deriving a number the team already governs.
Freshness, availability, and schema checks are exempt: they stay schema-first, with no catalog detour.
A measurement scout is exempt too, but only for the measure it invents: a subjective rubric has no governed definition to defer to, while any conventional metric the same scout reports still goes through the catalog.
Run posture (config)
A scout's schedule and emit behavior live on its SignalScoutConfig, separate from the skill body.
For a brand-new scout, pass these settings in the nested config object of the posthog:scout-create call, including creating it disabled or in dry-run before it ever runs.
The endpoint creates the skill and config atomically, always opts the scout into the report channel, and safely re-applies config fields when the same definition is retried.
Otherwise the coordinator auto-registers an enabled config on the default every-24-hours schedule on its next tick (up to ~30 min).
For an existing scout, tune with posthog:scout-config-update (find the id via -config-list):
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 62
- Forks
- 6
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
authoring-scouts- Source
- github.com/posthog/skills