Managing Self Driving Spend
PostHogOfficialPublished by PostHog
- Skill
- Workflow
- Data and AI
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured workflow for auditing and managing the costs of Self-driving (Inbox) features. It enables users to understand their spending patterns by breaking down credits used by signal sources, scouts, and daily activity. By linking costs to report production and resolution rates, the agent helps identify inefficiencies and recommends specific, user-confirmed actions to reduce or cap expenses without compromising critical data ingestion.
What it does
- Calculates and explains monthly Self-driving spend in credits and USD.
- Drills down into spend by specific signal sources, scouts, and daily usage.
- Evaluates the yield and effectiveness of scouts and sources based on settled reports.
- Identifies high-cost areas within sources that account for significant spend.
- Recommends actionable controls like pausing scouts, setting limits, or adjusting source configurations.
- Applies cost-saving changes only after explicit user confirmation.
When to use it
- When you need to understand why your Self-driving or Inbox bill is higher than expected.
- When you want to identify which specific scouts or signal sources are driving the most costs.
- When you need to implement daily report limits or billing caps to control expenses.
- When you want to optimize your configuration by pausing underperforming scouts or sources.
- When you need to investigate daily spend spikes or evaluate the ROI of automated reporting.
Advantages
- Provides granular visibility into cost drivers by source and scout.
- Distinguishes between necessary operational costs and potential waste.
- Ensures safety by requiring explicit user approval before applying any configuration changes.
- Offers data-driven recommendations based on report resolution and yield metrics.
- Helps balance cost-saving measures with the need to maintain data integrity.
Usage examples
- “Why is my Inbox spend so high this month?”
- The agent will analyze the current month's usage, break down the spend by source and scout, and highlight any specific areas contributing to the high bill.
- “Can you help me reduce my scout costs?”
- The agent will evaluate scout performance and yield, then suggest specific scouts to pause or optimize based on their contribution to spend and report resolution.
- “How do I set a daily limit for my reports?”
- The agent will explain how to set the daily report limit in the settings and describe the impact on signal processing and potential data loss.
- “Which signal sources are costing the most?”
- The agent will provide a breakdown of spend by source, identifying those responsible for more than 10% of the total signal spend and offering a deep dive into their components.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/posthog/managing-self-driving-spend/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip managing-self-driving-spend.zip -d .agents/skills
Documentation by PostHog
Managing Self-driving spend
Start with posthog:inbox-usage-get for monthly recorded usage, including processing, research, repository selection, scout execution, and automatic report implementation.
Pass month: "YYYY-MM", or omit it for this month; history starts no earlier than October 2026, and a project's first receipt can be later.
Show amounts as AI credits, with the USD value next to them: multiply decimal credits by the returned pricing.usd_per_credit.
Recorded usage includes exempt work and is not an invoice; use posthog:billing-limits-get for the billing spend and limit.
On a large project these tools can return more than fits in your context. If yours saves the output to a file, parse the file with a script, and keep the fields you need.
Workflow
Scope. Use the selected project and requested dates, defaulting to this UTC calendar month. Read
posthog:inbox-usage-getandposthog:billing-limits-get. Use the returned canonicalproject_idfor SQL reconciliation; child environments resolve to their parent and require access there.Inventory. List sources with
posthog:inbox-source-configs-listand scouts withposthog:scout-config-list. Explain historical spend even for disabled items; recommend controls only where they still apply.By source and scout. Use the monthly tool's
sourcesandscouts; theirtotal_creditssum to the overall total. Sources include downstream research and implementation; scouts contain execution only, including runs with no reports.Drill down. Use
posthog:execute-sqlwith references/queries.md for custom dates, individual runs or reports, and finer source breakdowns. If the monthly tool is unavailable, use the SQL ledger subject to its access controls; report credits if no verified USD conversion is available.By day. Run "First receipt" and "Spend by day" in references/queries-spend.md, and investigate spikes by source, scout, or
kind.Yield. Run "Baselines", "Yield by signal source", and "Yield by scout" in references/queries-yield.md. Yield is the share of settled reports that were resolved. Compare each item with its baseline on both settled rate and cost per resolved.
Inside each large source. Run "Breakdown inside a source" in references/queries-source-parts.md for every source that holds more than 10% of signal spend. This finds the specific scanners, signal types, evaluations, alerts, or channels behind the spend, which is where most recommendations come from.
Recommend. Go through every control in references/controls.md and decide whether it applies, using references/recommendations.md. Before you judge a scout, find out what kind of scout it is. A quiet run or an unresolved report is not always waste. Name the specific item to change, give a dollar figure, say what the user loses, and say whether you can apply it.
Apply. Change nothing without an explicit yes for that specific change. references/controls.md lists the tool for each control, or where to change it in the app when no tool exists. Read the setting back after you change it.
Present the result with references/report-template.md.
Rules
Sum each
system.signal_spendrecord once. Signalmetadata.total_spend, scoutspend_credits, and report detail totals are copies or overlapping views, not additional charges.Filter finalized usage by
finalized_atwith inclusive start and exclusive end in UTC. Work started earlier can finalize in this period.Show
exempt_creditsas a subset, not an additional cost. Use receipt exemptions rather than excluding named sources or scouts; non-exempt usage is still not necessarily invoiced usage.Report
unsettled_credits,untracked_scout_run_count, and any row withincompletetrue. Unsettled credits cover work created in the requested month, exclude finalized totals, and are not the outstanding balance across all months. Missing receipts mean unknown cost.Explain the two summary flags by their cause.
incompleteis true when any work is unsettled, any scout run is untracked, or any row is incomplete, so it is usually true while Self-driving is running.attribution_incompleteis true when any spend has no source, which is the null-source row.Preserve unattributed costs, including implementation for deleted reports. Implementation is attributed to the report's current triggering signal, which can change.
Implementation usage covers automatic runs only. A fix that a person starts from a report is metered as PostHog AI, so it has no receipt here. Do not present implementation usage as the total cost of fixing reports, and do not estimate fix cost from pull request counts.
Use latest signal metadata only for attribution, with one embedding model and rendering. Do not filter metadata by signal arrival date when attributing period spend.
Reports need about 14 days to resolve, so measure yield on settled reports: reports first shown at least 14 days ago. Take them from the last 60 days, even when the spend period is shorter. When a source or scout has fewer than 20 settled reports, call its yield too new to judge, and recommend no cut that rests on it.
Do not treat a low resolved share as waste for a scout that measures, digests, or hands off work. references/recommendations.md says how to judge each kind.
Private scout trials are excluded from the SQL tables. Scout report counts can overlap; deduplicate IDs for project totals, and never add shared scout costs across report details.
A scout that rarely creates reports can still be useful if it edits existing ones. Check
edited_report_idsbefore you recommend pausing it.A scout with a pre-check can have few runs on purpose, because a skipped run leaves no run row. Read
last_precheck_atandlast_precheck_outcomebefore you call its runs missing.Turn off a source only after you check its narrowing settings and source steering. references/controls.md lists which sources read
steering.Never turn off error tracking ingestion or lower its rate limits to save Self-driving spend. That drops exception data permanently. Change the Self-driving source instead.
Files
- ATTRIBUTION.mdAdded by AutoGineer873 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md7.1 KiB
- references/controls.md16.2 KiB
- references/queries-controls.md4.0 KiB
- references/queries-source-parts.md5.3 KiB
- references/queries-spend.md5.0 KiB
- references/queries-yield.md7.1 KiB
- references/queries.md3.2 KiB
- references/recommendations.md10.2 KiB
- references/report-template.md2.5 KiB
references/queries-source-parts.md
Source part queries
Read the placeholders and HogQL rules in queries.md first.
Breakdown inside a source
part is the setting-level item inside a source: a scanner, an evaluation, an alert, a ticket channel and priority, a severity, or a page.
Error tracking has no part, because its signal types are already separate rows in source_type.
Filter the results to the source you are reading.
SELECT
nullIf(JSONExtractString(ifNull(m.metadata, '{}'), 'source_product'), '') AS source_product,
nullIf(JSONExtractString(ifNull(m.metadata, '{}'), 'source_type'), '') AS source_type,
multiIf(
source_product = 'replay_vision', JSONExtractString(m.metadata, 'extra', 'scanner_name'),
source_product = 'llm_analytics', JSONExtractString(m.metadata, 'extra', 'evaluation_name'),
source_type = 'anomaly_investigation', JSONExtractString(m.metadata, 'extra', 'alert_name'),
source_product = 'conversations', concat(JSONExtractString(m.metadata, 'extra', 'channel_source'), ' / ', JSONExtractString(m.metadata, 'extra', 'priority')),
source_product = 'pganalyze', JSONExtractString(m.metadata, 'extra', 'severity'),
source_product = 'google_search_console', JSONExtractString(m.metadata, 'extra', 'page'),
''
) AS part,
sum(a.credits) AS recorded_credits,
sumIf(a.credits, a.kind = 'ad-hoc') AS processing_credits,
sumIf(a.credits, a.kind IN ('research', 'repo_selection')) AS research_credits,
sumIf(a.credits, a.kind IN ('reviewer_triggered_implementation', 'scout_triggered_implementation')) AS implementation_credits
FROM (
SELECT
s.credits AS credits,
s.kind AS kind,
if(s.report_key != '', r.trigger_key, s.signal_key) AS signal_key
FROM (
SELECT
credits, kind,
ifNull(toString(report_id), '') AS report_key,
ifNull(toString(signal_id), '') AS signal_key
FROM system.signal_spend
WHERE finalized_at >= {date_from} AND finalized_at < {date_to}
AND kind != 'scout_run'
) AS s
LEFT JOIN (
SELECT toString(id) AS rid, toString(triggering_signal_id) AS trigger_key
FROM system.inbox_reports
) AS r ON s.report_key = r.rid
) AS a
LEFT JOIN (
SELECT document_id, argMax(metadata, inserted_at) AS metadata
FROM document_embeddings
WHERE model_name = 'text-embedding-3-small-1536'
AND product = 'signals' AND document_type = 'signal' AND rendering = 'plain'
GROUP BY document_id
) AS m ON a.signal_key = m.document_id
GROUP BY source_product, source_type, part
ORDER BY recorded_credits DESC
LIMIT 300Yield for the same parts:
SELECT
b.source_product AS source_product,
b.source_type AS source_type,
b.part AS part,
uniqExactIf(b.report_id, b.ts >= {date_from}) AS reports_created,
uniqExactIf(b.report_id, r.settled = 1) AS settled_reports,
uniqExactIf(b.report_id, r.settled = 1 AND r.status = 'resolved') AS settled_resolved,
round(settled_resolved / greatest(settled_reports, 1), 3) AS settled_rate
FROM (
SELECT
document_id,
min(timestamp) AS ts,
argMax(JSONExtractString(metadata, 'source_product'), inserted_at) AS source_product,
argMax(JSONExtractString(metadata, 'source_type'), inserted_at) AS source_type,
argMax(JSONExtractString(metadata, 'report_id'), inserted_at) AS report_id,
argMax(multiIf(
JSONExtractString(metadata, 'source_product') = 'replay_vision', JSONExtractString(metadata, 'extra', 'scanner_name'),
JSONExtractString(metadata, 'source_product') = 'llm_analytics', JSONExtractString(metadata, 'extra', 'evaluation_name'),
JSONExtractString(metadata, 'source_type') = 'anomaly_investigation', JSONExtractString(metadata, 'extra', 'alert_name'),
JSONExtractString(metadata, 'source_product') = 'conversations', concat(JSONExtractString(metadata, 'extra', 'channel_source'), ' / ', JSONExtractString(metadata, 'extra', 'priority')),
JSONExtractString(metadata, 'source_product') = 'pganalyze', JSONExtractString(metadata, 'extra', 'severity'),
JSONExtractString(metadata, 'source_product') = 'google_search_console', JSONExtractString(metadata, 'extra', 'page'),
''
), inserted_at) AS part
FROM document_embeddings
WHERE model_name = 'text-embedding-3-small-1536'
AND product = 'signals'
AND document_type = 'signal'
AND rendering = 'plain'
AND timestamp >= {yield_from}
AND timestamp < {date_to}
GROUP BY document_id
) AS b
LEFT JOIN (
SELECT
toString(id) AS rid,
status,
if(first_visible_at IS NOT NULL AND first_visible_at <= now() - INTERVAL 14 DAY, 1, 0) AS settled
FROM system.inbox_reports
) AS r ON r.rid = b.report_id
WHERE b.report_id != ''
GROUP BY source_product, source_type, part
ORDER BY reports_created DESC
LIMIT 300Join the two results by source and part when you present them.
Both queries stop at 300 rows, and a project with many alerts or pages can reach that. If a result has exactly 300 rows, it is cut off: run it again for one source, with HAVING source_product = '...' in the spend query and AND b.source_product = '...' in the yield query.
A source whose parts are each small (under about $5 a month) has nothing worth narrowing. Say that, and move on.
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.
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/managing-self-driving-spend · 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 managing-self-driving-spend.zip