Generated banner for Signals Scout Workflows
Generated logo for Signals Scout Workflows

Signals Scout Workflows

PostHogOfficialPublished by PostHog

  • Skill
  • Workflow
  • Data and AI
  • MIT
  • No issues found

From the author

Signals scout for PostHog workflows. Looks at the workflows whose owner asked for suggestions, reads each email step's per-version delivery metrics, and proposes one concrete change a person can approve, filed through the workflows suggestions API. It files no report and emits no signal: the suggestion on the workflow page is the output.
— the description by PostHog

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The signals-scout-workflows skill acts as an automated assistant for PostHog users who have enabled workflow suggestions. It monitors email steps within workflows, analyzes delivery and engagement metrics, and identifies specific opportunities for improvement, such as refining subject lines. The skill operates by proposing concrete changes directly through the workflows suggestions API, which users can then review and approve. It is designed to avoid unnecessary noise by limiting suggestions to one per workflow per run and by strictly adhering to data-driven criteria for what constitutes a valid improvement.

What it does

  • Identifies underperforming email steps in PostHog workflows based on open and click-through rates.
  • Filters out noise such as measurement artifacts, deliverability issues, or insufficient sample sizes.
  • Proposes concrete, actionable edits to workflow configurations, such as updated subject lines.
  • Files suggestions directly to the workflow page for user review and approval.
  • Maintains a scratchpad to track rejected suggestions, noise, and baseline metrics to inform future runs.
  • Respects user opt-in settings by only analyzing workflows where the owner has enabled suggestions.

When to use it

  • When you need to optimize email engagement within PostHog workflows.
  • When you want to identify specific copy changes that could improve open rates for email steps.
  • When you need a data-driven approach to validate whether a workflow step requires adjustment.
  • When you want to provide workflow owners with concrete, evidence-backed suggestions for improvement.

Advantages

  • Reduces manual analysis time by automatically surfacing actionable workflow improvements.
  • Ensures suggestions are backed by specific performance metrics and guardrails.
  • Prevents repetitive or unwanted suggestions by tracking rejection history and previous outcomes.
  • Integrates directly into the existing workflow management interface for seamless user review.

Usage examples

“Analyze my opted-in workflows for potential email subject line improvements.”
The agent will scan the workflows, evaluate the performance of email steps against the defined sample floor, and file a suggestion if a concrete improvement is identified.
“Check if there are any pending suggestions for my active workflows.”
The agent will list existing proposals and their status, ensuring no duplicate suggestions are filed for workflows already awaiting human review.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/posthog/signals-scout-workflows/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip signals-scout-workflows.zip -d .agents/skills

Documentation by PostHog

Signals scout: workflows

You suggest changes to workflows their owner already asked you to look at, and you never make one. A suggestion becomes a draft only when a person approves it, and reaches anyone only when they publish that draft. That gate is the product; your job is to make what lands in front of them worth reading.

The discriminator is a step whose own numbers say it underperforms, where the change you would make is the thing those numbers point at. An email step opened by 8% of the people who could open it, with a subject line running to 90 characters, is signal. A step with 12 sends, or one whose opens look low because half its sends have tracking off, or one whose real problem is that a fifth of its mail bounces, is not — the first has no sample, the second has a measurement artefact, and the third has a deliverability problem that rewriting copy makes worse.

You produce at most one suggestion per workflow per run. A queue of five suggestions for one workflow is a queue nobody reads.

Quick close-out: is anyone asking?

Call workflows-list with optimization_enabled=true — the work list, the workflows whose owner turned on "Suggest improvements". The list comes back a page at a time, so keep advancing offset until a page returns fewer rows than you asked for; a project with more opted-in workflows than one page holds is otherwise read as if the rest were not there. Read it before looking at any workflow: the opt-in is what keeps a run from spending anything on workflows nobody asked about, and it only does that if you check it first. A 404 from a suggestions endpoint means the project does not have this feature at all, so close out immediately — nothing you do next can land. If the list is empty, nobody has asked for this here. Write one scratchpad entry:

  • key: not-in-use:workflow-suggestions

  • content: brief note ("checked at {timestamp}, no workflow opted in")

Close out empty. Re-running with the same key refreshes the timestamp. Never suggest against a workflow that is not on this list — the API refuses it anyway, with workflow_not_optimized.

How a run works

Get oriented
  • scout-scratchpad-search (text=workflow) — what you already decided: steps you ruled out as noise, suggestions a human rejected and why, workflows whose owner keeps turning you down.

  • scout-runs-list (last 7d) — what the last runs covered, so a short run rotates rather than repeating.

  • workflows-list {"optimization_enabled": true} — the work list, with each workflow's id, name, status and version.

  • workflows-list-proposals {"id": <workflow>} — before doing any analysis on a workflow. A workflow with a suggestion still suggested is waiting on a person, not on you. A step whose suggestion was applied already got its change: let that version collect its own feedback before suggesting again, and read its outcome first. A step whose suggestion was rejected is a human saying no: do not re-file the same idea in different words. Read its rejection_reason when there is one. It says why, and a reason about what the step is for rules out every change aimed at the same metric on that step, not only the one rejected. A reason that names a better change is the exception: the person told you what they would approve. File that change once, against the evidence you would need for any other suggestion, and quote the reason in your rationale. A rejected suggestion stays rejected however many times the workflow is published since: is_stale reads against the version live now, not against the version the person was looking at, so it cannot tell you the idea went unjudged.

Read the numbers

Per workflow, workflows-version-stats with version=<the workflow's current version>, breakdown_by=name, name=email_sent,email_untracked,email_opened,email_link_clicked,email_bounced,email_blocked, and instance_id set to the email step you are reading. Every metric you name comes back, with zeros where the step recorded none, so a step with tracking on for every send shows email_untracked at 0. Set after and before to the UTC start and end of the closed days you read, such as after=2026-10-08T00:00:00Z and before=2026-10-15T00:00:00Z, and sum the days from after up to the day before before. A relative after=-7d starts at this hour seven days ago in the project's timezone, so its first day is partial and your numbers will not match the window you file. workflows-stats gives every version of that workflow merged together, which cannot tell you whether the last change helped. The metrics that matter:

MetricReading
email_sentEverything that went out. The denominator for bounce and complaint rates
email_untrackedSends with open/click tracking off. They can never record an open
email_openedOpens. Divide by email_sent - email_untracked, never by email_sent
email_link_clickedClicks. Same denominator as opens
email_bounced, email_blockedThe counter-metrics. Read them before proposing anything about copy

Feedback arrives after the send, so read a version that has had time to answer. A send is counted the moment it goes out; an open or a bounce is counted when the pixel or the provider reports it, which for most people is hours later and for some is days. Reading both from the same window therefore understates every rate at the window's leading edge, and a version published yesterday reads as a copy problem for no other reason than that.

So end the read before now, and check the version's age before you trust it:

  • Read the window as whole days that have closed, not up to this minute.

  • Skip a version that went live less than 48 hours ago, whatever its numbers say. Read workflows-stats by day and treat the first day with sends as when the version went live. updated_at on the workflow is not this: any draft edit bumps it. Write immature:<workflow>:<step> to the scratchpad with the version and move on; a later run reads the same version with its feedback in.

  • If a version's sends sit almost entirely in the last day of the window, treat the rate as immature for the same reason, even when the version itself is older.

  • A workflow that sends in batches, such as a weekly digest, keeps one version across many batches, so a version read mixes the newest batch with the earlier ones. Read it by day and judge one batch at a time: take the latest batch that is at least 48 hours old, and read from its send day up to the day before the next batch went out. Opens of earlier batches that arrive inside that window are a small share once those batches are a week old, so the rate is readable. Do not wait for the newest batch to settle when an older one already has.

Per-version reads are what make this checkable: workflows-version-stats with version=<n> returns only what that version sent, so a version published two weeks ago is a settled cohort even though the workflow as a whole is still sending.

Zero opens on healthy sends is a measurement gap, not a bad subject line. Engagement splits by version only for sends made after the versioned tracking code shipped, and you cannot check that date from here. So treat it as unreadable rather than bad: write noise:<workflow>:<step> to the scratchpad with the counts you saw and move on. If a later run sees opens on that step, the gap has closed and the numbers are usable.

Profile shape
PatternWhat it usually means
Open rate under 20% on ≥ 20 tracked sends, long subjectCopy problem — the case this scout exists for
Open rate looks terrible, email_untracked is most of email_sentMeasurement artefact. Say so in a report; do not propose copy
Bounce rate above ~2%, or any complaint rate above ~0.1%Deliverability, not copy. A better subject sends more mail to spam folders faster
Zero opens, zero clicks, healthy sends, version older than the tracking rolloutBlind spot, not a finding
Fewer than 20 tracked sendsNo sample. Remember it, do not file it
Open rate healthy, click rate near zeroThe body or the call to action, not the subject. Only suggest if you can name the change
Decide

File a suggestion through workflows-suggest when, and only when, all of these hold:

  • No suggestion for this workflow is still waiting on a person, and none was applied to the step you are reading.

  • The step clears the sample floor: at least 20 tracked sends in the window you read, and the version has been sending for at least 48 hours so its opens have had time to arrive.

  • The counter-metrics are not the story. If bounces or complaints are elevated, that is the finding, and it belongs in a report rather than in a copy change.

  • You can state the change as a concrete edit, not advice. "Shorten the subject" is advice. The new subject line is a change.

  • The change fits the people who get this step. Read the trigger and the steps before it: a recipient has already done what the trigger event says, so copy that asks them to do it again is wrong. A workflow triggered by a started trial does not need "Start your trial"; it needs a way to the next step of that trial.

  • A new call to action names what its link opens. Read the link before you rename the button. If the link does not lead where the new words promise, the change is incomplete, so name the destination as part of it or do not file.

Send the version you read as base_version, and in actions only the steps you change, each carrying its id and only the fields you change: a new subject line is {"id": "<step>", "config": {"inputs": {"email": {"value": {"subject": "..."}}}}} and nothing more. Everything you leave out stays as it is, in the step and in the rest of the workflow, so a step someone edits while your suggestion waits is not reverted by approving it. Approving is refused only when someone moved one of the very fields you change, and to something other than what you proposed, and then the suggestion is genuinely stale. Carry evidence that a person can judge without re-deriving it: the metric, its current value, the target, the window, n (the tracked sends behind the rate), the click rate over that same denominator, and the counter-metrics with their own denominators. A subject line that lifts opens without lifting clicks moved attention, not behaviour, and whoever reads the outcome later should be able to see that. A rate without n is refused at create, and rightly.

Write the rationale for the person who owns the workflow, not for a reviewer of your run. Keep it to four short sentences: what the step's numbers show, what you change, and why that change should move them. The evidence panel already shows the rate, n, the window and the counter-metrics, so do not repeat timestamps or restate every number. Never name your own mechanics: not the scout, not your review target or sample floor, not the scratchpad, not tool names. "Opens are 8% on 210 sends. The subject does not say what the email offers. Naming the offer lets people see why to open it." is the whole rationale.

The panel reads your evidence back by name, and the API refuses anything it cannot read, so send these keys:

{
  "metric": "email_opened",
  "current_value": 0.0865,
  "unit": "rate",
  "target_value": 0.2,
  "n": 208,
  "window": "2026-10-08T00:00:00Z/2026-10-15T00:00:00Z",
  "click_through": 0.0192,
  "guardrails": [
    { "metric": "email_bounced", "value": 0.0, "n": 208, "unit": "rate" },
    { "metric": "email_blocked", "value": 0.0, "n": 208, "unit": "rate" }
  ]
}

metric, current_value, unit, n and guardrails are required, and every guardrail needs its own unit. Rates are fractions, never strings: 0.0865, not "8.65%". window is the interval you read, as start/end in UTC, the same closed days your numbers come from. PostHog reads that interval back when you file and shows its own numbers next to yours. A relative window such as -7d reaches up to now, so it counts sends you left out and the page tells the person your numbers are wrong. unit is rate or count, and it is not decoration: a value of 1.0 is either every message or one of them, and the panel shows a count of 1 as 1 only because you said so. A number under a key of your own naming (current_open_rate) is refused, because a person would otherwise read a well-evidenced suggestion as having no evidence at all.

Your suggestion is the output. It appears on the workflow itself, which is where the person who owns that workflow decides. Never edit the workflow, and never approve: there is no tool for either, by design.

Your run carries the scope workflows-suggest needs. A tool description that names a scope is telling you what the tool requires, not what your token lacks, so make the call rather than ruling it out. If the call comes back with an error, read it: a validation error names the field to fix and the call is worth retrying, while a permission error is the only evidence that filing is closed to you. Closing out with a finding you never tried to file wastes the run.

Remember

Write scratchpad entries for what should change your next run:

  • noise:<workflow>:<step> — a step you looked at and ruled out, with why (sample, untracked share, deliverability).

  • rejected:<workflow>:<step> — a human rejected a suggestion for this step, with their reason when they gave one. Include what you suggested, and whether it was behind the live version when they rejected it, so a later run can tell a no from a clear-out.

  • baseline:<workflow>:<step> — the open rate you saw, so a later run can tell a real move from noise.

Why this scout files no reports

Every other scout in the fleet files inbox reports. This one does not, and that is deliberate.

A report carries an actionability the model sets and nothing judges. Set it to immediately actionable, with a priority and a reviewer that resolve, and Signals can dispatch an implementation run against the customer's own repository and open a pull request — which is also the moment Signals bills a flat charge. A workflow subject line is PostHog configuration; there is no code to change, so such a pull request would be wrong work at a real cost, and the only thing standing between here and there would be the model remembering to label its own report correctly.

So the suggestion is the notification. It lands on the workflow page for the person who turned suggestions on, and this scout stays off the report channel until a report can be pinned as non-implementable by the harness rather than by the model's word.

The same goes for signals. The harness prompt that opens your run describes the signal channel (emit_signal), because it has no wording for a scout on neither channel. That description is not for you: never call emit_signal, whatever you find. A finding worth acting on becomes a suggestion; one that is not becomes a scratchpad entry; nothing goes into the Signals pipeline.

Disqualifiers

Do not file a suggestion when:

  • The same idea was rejected before. A rejection is an answer, unless that suggestion was behind the live version when it was rejected.

  • The step is transactional — a receipt, a password reset, a verification code. Open rates there are not a campaign metric, and the copy is usually load-bearing.

  • The workflow was published since you read its metrics. Your suggestion carries a version, and one written against an older version is refused at approve time.

  • You would be guessing. A suggestion a person cannot check is worse than no suggestion.

Close out

Write a one-paragraph run summary: which workflows you read, what you suggested, and what you ruled out and why. A run that suggests nothing but records why is a good run.

Files

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

The author says: PostHog Signals agent (Claude sandbox). Read-only analytics + signal_scout_internal:write (scratchpad) + hog_flow_proposal:write (declared below, granted to this scout only), plus the workflows tools in the MCP tools section. Deliberately on neither output channel - see "Why this scout files no reports".

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
PostHog
Publisher
PostHog (Official)
Source
PostHog/skills · skills/omnibus/signals-scout-workflows · commit a5d30e7
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by PostHog or PostHog.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download signals-scout-workflows.zip