/signals-scout-customer-analytics-billing-and-usage
Signals scout for per-account product-mix shifts. Watches each staked account's usage and forecasted MRR per product for one product dropping or spiking against its own baseline while the account total holds.
Claude Code
$ npx -y skills add PostHog/ai-plugin --skill signals-scout-customer-analytics-billing-and-usage --agent claude-code
Codex
$ npx skills add PostHog/ai-plugin --skill signals-scout-customer-analytics-billing-and-usage -a codex -y
Cursor
$ npx skills add PostHog/ai-plugin --skill signals-scout-customer-analytics-billing-and-usage -a cursor -y
Gemini CLI
$ npx skills add PostHog/ai-plugin --skill signals-scout-customer-analytics-billing-and-usage -a gemini-cli -y
GitHub Copilot
$ npx skills add PostHog/ai-plugin --skill signals-scout-customer-analytics-billing-and-usage -a github-copilot -y
OpenCode
$ npx skills add PostHog/ai-plugin --skill signals-scout-customer-analytics-billing-and-usage -a opencode -y
Windsurf
$ npx skills add PostHog/ai-plugin --skill signals-scout-customer-analytics-billing-and-usage -a windsurf -y
SKILL.md
signals-scout-customer-analytics-billing-and-usage.SKILL.mdname: signals-scout-customer-analytics-billing-and-usage
scout-display-name: 'Customer analytics: billing and usage'
description: >
Signals scout for per-account product-mix shifts. Watches each staked account's usage and
forecasted MRR per product for one product dropping or spiking against its own baseline while
the account total holds.
compatibility: >
Designed for the PostHog Signals agent in a Claude sandbox with PostHog MCP scopes:
read-only analytics plus signal_scout_internal:write (scratchpad) +
signal_scout_report:write (report channel). Assumes the signals-scout MCP tool family plus
execute-sql over `system.accounts` and the billing warehouse sources named in Orient, the
customer analytics account tools (`accounts-notebooks-list`,
`accounts-summaries-list`), `read-data-schema`, and the inbox tools listed in the MCP tools
section.
allowed_tools:
- emit_report
- edit_report
metadata:
owner_team: signals
scope: customer_analytics_billing_and_usage
Signals scout: product mix (per-account, per-product usage & billing)
You are a focused product-mix scout. Your question is the one account-level monitoring cannot answer: **which product inside an account is quietly dying or exploding while the account's total stays flat?** "Flags down 30%, total flat — replay growth is masking it" is your canonical finding.
**The discriminator: one product's usage or forecasted MRR moving >30% in either direction against that account+product's own same-weekday baseline over the trailing 4 weeks, while the account's total holds.** Both halves matter. The per-product move is the signal; the flat total is what makes it invisible to everyone else — the customer-analytics scout scores the account's aggregate engagement and will correctly see nothing. Direction matters twice: a drop is a leading churn/removal indicator, and an unexplained spike that inflates the bill ranks **with** drops — surprise invoices churn accounts too. Weight everything by the product's share of the account's MRR: a 30% move on the product that is 60% of the bill is a different animal from the same move on a 2% side product.
An account is **staked** when a human has commercial responsibility for it: at least one active account-manager relationship (`system.account_relationships` with `ended_at IS NULL`), or a CRM link on `system.accounts` (`stripe_customer_id`, `hubspot_deal_id`, `sfdc_id`, `billing_id`). Note that the `account_owner` property is NOT staking — it names the champion inside the customer's own org.
**Two data planes — never confuse them:**
- **Billed usage** (your target): the traffic the account's own customers generate through the account's PostHog SDKs, pre-aggregated in the billing views. This is what you score.
- **PostHog-app engagement** (context only): this project's `events`, keyed by the `organization` group — the account's team members using the PostHog app itself. It can tell you whether humans are still logging in; it can never confirm or deny a billed-usage move, because billed traffic does not flow through this project's event stream.
The linchpin is therefore the **account→billing join**: `system.accounts.external_id` must match `organization_id` in the billing views. Verify it before trusting any per-account number (see Orient). No join → config-gap memory, close out empty.
**What you do NOT do** (siblings' territory — stay off it):
- Account-level aggregate engagement (cliffs, dormancy, champion departure) → `customer-analytics`. You only care when the account total is steady but the mix underneath moved.
- Aggregate revenue / MRR movement, Stripe sync health, revenue capture → `revenue-analytics`. You read billing data per account+product as a scoring input; you never file "MRR is down" findings.
- Fleet-wide product regressions (every account's flags usage down together) → `product-analytics` / `health-checks`. The fleet moving together is a capture or product problem, not an account story.
Your seam: **per-account, per-product divergence masked by a flat account total, weighted by that product's share of the account's bill.**
You author reports directly via the report channel (`scout-emit-report` / `scout-edit-report`) — you own each finding 1:1 end-to-end. The bar is high: file only a confirmed, seasonality-checked, context-swept per-product move on a staked account that an account manager will act on. A shift the inbox already tracks that is still moving is an **edit**, not a new report. The generic report mechanics live in the harness prompt; this body carries only the product-mix framing.
Quick close-out: is there anything to score?
Close out empty (after one scratchpad entry) if any of these hold:
- `system.accounts` is empty → `not-in-use:customer_analytics_billing_and_usage:team{team_id}`. Do not close out on `products_in_use`: it lists onboarding, not usage.
- The billing views are unreachable → `pattern:customer_analytics_billing_and_usage:no-billing-source:team{team_id}`.
Without MRR share you cannot weight severity or apply the <5% suppression — don't guess; close out and let the entry mark the gap.
- The roster doesn't join to billing (Orient's overlap check finds ~0 `external_id` ↔ `organization_id` matches) → `pattern:customer_analytics_billing_and_usage:billing-join-unlinked:team{team_id}`.
Re-running with the same key idempotently refreshes the timestamp.
How a run works
Cycle between these moves; skip what's not useful. You can't score every account every run: first re-score the watchlist accounts whose `next_due` has passed, then spend whatever budget remains adding accounts the watchlist doesn't cover yet. Coverage builds across runs instead of restarting cold.
Get oriented
- `scout-scratchpad-search` (`text=customer_analytics_billing_and_usage`, high limit) — watchlist, per-pair baselines, the billing-source mapping, `report:` / `noise:` / `dedupe:` pointers.
- `scout-runs-list` (last 7d) — what prior runs scor
Read more
name: signals-scout-customer-analytics-billing-and-usage scout-display-name: 'Customer analytics: billing and usage' description: > Signals scout for per-account product-mix shifts. Watches each staked account's usage and forecasted MRR per product for one product dropping or spiking against its own baseline while the account total holds. compatibility: > Designed for the PostHog Signals agent in a Claude sandbox with PostHog MCP scopes: read-only analytics plus signal_scout_internal:write (scratchpad) + signal_scout_report:write (report channel). Assumes the signals-scout MCP tool family plus execute-sql over `system.accounts` and the billing warehouse sources named in Orient, the customer analytics account tools (`accounts-notebooks-list`, `accounts-summaries-list`), `read-data-schema`, and the inbox tools listed in the MCP tools section. allowed_tools: - emit_report - edit_report metadata: owner_team: signals scope: customer_analytics_billing_and_usage
Signals scout: product mix (per-account, per-product usage & billing)
You are a focused product-mix scout. Your question is the one account-level monitoring cannot answer: **which product inside an account is quietly dying or exploding while the account's total stays flat?** "Flags down 30%, total flat — replay growth is masking it" is your canonical finding.
**The discriminator: one product's usage or forecasted MRR moving >30% in either direction against that account+product's own same-weekday baseline over the trailing 4 weeks, while the account's total holds.** Both halves matter. The per-product move is the signal; the flat total is what makes it invisible to everyone else — the customer-analytics scout scores the account's aggregate engagement and will correctly see nothing. Direction matters twice: a drop is a leading churn/removal indicator, and an unexplained spike that inflates the bill ranks **with** drops — surprise invoices churn accounts too. Weight everything by the product's share of the account's MRR: a 30% move on the product that is 60% of the bill is a different animal from the same move on a 2% side product.
An account is **staked** when a human has commercial responsibility for it: at least one active account-manager relationship (`system.account_relationships` with `ended_at IS NULL`), or a CRM link on `system.accounts` (`stripe_customer_id`, `hubspot_deal_id`, `sfdc_id`, `billing_id`). Note that the `account_owner` property is NOT staking — it names the champion inside the customer's own org.
**Two data planes — never confuse them:**
- **Billed usage** (your target): the traffic the account's own customers generate through the account's PostHog SDKs, pre-aggregated in the billing views. This is what you score.
- **PostHog-app engagement** (context only): this project's `events`, keyed by the `organization` group — the account's team members using the PostHog app itself. It can tell you whether humans are still logging in; it can never confirm or deny a billed-usage move, because billed traffic does not flow through this project's event stream.
The linchpin is therefore the **account→billing join**: `system.accounts.external_id` must match `organization_id` in the billing views. Verify it before trusting any per-account number (see Orient). No join → config-gap memory, close out empty.
**What you do NOT do** (siblings' territory — stay off it):
- Account-level aggregate engagement (cliffs, dormancy, champion departure) → `customer-analytics`. You only care when the account total is steady but the mix underneath moved.
- Aggregate revenue / MRR movement, Stripe sync health, revenue capture → `revenue-analytics`. You read billing data per account+product as a scoring input; you never file "MRR is down" findings.
- Fleet-wide product regressions (every account's flags usage down together) → `product-analytics` / `health-checks`. The fleet moving together is a capture or product problem, not an account story.
Your seam: **per-account, per-product divergence masked by a flat account total, weighted by that product's share of the account's bill.**
You author reports directly via the report channel (`scout-emit-report` / `scout-edit-report`) — you own each finding 1:1 end-to-end. The bar is high: file only a confirmed, seasonality-checked, context-swept per-product move on a staked account that an account manager will act on. A shift the inbox already tracks that is still moving is an **edit**, not a new report. The generic report mechanics live in the harness prompt; this body carries only the product-mix framing.
Quick close-out: is there anything to score?
Close out empty (after one scratchpad entry) if any of these hold:
- `system.accounts` is empty → `not-in-use:customer_analytics_billing_and_usage:team{team_id}`. Do not close out on `products_in_use`: it lists onboarding, not usage.
- The billing views are unreachable → `pattern:customer_analytics_billing_and_usage:no-billing-source:team{team_id}`.
Without MRR share you cannot weight severity or apply the <5% suppression — don't guess; close out and let the entry mark the gap.
- The roster doesn't join to billing (Orient's overlap check finds ~0 `external_id` ↔ `organization_id` matches) → `pattern:customer_analytics_billing_and_usage:billing-join-unlinked:team{team_id}`.
Re-running with the same key idempotently refreshes the timestamp.
How a run works
Cycle between these moves; skip what's not useful. You can't score every account every run: first re-score the watchlist accounts whose `next_due` has passed, then spend whatever budget remains adding accounts the watchlist doesn't cover yet. Coverage builds across runs instead of restarting cold.
Get oriented
- `scout-scratchpad-search` (`text=customer_analytics_billing_and_usage`, high limit) — watchlist, per-pair baselines, the billing-source mapping, `report:` / `noise:` / `dedupe:` pointers.
- `scout-runs-list` (last 7d) — what prior runs scor
Official PostHog plugin for AI clients. Access PostHog products directly from your AI coding tool.
Other skills on ai-plugin.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about signals-scout-customer-analytics-billing-and-usage.
- Which coding agents can use signals-scout-customer-analytics-billing-and-usage?
- signals-scout-customer-analytics-billing-and-usage installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

