Triaging Visual Review Runs

by PostHog469d1773e9cbNo licenseListed Oct 8, 2026Updated Oct 8, 2026

Inspects PostHog Visual Review (VR) runs that gate PR merges with screenshot regression checks. Use when the user mentions "visual review", "VR", "snapshot diff", "screenshot test", "storybook regression", "playwright snapshot", asks why a PR is blocked or what changed visually, wants to triage the VR backlog, decide whether a snapshot diff is real vs flaky, or check whether a story has been changing across runs. Also invoke when a PR has a failing `visual-review` status check, when a PR comment mentions "Visual review", or when the user is on a branch with an open VR run.

AI-generated overview

Triages PostHog Visual Review runs that gate PRs with screenshot regression checks, using VR MCP tools.

What it does
Guides an agent through PostHog Visual Review (VR) runs that gate pull requests with storybook and playwright screenshot diffs. It chains VR MCP read tools to report run status, snapshot scope, per-story history and queue counts, and uses reversible triage marks plus a finalize step that commits the baseline and greens the GitHub check. It produces per-snapshot verdicts on whether a diff is a real regression or a flake, with a recommended action.
When to use it
Use when a PR has a failing visual-review status check, when a PR comment mentions visual review, or when the user asks why a PR is blocked, what changed visually, or whether a snapshot diff is real or flaky. Also suited to triaging a backlog of VR runs or checking whether a story has been changing across runs.
Requirements
Requires access to the PostHog Visual Review MCP tools (run, snapshot, history, counts, repos, approve, tolerate, finalize) and network access to PostHog and to pre-signed S3 artifact URLs for pulling baseline and current PNGs. Instructions only; ships no scripts.

Triaging visual review runs

Visual Review is PostHog's screenshot-regression product: CI captures storybook + playwright screenshots, diffs them against committed baseline hashes, and gates the PR until a human approves the visible changes. A PR with visual changes carries a visual-review GitHub status check that stays red until each diffed snapshot is approved or tolerated in the VR UI.

This skill teaches an agent how to answer the questions a human reviewer would actually ask, by chaining the VR MCP tools — instead of reaching for gh pr view and tab-hopping to the VR web UI. The read tools cover status / scope / history / triage. Two are reversible DB-only triage marks (approve-create, tolerate-create); one ships the change (finalize-create) — it commits the baseline and greens the gate, and only that one needs explicit per-run human confirmation.

When this skill applies

Trigger this skill on any of:

  • A PR number, branch name, or commit SHA paired with words like visual review, VR, snapshot, screenshot, storybook diff, playwright snapshot, baseline, approve, tolerated, quarantine.
  • Questions about why a PR is blocked, what visually changed, or whether a diff is real.
  • "Is my run done?" / "What's left to review?" / "Has this story flaked recently?"
  • A failing visual-review GitHub check or a PR comment from the posthog-bot mentioning visual review.

When the user asks for the rendered diff image itself, the VR web UI is faster — direct them there. This skill is for everything around the diff: status, scope, history, triage.

Tools

Read tools (safe to call freely):

ToolPurpose
posthog:visual-review-runs-listList runs, filter by pr_number / commit_sha / branch / review_state. Start here.
posthog:visual-review-runs-retrieveFull detail for a single run (status, summary counts, supersession).
posthog:visual-review-runs-snapshots-listPer-snapshot results inside a run: identifier, result, diff %, classification, baseline + current artifact URLs. Quarantined snapshots are excluded by default (see quarantined_count); pass include_quarantined=true to see them.
posthog:visual-review-runs-snapshot-history-listA single story's last N runs across master/PRs — the flake check.
posthog:visual-review-runs-counts-retrieveAggregate counts for queue triage (how many runs in needs_review, etc.).
posthog:visual-review-runs-tolerated-hashes-listHashes the team has explicitly accepted as "known flake / acceptable variation".
posthog:visual-review-repos-listRepos (one per GitHub repo) — usually only one matters; useful for filtering.
posthog:visual-review-repos-retrieveRepo metadata: baseline file paths, PR-comment configuration.

Triage tools (reversible, DB-only — they record a review decision but do NOT change the baseline or the gate):

ToolPurpose
posthog:visual-review-runs-approve-createMark changed / new snapshots reviewed (approved) in the DB. Does NOT commit or green the gate — ship via finalize.
posthog:visual-review-runs-tolerate-createMark a single changed snapshot as a known tolerated alternate. Does NOT change the baseline — use for benign variants.

Ship tool (irreversible, outward-facing — requires explicit per-run human confirmation; see the gate):

ToolPurpose
posthog:visual-review-runs-finalize-createCommit the approved baseline to the PR branch and green the GitHub visual-review check. This ships the change.

Mark-reviewed call shape (approve-create):

  • id (required) — the run UUID. It's the route parameter, so the call fails without it.
  • snapshots: [{identifier, new_hash}] — new_hash is the content_hash of each snapshot's current_artifact. This only records the review in the DB; nothing is committed and the gate stays red until you finalize.

Toleration call shape — both fields are required:

  • id (required) — the run UUID. It's the route parameter, so the call fails without it.
  • snapshot_id (required) — the UUID of the individual snapshot to tolerate (from visual-review-runs-snapshots-list). This identifies which snapshot inside the run; it does not replace the run id.

Finalize call shape (finalize-create) — the all-or-nothing ship action:

  • id (required) — the run UUID.
  • approve_all: true — approve every still-pending changed/new snapshot before finalizing (tolerated ones are left alone). Use when you've verified every remaining diff is intended.
  • Omit approve_all (default false) to finalize a run you've already reviewed snapshot-by-snapshot. Finalize is all-or-nothing: it fails with 409 not_fully_resolved (and lists what's left) unless every changed/new snapshot is approved, tolerated, or quarantined.
  • It commits exactly the snapshots approved in the DB — tolerated snapshots keep their baseline and are never overwritten. When a baseline commit is pushed, its SHA comes back on the run's metadata.baseline_commit_sha. It's absent when nothing needed committing (everything resolved by toleration/quarantine — the gate still greens) or when the commit was skipped: no PR, or a 409 sha_mismatch because the PR has newer commits (that one leaves the gate red — re-run CI on the latest commit and finalize again).

If finalize fails with 409 stale_run, the run has been superseded — visual-review-runs-list { pr_number } and finalize the newest one. A successful finalize often kicks off a fresh CI run, which is normal.

The finalize gate

Finalize is the one irreversible, outward-facing action in this skill: it rewrites the baseline committed to the PR and greens the merge gate. Treat it like pushing to someone's branch — never automatic.

Before any finalize-create call, all of these must hold:

  1. You verified the diffs. You pulled the current (and, for changed, baseline) PNGs and looked at them, ran the flake check on anything suspect, and reached a per-snapshot verdict. Metadata alone is never enough.
  2. You presented the verdict and waited. Show the user, per snapshot, what changed and your recommendation, then stop.
  3. The user explicitly approved this run. A broad "get the gate green" / "fix the PR" is permission to investigate and recommend — NOT to finalize. When the task implies finalizing but the human hasn't said it for this specific run, ask.

approve-create and tolerate-create are reversible triage and don't need this gate — but they don't ship anything either. The moment you're about to finalize-create and can't point to a specific human "yes" for this run, stop and ask.

Vocabulary cheat sheet

These appear in tool output and matter for interpretation:

  • Run review_state: needs_review (open, awaiting human), clean (zero diffs), processing (CI still uploading), stale (a newer run on the same PR has superseded this one — check superseded_by_id).
  • Run run_type: storybook (component snapshots) or playwright (full-page e2e snapshots).
  • Snapshot result: unchanged, changed (real diff), new (no baseline yet), removed.
  • Snapshot classification_reason: tolerated_hash (matches a known-tolerated hash, no action needed), below_threshold (under the noise floor), exact (byte-identical), "" (real diff requiring review).
  • Snapshot review_state: pending or approved.
  • Run summary: total / changed / new / removed / unchanged / unresolved / tolerated_matched — unresolved is what's actually blocking review.

Workflows

"What's the VR status of this PR?"

The single most common job. Map a PR number to its run state in two calls.

  1. posthog:visual-review-runs-list { pr_number: <n>, limit: 5 } — sort by created_at desc, take the latest non-stale one.
  2. If the run has summary.changed > 0 or summary.unresolved > 0, drill in: posthog:visual-review-runs-snapshots-list { id: <run_id> } and report the changed snapshots.

Report back: PR number, run UUID, review_state, summary counts, and the _posthogUrl deep link so the user can click straight to the diff viewer.

"Is the diff real or unrelated?"

The most useful judgment a code-aware agent can add. Combine three signals: scope match, flake history, and the actual rendered images. The agent should look at the screenshots — not just describe metadata.

  1. Scope check — git diff master...HEAD --stat (or against the PR's base branch) → list of touched paths. Cross-reference with posthog:visual-review-runs-snapshots-list { id } filtered to result: changed → story identifiers. Stories are namespaced like <area>-<scene>--<story>--<theme>; e.g. scenes-app-settings-user--settings-user-profile--dark maps to frontend/src/scenes/settings/user/.... Use this to translate story id → likely source path.

  2. Visual inspection — for each changed snapshot, the tool result contains current_artifact.download_url and baseline_artifact.download_url. These are pre-signed S3 URLs to PNG files; pull them and look:

    bash
    curl -s -o /tmp/vr-baseline.png "<baseline_artifact.download_url>"curl -s -o /tmp/vr-current.png "<current_artifact.download_url>"

    Then Read both files (the Read tool renders images visually) and compare. Things to call out:

    • The actual visible delta (text changed, button moved, layout shift, color drift, missing element).
    • Whether the change is consistent with the diff_pixel_count and diff_percentage in the metadata (e.g. 54% diff but the images look near-identical → screenshot framing changed, not the UI).
    • Whether the baseline and current have different dimensions (width / height fields). Mismatched dimensions usually mean the story rendered to a different viewport or didn't fully render before screenshot — a flake signal, not a regression.
  3. Flake history — run the flake check below for any story that looks suspect.

  4. Verdict — combine all three:

    • Scope plausible + visible regression matches the code change → real diff, recommend approval.
    • Scope mismatch + dimensions mismatch + frequent prior changes → flake, recommend tolerating the hash.
    • Scope plausible + visible regression looks unintended → push a fix; do not approve.

Always include a one-line description of what you saw in the images — the user uses this to decide whether to trust your verdict without opening the VR UI themselves.

Flake check: "Has this story been changing?"

Once you have a suspect snapshot identifier:

posthog:visual-review-runs-snapshot-history-list { id: <snapshot_id> } → returns prior outcomes for the same story.

Verdicts:

  • Mostly unchanged and this run's diff is the outlier → likely a real regression caused by this PR.
  • Frequent changed across unrelated branches/master → flaky story; recommend tolerating the hash via the UI.
  • Recent removed or large-jump dimension change → baseline likely stale; recommend re-baselining on master.

Triaging the queue

When the user is doing housekeeping rather than asking about a specific PR:

  1. posthog:visual-review-runs-counts-retrieve → total queue size.
  2. posthog:visual-review-runs-list { review_state: needs_review, limit: 50 } (paginate if needed).
  3. Group by branch author or run_type to surface clusters (e.g., "12 PRs blocked on the same shared component change" usually means a single underlying root cause to address).
  4. Prefer surfacing runs whose summary.changed > 0 over runs that are only new — new means no baseline yet, which is usually trivial to approve; changed is the real review work.

Output expectations

For PR-status questions, lead with the verdict in one line, then 2-4 bullets of supporting context. Always include the _posthogUrl deep link to the run — humans need to see the rendered images to make the call, the agent can only describe the metadata.

For triage / aggregate questions, a short table beats prose. Group by what the user is going to act on.

What NOT to do

  • Do not approve or tolerate without explicit user confirmation. The verdict is yours to recommend; the decision to ship belongs to the user. Once they say "approve those" / "tolerate that", call the tool.
  • Do not assume the failing GitHub check on a PR is unrelated to VR — if a visual-review check is red on a PR you're working on, that's the trigger to run this skill.
  • Do not declare a verdict from metadata alone when result: changed. Pull the baseline and current PNGs and look at them; metadata can only say "something changed", not whether the change is intended.

Source and attribution

Source:PostHog/ai-plugininskills/triaging-visual-review-runsat commit469d177

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal

More from PostHog/ai-plugin

Writing Simplified Technical English

PostHog

Applies ASD-STE100 simplified technical English rules to make agent-written prose unambiguous and actionable.

Writing & ContentOct 8, 2026

Working With Task Comments

PostHog

Reads and interprets comments on PostHog tasks, artifacts, and canvases through the PostHog MCP exec dispatcher.

Productivity & WorkflowOct 8, 2026

Working With Skills

PostHog

Guides agents in using PostHog's skill-* MCP tools to discover, read, create, update, and refactor skills.

AI & AgentsOct 8, 2026

Working With Scouts

PostHog

Operating manual for delegating watching jobs to PostHog Signals scouts, acting on their reports, and steering the fleet over time.

AI & AgentsOct 8, 2026

Validating And Publishing Canvases

PostHog

Validate and publish a canvas source project safely: the source-project shape, declared capabilities, reading the current version pointer, iterating on validation diagnostics, guarded publishing with expected_current_version_id, staging a draft build and promoting it, waiting out the queued build, and recovering from a 409 version_conflict or a 429 capacity limit without overwriting concurrent work. Use whenever a canvas edit is ready to save, a draft build is wanted, a canvas publish or build returns diagnostics or a conflict, or a task needs to understand canvas version history.

Awaiting classificationOct 8, 2026

Understanding Billing Usage

PostHog

Explains PostHog billing usage and spend from the customer's visible Billing MCP tools. Use when the user asks why usage or spend is high, which product or project is driving usage, what a usage type means, how to reduce usage, what changed over time, why they got a usage change alert, or whether a spike/drop alert was real or noisy. Also use before product-specific analytics skills when the user names a billable PostHog product metric such as events, recordings, feature flag requests, exceptions, survey responses, synced rows, logs, AI events, AI credits, or Inbox credits. Starts from Billing usage/spend tools, then routes to customer-visible product MCP surfaces for deeper investigation.

Awaiting classificationOct 8, 2026