
inbox-exploration
Explore PostHog's Inbox and act on what it surfaces — the place where signal reports cluster into actionable issues and trends. Use when the user asks "what's in my inbox?", "what should I look at?", "which reports are actionable?", "what's PostHog flagged recently?", asks about a specific report by ID or title, wants to act on / fix / implement a report (turn it into a PR), wants to resolve, dismiss, or snooze a report, or wants to see which signal sources are configured. Covers listing, filtering, drilling into, and acting on reports, plus pointers to the deeper signals skill when raw signals or semantic search are needed.
- Installs
- 201
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/posthog/ai-plugin --skill inbox-exploration- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads inbox-exploration automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Exploring the Inbox
The Inbox is where PostHog surfaces signal reports — clusters of related observations (signals) that have been aggregated into a single issue or trend (e.g. "Error rate spiked 3× on /checkout"). Reports come from multiple source products: error tracking, session replay, web analytics, experiments, and integrations like Linear, GitHub, and Zendesk.
Inbox is part of PostHog Desktop, PostHog's agentic surface for engineering teams.
Don't assume the user's project has reports, or that any signal sources are configured — plenty of projects don't have Inbox set up. Always run the setup-check workflow below before answering the user's actual question.
When to use this skill
- "What's in my inbox?" / "What should I look at first?"
- "Show me actionable reports" / "What's PostHog flagged recently?"
- "Are there any reports about <topic / product area>?"
- "What signal sources are configured for this project?"
- The user pastes a report ID or URL and wants context
- "Fix this inbox item" / "turn this report into a PR" / "implement this report" — see Workflow: act on an actionable report
- "Dismiss this" / "snooze this report" / "mark this resolved" / "I've fixed this" — see Workflow: resolve, dismiss, or snooze a report
- "Get this merged" / "run the suggested prompt on this report" — see Workflow: run an action on a report
For deeper investigation, hand off to other skills and tools:
signalsskill — querydocument_embeddingsvia HogQL for raw signal text, semantic search across signals, or to inspect every signal that contributed to a report.- PostHog's product-specific MCP tools — when a report points at a specific error, log line,
session, person, or time range, reach for the matching domain tool to pull richer context:
- Error tracking:
query-error-tracking-issues-list,query-error-tracking-issue,query-error-tracking-issue-eventsfor error-tracking-sourced reports - Logs:
query-logs,logs-count-rangesto find log activity around the issue - Session replays:
query-session-recordings-list,session-recording-getto find recordings of affected users - Persons / activity:
persons-retrieve,advanced-activity-logs-listto inspect a specific user's behavior - Trends / SQL:
query-trends,execute-sqlfor ad-hoc verification queries
- Error tracking:
A signal report tells you what PostHog clustered. The product-specific tools tell you the underlying detail — pair them when the user wants to dig in.
Available tools
| Tool | Purpose |
|---|---|
inbox-reports-list | Paginated list of reports with filters (status, search, etc.) |
inbox-reports-retrieve | Full detail for a single report |
inbox-reports-claim | Claim or release a report, and optionally attach its implementation PR |
inbox-report-artefacts-list | A report's full work log — signal_finding evidence, status judgments, commits, task runs, notes (read-only) |
inbox-report-artefacts-retrieve | Full detail for a single artefact (read-only) |
inbox-reports-set-state | Resolve (resolved), dismiss (suppressed), or snooze (potential) a single report |
inbox-reports-bulk-set-state | Same transition for 1–100 reports in one call (per-id result) |
inbox-report-actions-list | The report's agent run actions (Get it merged, suggested prompts) and whether each can start now (read-only) |
inbox-report-actions-run | Start one of those actions as a background agent run linked to the report |
inbox-ranking-outcomes-list | What each ranking model outcome predicts, with its horizon, cohort and base rate (read-only) |
inbox-source-configs-list | Configured signal sources (which products feed the inbox) |
inbox-source-configs-retrieve | Full record for a single source config |
inbox-source-configs-partial-update | Toggle a source's enabled flag (or adjust its config) |
posthog:execute-sql (signals skill) | HogQL access to underlying signals (read the signals skill first) |
The inbox-reports-*-list / -retrieve, inbox-report-artefacts-list / -retrieve, and
inbox-source-configs-*-list / -retrieve tools are read-only. The exposed writes are inbox-reports-set-state (resolve / dismiss / snooze a single report),
inbox-reports-bulk-set-state (the same transition for 1–100 reports in one call),
inbox-reports-claim (claim / release / attach a PR), see
Workflow: resolve, dismiss, or snooze a report — inbox-report-actions-run (start an agent run
from a report action), see Workflow: run an action on a report — and inbox-source-configs-partial-update, which flips a
source's enabled flag on or off (e.g. {enabled: false} to stop a source feeding the inbox);
-create / -update exist too for standing a source up or replacing it wholesale. Pausing
processing is not exposed via MCP.
Terminology
What each report status means (in roughly the order a triage agent should care about):
ready— judgment finished, actionable assessment availablepending_input— waiting on user input to proceedin_progress— actively being summarized / judgedcandidate/potential— accumulated signals but not yet promoted to a real reportfailed— processing erroredsuppressed— out of the inbox; not surfaced by default. A person or agent dismissed it, or a judge held it back before anyone reviewed it. See Dismissed and held-back reports belowresolved— the work the report asked for is done. Terminal: a resolved report never re-promotes, so a recurrence starts a fresh report linked back to it. Set automatically when a linked implementation PR merges, or directly viainbox-reports-set-state(see the workflow below)
By default inbox-reports-list excludes suppressed reports and orders results by
-is_suggested_reviewer,status,-updated_at — the user's own suggested reports first, then by
status, then most recently updated. Refer to the tool's input schema for filter mechanics.
Dismissed and held-back reports
A suppressed report has one of two origins. The inbox shows each origin in its own view, and
inbox-reports-list accepts the same split through its view parameter:
view | Lists suppressed reports that… | suppression_source |
|---|---|---|
dismissed | a person or agent dismissed, or that were merged into another report, or whose PR closed unmerged | dismissed |
held_back | a judge suppressed before anyone reviewed them | safety_judge, not_actionable, system |
Each suppressed row carries two fields that tell the origins apart:
suppression_source—nullunless the status issuppressed.dismissed: someone chose to remove the report. Readdismissal_reasonanddismissal_notefor the reason.safety_judge: the safety judge marked the report unsafe.not_actionable: the actionability judge marked the report not actionable.system: the pipeline suppressed the report for a different reason. An older report that has no dismissal record and no judge verdict also shows this value.
suppression_explanation— the judge's explanation when the source issafety_judgeornot_actionable.nullfor the other sources, or when the judge gave none.
Only dismissed is a human or agent decision. The other sources are judge verdicts that nobody
has reviewed, and a judge can be wrong. Do not tell the user they hid a held-back report.
Include held-back reports in a review when:
- the user asks what PostHog filtered out, or why an expected report is missing from the inbox
- the user asks for a full review or audit of the inbox, not only the actionable queue
- you deduplicate against the full inbox state before you file or merge a report
For a held-back review, call inbox-reports-list with {"view": "held_back"}. Show the
suppression_source and the suppression_explanation for each report, so the user can judge
the verdict. If the user decides that a report is valid, restore it with state: "potential".
The report goes back to the status it had before the judge held it back. If the user agrees with the
verdict, call state: "suppressed" with a dismissal_reason. The report then moves from
held_back to dismissed. See Workflow: resolve, dismiss, or snooze a report for both calls.
What "suggested reviewer" means
is_suggested_reviewer: true on a report means the current PostHog user is one of up to
three people the report-research flow flagged as best-placed to act on this report. It is
the strongest signal you have that a report matters to the user personally, and you should
lean on it when triaging.
How the flag is produced:
- While researching a report, the agent identifies the GitHub commits most relevant to the underlying signals (e.g. commits that touched the failing code path).
- It fetches the authors of those commits, weights earlier/more-relevant commits more
heavily, and keeps the top three GitHub logins. These get persisted as a
SUGGESTED_REVIEWERSartefact on the report. - At read time, those GitHub logins are mapped back to PostHog users via each org member's
linked GitHub identity (social auth or GitHub integration). If the current viewer's
linked GitHub login is one of them,
is_suggested_reviewerflips totruefor that report. A reviewer can also be stored by PostHoguser_uuid(a scout or a person naming an org member directly), which matches the viewer without any GitHub link. The flag is forced tofalseon afailedreport and on areadyreport judgednot_actionable, whatever reviewers they carry, so readsuggested_reviewersdirectly when auditing routing.
Practical implications for triage:
- A
truevalue means "you are a suggested reviewer for this report": a plausible owner, not an assignee. When the pipeline derived the reviewers, that usually means you wrote (or recently touched) the relevant code; when a scout or a person named you byuser_uuid, it means they judged you the owner. It's a recommendation, not authoritative. - A
falsevalue doesn't mean the report is irrelevant — it can mean (a) someone else owns the code, (b) the suggested logins came from commit history and no org member has that GitHub account linked (a reviewer set byuser_uuiddoesn't have this problem), or (c) the source material wasn't tied to a specific repo / commits. - If the user asks "what should I look at?", lead with
is_suggested_reviewer: truereports: these are the ones routed to the user as a likely owner. Mention the rest as a secondary group rather than mixing them in. - If the user has no suggested reports but the inbox isn't empty, say so explicitly ("nothing in the inbox is tied to code you've authored recently") rather than pretending the top of the list is personalized.
Workflow: handling an empty or unconfigured inbox (read first)
Run this check whenever a user asks about the inbox for the first time in a session, or any
time inbox-reports-list returns count: 0. The diagnosis decides what to say next.
Step 1 — Look at source configs
inbox-source-configs-list
{ "limit": 50 }
Three meaningful cases:
Case A — no source configs at all (count: 0)
The user hasn't onboarded to Inbox / signals. Don't pretend the inbox has data. Tell the user plainly that Inbox needs signal sources to be set up first, and that the recommended way to do this is to install PostHog Desktop at https://posthog.com/desktop. Example response:
Your project doesn't have any signal sources configured yet, so the Inbox is empty. Inbox surfaces issues and trends that PostHog automatically clusters from sources like error tracking, session replay, GitHub, Linear, and Zendesk. The fastest way to set this up is to install PostHog Desktop — once it's connected, signals will start flowing in and reports will appear in your inbox over the next day or so.
Stop here unless the user wants to discuss setup. Don't run further inbox tools — they'll all be empty.
Case B — source configs exist but all are enabled: false
Sources have been set up at some point but are currently turned off. Tell the user no signals are
flowing right now. You can re-enable a source directly with
inbox-source-configs-partial-update { "id": "<source_config_uuid>", "enabled": true } (confirm
with the user first), or they can flip it on from the project's signals settings. Don't go fishing
for reports — anything still there is stale.
Case C — at least one source config is enabled: true
Setup looks healthy. If inbox-reports-list still returns nothing, it's most likely "give it time"
— signals are flowing but nothing has clustered into a report yet. Tell the user that, briefly
list which sources are active (e.g. "you have GitHub and error tracking enabled"), and offer to
check back later or to drop into the signals skill to look at raw signal volume.
If any source config has status: "failed", surface that as part of your reply — that source
isn't producing signals right now, which may explain a thin inbox.
Step 2 — Only then proceed to the user's actual question
If Step 1 found a healthy setup and at least one report exists, continue with the triage / drill / filter workflows below.
Workflow: triage what's actionable
When the user asks "what should I look at?" or "what's actionable?":
Step 1 — Pull the ready/in-progress queue
inbox-reports-list
{
"status": "ready,in_progress,pending_input",
"limit": 20
}
If count: 0 comes back, jump to the empty/unconfigured workflow above before saying "your
inbox is empty" — the right reply depends on whether sources are configured.
A claimed report keeps its pipeline status, so this queue also returns work someone else already
owns. Add "unclaimed": true when the user is asking what is free to pick up, and
"assignee": "me" to list what the caller already owns and may want to resume.
Step 2 — Summarize by source and actionability
For each report, the response includes:
id,title,summarystatus,priority,actionability(note:nullfor reports still inpending_input/candidate— judgment hasn't run yet)signal_count,total_weight— how much underlying evidence drove the reportsource_products— which product(s) the underlying signals came fromis_suggested_reviewer— whether the current user is a suggested reviewer for this report (see "What 'suggested reviewer' means" above — it's based on GitHub commit authorship of the relevant code, mapped to PostHog users via linked GitHub identity)pull_requests— if a PR has been opened against this reportwork_state—unclaimed,working,in_review, ordoneassignee— who claimed the report (a user, an internal task, or an external agent), ornullwhen nobody has. Say so when you list a report someone else owns, so it doesn't read as free work_posthogUrl— clickable deep-link to the report; always include this in your response
Group the results so the user can scan quickly. Lead with reports where
is_suggested_reviewer: true — those are the ones tied to code the current user has
authored — and only then fall back to priority groupings for the rest:
## Inbox — 8 actionable reports
⭐ Suggested for you (1)
- Checkout error rate spiked 3× — error_tracking, 47 signals (you're a suggested reviewer)
<_posthogUrl>
🔴 High priority (2 more)
- Session replays on /pricing show repeated rage clicks — session_replay, 12 signals
<_posthogUrl>
…
🟠 Medium priority (4)
…
If no reports come back with is_suggested_reviewer: true, say so explicitly before listing
the rest — don't silently drop the section.
Step 3 — Offer the drill-down
End with a clear hand-off: "Want me to dig into the checkout errors?" → call
inbox-reports-retrieve for the full report, then optionally hop to the signals skill to look
at the underlying signal text.
Workflow: drill into a specific report
When the user pastes an Inbox URL or report ID:
inbox-reports-retrieve
{ "id": "<report_uuid>" }
Returns the full record including signals_at_run and artefact_count. Then read the report's
work log:
inbox-report-artefacts-list
{ "report_id": "<report_uuid>" }
This returns the report's evidence (signal_finding), the judgments behind its
status/priority/actionability (safety_judgment, actionability_judgment, priority_judgment,
repo_selection, suggested_reviewers), and its work-log (commit, task_run, note) — the
curated "why it exists and what's been done" view, in one read-only call.
Use the signals skill only when you need the raw signal text beyond the curated findings:
- Use
inbox-reports-retrieveto get the report metadata +id - Use
inbox-report-artefacts-listfor the curated evidence, judgments, and work-log - Use the
signalsskill's Example 2 (fetch all signals for a specific report) — pass the report ID asmetadata.report_idin the HogQL query — only for the raw underlying signal text
The layers complement each other: inbox-report-artefacts-list gives you the curated/judged view
(evidence + judgments + PR/task-run history), and the signals skill lets you inspect the raw
observations that produced it.
Workflow: act on an actionable report
When the user wants to do something about a report — "fix this inbox item", "turn this into a
PR", "implement this" — not just read it. A ready report with
actionability: immediately_actionable is the usual candidate. The discipline that matters here:
a report is a diagnosis, not ground truth — verify it against the actual code before you
implement. Reports from signals_scout (and any LLM-research source) are especially worth
double-checking; their summary often reads as a confident root-cause with file and function
names, but it can be stale or wrong.
Step 1 — Retrieve, check existing work, and claim it
inbox-reports-retrieve
{ "id": "<report_uuid>" }
Before doing any work, look at:
already_addressed— iftrue, the fix may already be in flight or merged; confirm with the user before duplicating it.pull_requests— inspect existing PRs before opening another; a report can have a stack or PRs across repositories.work_stateandassignee— show whether someone else has already picked it up. A takeover is allowed, but make it deliberate rather than overlooking active work.status— onlyreadyreports carry a finished judgment. Acandidate/pending_inputreport hasn't been researched yet; don't implement off a half-formed summary.
Before starting research or implementation, claim the report:
posthog:inbox-reports-claim
{ "report_id": "<report_uuid>" }
Save the returned assignee.claim_id and pass it on subsequent work updates and artefact writes.
Taking over another actor requires takeover=true; stale claim IDs are rejected.
The claim is attributed to the current internal task or external MCP client. Claims do not expire, so
release the report whenever you walk away without landing a fix — including when you dismiss it instead.
Release clears ownership only; an attached pull request stays on the report, and release works from any
status, so a dismissed report can be released too.
Step 2 — Verify the diagnosis against the code (do not skip)
Start by reading the report's work log — its evidence and the judgments behind it:
inbox-report-artefacts-list
{ "report_id": "<report_uuid>" }
This surfaces the signal_finding evidence, the status/priority/actionability judgments, and any
commit / task_run history — exactly the "why it exists and what's already been done" you need
before touching code. Then the report's summary will name files, functions, and sometimes line
numbers. Open them and confirm the claim holds — that the cited code exists, still looks the
way the report describes, and actually produces the described failure. As a deeper fallback, pull
the raw underlying signals via the signals skill (metadata.report_id) if you need the signal
text behind the curated findings. If the diagnosis doesn't hold up, say so and stop — a wrong
report is itself a useful finding (and a candidate for dismiss below), not a license to write a
speculative fix. Release the claim you took in Step 1 before you stop, so the report returns to the
unclaimed view instead of reading as active work nobody is doing:
posthog:inbox-reports-claim
{ "report_id": "<report_uuid>", "claim_id": "<claim_uuid>", "release": true }
Step 3 — Scope the fix to the right layer
- If
source_productsincludessignals_scoutand the root cause is in a scout's own behavior (the prompt it runs, a threshold it uses), the better fix is often the scout'sSKILL.md, not the harness. Note that per-team custom scouts live in the user's Skills Store, not this repo, so the fix site may be out of reach of a repo PR — flag that to the user. - Otherwise treat it like any normal change: follow the repo's conventions (
CLAUDE.md, area-specific skills), make the change minimal, and add a regression test that would have caught the reported failure.
Step 4 — Open the PR and attach it
Open the PR following the repo's PR conventions, then attach it to the report:
posthog:inbox-reports-claim
{
"report_id": "<report_uuid>",
"claim_id": "<claim_uuid>",
"pull_requests": ["https://github.com/example/repository/pull/123"]
}
PR links are additive and retries do not duplicate them. Send every known PR together so completion
considers the entire stack. The same PR may be attached to multiple reports. Connected repositories receive immediate state
validation and webhook updates. PRs from unconnected repositories are accepted with unknown state,
so resolve those reports manually after the work lands. Also reference the report's _posthogUrl
in the PR description so the loop is traceable from either side.
Don't resolve a report because you opened a PR. A report resolves when all linked PRs are closed
or merged and at least one merged. If all closed without merging, it is suppressed. Any open, draft,
or unknown PR prevents automatic completion. Resolving by hand at PR-open
time asserts work that hasn't landed, and a reviewer looking at the inbox can't tell the difference.
Manual resolve is for fixes a PR merge will never cover — a skill-body change, a config change, a
NO_REPO report — see the workflow below.
Workflow: run an action on a report
A report can offer actions that start an agent run, the same ones the inbox shows as buttons:
Get it merged (get_it_merged) fixes CI on the report's open, approved pull request and merges
it, and each suggested prompt (suggested_prompt) sends one prompt the report suggests. Use
these instead of tasks-create-and-run: a run started here is linked to the report, so it shows in
the report's runs, counts toward the report's task limit, and gets the report's code access rules.
The two tools are rolling out behind a flag, so they can be missing from your tool list. If they
are, send the person to the report's _posthogUrl to press the button.
Step 1 — List the actions
posthog:inbox-report-actions-list
{ "report_id": "<report_uuid>" }
Every action comes back, available or not. Pick one with available: true. When an action is not
available, disabled_reason says why (no approved open PR, AI data processing not approved, and so
on): tell the person rather than trying to run it. text is the message the run gets as its first
request, so show it when the person wants to know what the agent will be asked to do.
Step 2 — Confirm, then run it
Starting a run creates a task that spends the organization's usage, and Get it merged can merge a pull request. Confirm with the person before you run an action they did not ask for by name.
posthog:inbox-report-actions-run
{ "report_id": "<report_uuid>", "action": "suggested_prompt", "suggested_prompt_index": 0 }
Pass suggested_prompt_index only for suggested_prompt, with the value from the list. A 201
returns task_id, run_id, and task_url. Each successful call creates a new task, so do not
retry it. If run_error is set, the task exists but its run did not start: report the error and do
not start a second one.
Step 3 — Follow the run
The run works in the background. Follow it with tasks-runs-retrieve using task_id and run_id,
and give the person task_url. Nobody can answer questions in a background run, so when the agent
needs a decision it writes a note to the report's work log. Read new notes with
inbox-report-artefacts-list.
Errors
Every refusal carries a code. Do not retry any of them unchanged.
| Status | code | What to do |
|---|---|---|
| 400 | report_action_unavailable | The action is not available now. Tell the person the detail. |
| 403 | report_action_unavailable | The organization has not approved AI data processing. An admin turns it on in settings. |
| 403 | report_action_sandbox_refused | A task sandbox cannot start report actions. Ask a person to start it from their own session. |
| 409 | report_action_run_active | A merge run is already working on the report. Follow the task_id and run_id in the body. |
| 429 | signal_report_task_cap | The report reached its task limit. Work with the runs it already has. |
| 429 | throttled, usage_limit_exceeded | A per-user or organization usage limit fired. Wait until it clears. |
| 402 | self_driving_free_trial | The organization is on a Self-driving free trial, which cannot open pull requests. |
| 404 | none | The report has no suggested prompt at that index. List the actions again and use a fresh index. |
Workflow: resolve, dismiss, or snooze a report
Three outcomes, one tool. Pick by what actually happened to the underlying issue:
| The issue is… | State | Why |
|---|---|---|
| fixed by work you did | resolved | terminal; the report has served its purpose |
| not real, or not worth fixing | suppressed | dismissed from the inbox, with the reason recorded |
| real but deferred, or fixed by something else | potential | back into the pipeline; reappears if it recurs |
inbox-reports-set-state
{
"id": "<report_uuid>",
"state": "suppressed",
"dismissal_reason": "analysis_wrong",
"dismissal_note": "Verified against products/foo/bar.py — the cited code path can't reach this state."
}
state: "resolved"marks the requested work done, and is terminal — a recurrence starts a fresh report rather than reopening this one. Allowed fromready/pending_input, or from asuppressedreport that held one of those when archived; anything else returns409. Only resolve work that has actually landed. A fix shipping as a PR resolves itself on merge (see Step 4); resolve by hand only where the webhook can never reach — a skill-body edit, a config change, aNO_REPOreport. Recorddismissal_reason: "fixed_outside_posthog"for that (the fix landed without a pull request); usepr_mergedwhen a pull request with the fix was merged but did not resolve the report on its own; reservealready_fixedfor an issue fixed before the report was filed. Don't usealready_fixed+state: "potential"when you did the fixing: that pairing means "fixed by something else, might recur", so the report comes back.state: "suppressed"dismisses the report from the inbox;state: "potential"snoozes it back into the pipeline. When snoozing,snooze_for: <N>holds it until it accumulates N more signals.dismissal_reasonmust be one of the server-validated canonical codes —already_fixed,report_unclear,analysis_wrong,wrong_assignee,wrong_repo,wontfix_intentional,wontfix_irrelevant,fixed_outside_posthog,no_action_needed,pr_merged,other— an unlisted value returns400. Reach forotherplus adismissal_notefor anything that doesn't fit a specific code.dismissal_noteis free-form (≤ 4000 chars). Both persist as a DISMISSAL artefact, so the rationale survives later transitions — always include them, on a resolve too, so a future reader knows why.wrong_repomeans the agent researched the report against the wrong repository. Pair it withcorrected_repository("owner/repo", case-insensitive; only allowed with this reason) naming the right one: the correction is recorded on the dismissal and fed into every future repository selection for the project, and when the named repository is connected to the project it also becomes this report's own next selection. Without a usable correction the report's selection is cleared instead, so a restored report re-selects rather than reusing the rejected repository.wrong_assigneemeans the report reached the wrong person or team. It is routing feedback, not a verdict that the report itself was wrong.- On a dismiss, snooze, or restore, the
dismissal_noteis also forwarded as a steering note to the scout that filed the report, which every scout run reads at cold start, so what you write there is what stops the same report being filed again. Write it for that reader: name the evidence that settles it, not just the verdict. A resolve is not forwarded, since it says the report did its job rather than that filing it was wrong; that note stays on the report. Awrong_repodismissal is forwarded even with no note: the steering note names the repository the report wrongly targeted and, when you passed one, thecorrected_repository. Forwarding needs the same skill-editing access as leaving a scout note by hand, so on a project where you lack it the note still lands on the report but does not reach the scout. - It's a destructive, non-idempotent transition and returns
409if it isn't allowed from the report's current status (and400ifdismissal_reasonisn't a canonical code). Confirm with the user before suppressing, and capture why in the note — a dismissal with no rationale is worse than none. A report you dismissed because the diagnosis was wrong (Step 2 above) is the textbook case: suppress it withanalysis_wrongand the evidence in the note. A refunded report is frozen: snooze and resolve both come back409/skippedwith an explanatorydetail. - To transition several reports at once, use
inbox-reports-bulk-set-statewith anidsarray (1–100). It applies the samestate/dismissal_reason/dismissal_note/corrected_repository/snooze_forto every id and returns a per-idresultslist (in request order) plus atransitioned_count/skipped_count/failed_count/not_found_countsummary. Each id is processed independently, so the call returns200even on partial failure — an id whose transition isn't allowed comes back asskipped(the single-report409) while the rest go through. Inspect the per-id outcomes rather than assuming the whole batch succeeded.
Workflow: filter by topic or source
"Are there any reports about <topic>?" — start with search:
inbox-reports-list
{
"search": "checkout",
"status": "ready,in_progress,pending_input",
"limit": 20
}
search matches title and summary. If the user is asking about a product area rather than a
keyword, use source_product:
inbox-reports-list
{
"source_product": "session_replay,error_tracking",
"limit": 20
}
If the keyword search returns nothing meaningful, hand off to the signals skill — semantic
search over signal text via embedText() will catch reports the keyword filter missed.
Model predictions as building blocks
The inbox ranking model predicts outcomes for each report. Each row of inbox-reports-list and
inbox-reports-retrieve carries them in ranking:
"ranking": {
"status": "scored",
"scored_at": "2026-10-24T05:12:00Z",
"predictions": [
{ "outcome": "open", "probability": 0.21, "lift": 1.5, "readable": true },
{ "outcome": "action", "probability": 0.09, "lift": 1.4, "readable": true },
{ "outcome": "fix", "probability": 0.3, "lift": 2.7, "readable": true }
]
}
open: a person opens the report.action: a person or their agent acts on it.fix: someone fixes the problem it describes. Callinbox-ranking-outcomes-listfor the current meaning, horizon and base rate of each outcome, because they follow the served model.- A prediction says what may happen, never what did. A high
fixprobability does not mean the report is fixed: readstatusand the PR fields for that. - A lift is the probability divided by the outcome's base rate. 1.0 is an average report, 2.7 is 2.7x as likely. Compare lifts across outcomes. Raw probabilities do not compare, because each outcome has its own base rate.
readable: falsemeans the training run could not measure the holdout AUC of that outcome. Rank and filter on that outcome with caution.statusisscored,stale(the title or summary changed after scoring, so the predictions describe the old text),unscored(no score yet, which is not a low score), ornot_available(the user cannot see the ranking model, so ordering and filtering by it return 400).inbox-reports-retrievealso names themodelthat made the predictions. Predictions from different models do not compare.
Recipes:
- Likely to get a fix:
view=actionablewithordering=-ranking_fix. - Hidden gems:
priority=P3,P4withranking_min_lift=fix:2. - Probably noise: reports with a low lift on all three outcomes are candidates to dedupe or dismiss. Read them before you act: a low lift is a hint, not a verdict.
- Add
searchorsource_productto any recipe to narrow it to a topic.
ranking_min_lift and ranking_min_probability take comma-separated <outcome>:<value> pairs,
and a report must meet every pair. Unscored and stale reports never match.
Caveats:
- The predictions are model estimates, and the top end over-predicts. Use them to rank and filter, not as literal odds.
- Most
fixpositives are alsoactionpositives, so do not add the two together.
Workflow: review configured sources
When the user asks "which signal sources are set up?" or "is <product> hooked up?":
inbox-source-configs-list
{ "limit": 50 }
Each entry returns id, source_product, source_type, enabled, status, plus timestamps.
For full details (including the per-source config JSON — recording filters, evaluation IDs,
etc.):
inbox-source-configs-retrieve
{ "id": "<source_config_uuid>" }
Integration credentials live in a separate Integration model — they are not in the
config blob, so it's safe to summarize the contents back to the user.
The status field reflects the underlying data import or workflow:
running/completed— feeding signals normallyfailed— the source isn't currently producing signals; flag this to the user
To turn a source on or off, use inbox-source-configs-partial-update with the config's id and
{ "enabled": true | false } — only the fields you pass change, so this is the right tool for a
plain toggle (-update replaces the whole record; -create stands up a new source). Confirm with
the user before flipping a source, since enabling one drives signal processing and spend.
inbox-source-configs-partial-update
{ "id": "<source_config_uuid>", "enabled": false }
Tips
- Check setup before assuming the inbox is empty. If
inbox-reports-listreturnscount: 0, callinbox-source-configs-listfirst — no sources means the user needs to install PostHog Desktop to start receiving signals; sources-but-no-reports means signals are flowing but nothing has clustered yet - Always surface
_posthogUrlso the user can click through to the report - The default ordering already prioritizes the user's suggested reports — don't reorder unless asked
priorityandactionabilityarenullfor reports still inpending_inputorcandidatestatus; this is expected, not a bug — judgment hasn't run yetsuppressedreports are excluded by default. Passview: "dismissed"for reports someone dismissed,view: "held_back"for reports a judge held back, orstatus: "suppressed"for both. Readsuppression_sourcebefore you describe why a report left the inbox- The inbox writes exposed via MCP are
inbox-reports-set-state(resolve / dismiss / snooze one report),inbox-reports-bulk-set-state(the same for 1–100 reports),inbox-reports-claim(claim / release / attach a PR), andinbox-source-configs-partial-update(toggle a source'senabledflag). To act on a report (implement a fix), claim it, verify the diagnosis against the code, then open and attach a PR — see Workflow: act on an actionable report. A PR-backed fix is resolved automatically when the PR merges, so don't resolve it by hand at PR-open time. Always also surface the_posthogUrldeep-link - Never implement a report's fix straight from its
summary. Reports — especiallysignals_scoutones — are LLM diagnoses; confirm the cited files / functions / behavior in the actual code before writing a fix. A report that doesn't hold up is a dismissal candidate, not a fix - For "what kinds of signals exist?" or "what's been happening recently across all sources?",
drop into the
signalsskill — the report layer hides individual observations; you need HogQL ondocument_embeddingsto see them - Source configs don't have per-record deep-links — they live behind project settings, so
inbox-source-configs-retrievereturns no_posthogUrl. Don't confuse them with reports
FAQ
What does the inbox-exploration skill do?
Explore PostHog's Inbox and act on what it surfaces — the place where signal reports cluster into actionable issues and trends. Use when the user asks "what's in my inbox?", "what should I look at?", "which reports are actionable?", "what's PostHog flagged recently?", asks about a specific report by ID or title, wants to act on / fix / implement a report (turn it into a PR), wants to resolve, dismiss, or snooze a report, or wants to see which signal sources are configured. Covers listing, filtering, drilling into, and acting on reports, plus pointers to the deeper signals skill when raw signals or semantic search are needed.
How do I install inbox-exploration?
Run npx skills add https://github.com/posthog/ai-plugin --skill inbox-exploration in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/inbox-exploration/ (personal) or .claude/skills/inbox-exploration/ (project).
Which AI agents can use inbox-exploration?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is inbox-exploration safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains inbox-exploration?
It is published by posthog in posthog/ai-plugin, and it is an official skill from the maker of the technology it covers. It has 201 recorded installs.
More from posthog/ai-plugin
instrument-product-analytics
posthog/ai-plugin
Add PostHog product analytics events to track user behavior. Use after implementing new features or reviewing PRs to ensure meaningful user actions are captured. Also handles initial PostHog SDK setup if not yet installed.
instrument-feature-flags
posthog/ai-plugin
Add PostHog feature flags to gate new functionality. Use after implementing features or reviewing PRs to ensure safe rollouts with feature flag controls. Also handles initial PostHog SDK setup if not yet installed.
cleaning-up-stale-feature-flags
posthog/ai-plugin
Identify stale feature flags in a PostHog project and clean up the code that checks them. Use when the user wants to find, audit, or remove unused, fully rolled out, or abandoned feature flags, run a feature flag hygiene review or a weekly cleanup, reduce feature flag tech debt, or asks "which flags can I remove?". When the agent can read and edit a repository it performs the code cleanup itself: tested local changes, and one draft PR per flag when the user authorizes publishing. Agents without repository access generate a tailored cleanup prompt instead. Covers staleness detection, dependency checking, retained-path rules, and the code-first ordering. This skill does not archive or otherwise change a flag in PostHog.
auditing-experiments-flags
posthog/ai-plugin
Audit PostHog experiments and feature flags for configuration issues, staleness, and best-practice violations. Read when the user asks to audit, health-check, or review experiments or feature flags, check flag hygiene, or verify experiment setup.
querying-posthog-data
posthog/ai-plugin
Explains how to query PostHog data, defaulting to typed runners for supported product analytics. Read it before you write HogQL/SQL. Also read it before you call execute-sql against PostHog. Use it to find or aggregate PostHog entities. These entities include insights, dashboards, cohorts, feature flags, experiments, surveys, hog flows, warehouse data, and persons. Use it for trends, funnels, retention, lifecycle, paths, stickiness, web analytics, error tracking, logs, sessions, and LLM traces. Before you calculate a governed business or telemetry measure, check system.informationschema.metrics for an approved definition. Examples include MRR, activation, billable usage, active organizations, and failure rates. Use the approved definition before you derive a measure from raw events or use a typed domain tool. It also covers HogQL differences, system table schemas, functions, query examples, and schema discovery.
creating-experiments
posthog/ai-plugin
Guides agents through experiment creation: reading the project's setup with experiment-setup-context, defining the hypothesis, configuring rollout and bucketing, setting up analytics and running time, and reporting which choices are guesses. Delegates rollout decisions to configuring-experiment-rollout and metric setup to configuring-experiment-analytics. TRIGGER when: user asks to create a new experiment or A/B test, OR when you are about to call experiment-create. DO NOT TRIGGER when: user is updating an existing experiment, managing lifecycle, or only browsing experiments.
Popular docs & writing skills
grill-with-docs
mattpocock/skills
A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go.
lark-markdown
open.feishu.cn
飞书 Markdown:查看、创建、上传、编辑和比较飞书中的原生 Markdown 文件。当用户要操作飞书 Markdown 文件,或比较其远端版本及本地草稿时使用。纯本地 Markdown 文件操作不触发本 skill。不负责将 Markdown 导入为飞书在线文档,也不负责文件搜索、权限、评论、移动、删除等云空间管理操作。
writing-beats
mattpocock/skills
Writing, exploit; assemble raw material into a journey of beats, grounding each term before a beat leans on it.
writing-shape
mattpocock/skills
Writing, exploit: shape raw material into an article, paragraph by paragraph.
writing-fragments
mattpocock/skills
Writing, explore: mine raw fragments, no structure yet.
writing-for-agents
mattpocock/skills
Writing documents for agents. Use when creating or editing skills, or modifying AGENTS.md or CLAUDE.md.