[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-posthog-triaging-visual-review-runs":3,"mdc--uqg924-key":52,"related-repo-posthog-triaging-visual-review-runs":1809,"related-org-posthog-triaging-visual-review-runs":1913},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":26,"repoUrl":27,"updatedAt":28,"license":29,"forks":30,"topics":31,"repo":47,"sourceUrl":50,"mdContent":51},"triaging-visual-review-runs","triage PostHog visual regression tests","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.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"posthog","PostHog","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fposthog.png",[12,14,17,20,23],{"name":9,"slug":8,"type":13},"tag",{"name":15,"slug":16,"type":13},"Triage","triage",{"name":18,"slug":19,"type":13},"Testing","testing",{"name":21,"slug":22,"type":13},"Frontend","frontend",{"name":24,"slug":25,"type":13},"Design","design",35568,"https:\u002F\u002Fgithub.com\u002FPostHog\u002Fposthog","2026-05-01T06:05:20.257703",null,2977,[32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"ab-testing","ai-analytics","analytics","cdp","data-warehouse","experiments","feature-flags","javascript","product-analytics","python","react","session-replay","surveys","typescript","web-analytics",{"repoUrl":27,"stars":26,"forks":30,"topics":48,"description":49},[32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"🦔 PostHog is an all-in-one developer platform for building successful products. We offer product analytics, web analytics, session replay, error tracking, feature flags, experimentation, surveys, data warehouse, a CDP, and an AI product assistant to help debug your code, ship features faster, and keep all your usage and customer data in one stack.","https:\u002F\u002Fgithub.com\u002FPostHog\u002Fposthog\u002Ftree\u002FHEAD\u002Fproducts\u002Fvisual_review\u002Fskills\u002Ftriaging-visual-review-runs","---\nname: triaging-visual-review-runs\ndescription: >\n  Inspects PostHog Visual Review (VR) runs that gate PR merges with screenshot regression checks.\n  Use when the user mentions \"visual review\", \"VR\", \"snapshot diff\", \"screenshot test\", \"storybook regression\",\n  \"playwright snapshot\", asks why a PR is blocked or what changed visually, wants to triage the VR backlog,\n  decide whether a snapshot diff is real vs flaky, or check whether a story has been changing across runs.\n  Also invoke when a PR has a failing `visual-review` status check, when a PR comment mentions \"Visual review\",\n  or when the user is on a branch with an open VR run.\n---\n\n# Triaging visual review runs\n\nVisual Review is PostHog's screenshot-regression product: CI captures storybook + playwright screenshots,\ndiffs them against committed baseline hashes, and gates the PR until a human approves the visible changes.\nA PR with visual changes carries a `visual-review` GitHub status check that stays red until each diffed\nsnapshot is approved or tolerated in the [VR UI](https:\u002F\u002Fus.posthog.com\u002Fproject\u002F2\u002Fvisual_review).\n\nThis skill teaches an agent how to answer the questions a human reviewer would actually ask, by chaining\nthe VR MCP tools — instead of reaching for `gh pr view` and tab-hopping to the VR web UI. The read tools\ncover status \u002F scope \u002F history \u002F triage. Two are reversible DB-only triage marks (`approve-create`,\n`tolerate-create`); one ships the change (`finalize-create`) — it commits the baseline and greens the gate,\nand only that one needs explicit per-run human confirmation.\n\n## When this skill applies\n\nTrigger this skill on any of:\n\n- A PR number, branch name, or commit SHA paired with words like _visual review_, _VR_, _snapshot_, _screenshot_,\n  _storybook diff_, _playwright snapshot_, _baseline_, _approve_, _tolerated_, _quarantine_.\n- Questions about why a PR is blocked, what visually changed, or whether a diff is real.\n- \"Is my run done?\" \u002F \"What's left to review?\" \u002F \"Has this story flaked recently?\"\n- A failing `visual-review` GitHub check or a PR comment from the `posthog-bot` mentioning visual review.\n\nWhen the user asks for the rendered diff image itself, the [VR web UI](https:\u002F\u002Fus.posthog.com\u002Fproject\u002F2\u002Fvisual_review)\nis faster — direct them there. This skill is for everything around the diff: status, scope, history, triage.\n\n## Tools\n\nRead tools (safe to call freely):\n\n| Tool                                               | Purpose                                                                                                                                                                                                                                  |\n| -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `posthog:visual-review-runs-list`                  | List runs, filter by `pr_number` \u002F `commit_sha` \u002F `branch` \u002F `review_state`. Start here.                                                                                                                                                 |\n| `posthog:visual-review-runs-retrieve`              | Full detail for a single run (status, summary counts, supersession).                                                                                                                                                                     |\n| `posthog:visual-review-runs-snapshots-list`        | Per-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. |\n| `posthog:visual-review-runs-snapshot-history-list` | A single story's last N runs across master\u002FPRs — the flake check.                                                                                                                                                                        |\n| `posthog:visual-review-runs-counts-retrieve`       | Aggregate counts for queue triage (how many runs in `needs_review`, etc.).                                                                                                                                                               |\n| `posthog:visual-review-runs-tolerated-hashes-list` | Hashes the team has explicitly accepted as \"known flake \u002F acceptable variation\".                                                                                                                                                         |\n| `posthog:visual-review-repos-list`                 | Repos (one per GitHub repo) — usually only one matters; useful for filtering.                                                                                                                                                            |\n| `posthog:visual-review-repos-retrieve`             | Repo metadata: baseline file paths, PR-comment configuration.                                                                                                                                                                            |\n\nTriage tools (reversible, DB-only — they record a review decision but do NOT change the baseline or the gate):\n\n| Tool                                         | Purpose                                                                                                                |\n| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |\n| `posthog:visual-review-runs-approve-create`  | Mark `changed` \u002F `new` snapshots reviewed (approved) in the DB. Does NOT commit or green the gate — ship via finalize. |\n| `posthog:visual-review-runs-tolerate-create` | Mark a single changed snapshot as a known tolerated alternate. Does NOT change the baseline — use for benign variants. |\n\nShip tool (irreversible, outward-facing — requires explicit per-run human confirmation; see [the gate](#the-finalize-gate)):\n\n| Tool                                         | Purpose                                                                                                          |\n| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |\n| `posthog:visual-review-runs-finalize-create` | Commit the approved baseline to the PR branch and green the GitHub `visual-review` check. This ships the change. |\n\nMark-reviewed call shape (`approve-create`):\n\n- `id` (required) — the run UUID. It's the route parameter, so the call fails without it.\n- `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.\n\nToleration call shape — both fields are required:\n\n- `id` (required) — the run UUID. It's the route parameter, so the call fails without it.\n- `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`.\n\nFinalize call shape (`finalize-create`) — the all-or-nothing ship action:\n\n- `id` (required) — the run UUID.\n- `approve_all: true` — approve every still-pending `changed`\u002F`new` snapshot before finalizing (tolerated ones are left alone). Use when you've verified every remaining diff is intended.\n- 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\u002Fnew snapshot is approved, tolerated, or quarantined.\n- 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\u002Fquarantine — 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).\n\nIf 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.\n\n### The finalize gate\n\nFinalize is the one irreversible, outward-facing action in this skill: it rewrites the baseline committed to the\nPR and greens the merge gate. Treat it like pushing to someone's branch — never automatic.\n\nBefore _any_ `finalize-create` call, all of these must hold:\n\n1. **You verified the diffs.** You pulled the current (and, for `changed`, baseline) PNGs and looked at them, ran\n   the flake check on anything suspect, and reached a per-snapshot verdict. Metadata alone is never enough.\n2. **You presented the verdict and waited.** Show the user, per snapshot, what changed and your recommendation, then stop.\n3. **The user explicitly approved _this_ run.** A broad \"get the gate green\" \u002F \"fix the PR\" is permission to\n   investigate and recommend — NOT to finalize. When the task implies finalizing but the human hasn't said it for\n   this specific run, ask.\n\n`approve-create` and `tolerate-create` are reversible triage and don't need this gate — but they don't ship anything\neither. The moment you're about to `finalize-create` and can't point to a specific human \"yes\" for this run, stop and ask.\n\n## Vocabulary cheat sheet\n\nThese appear in tool output and matter for interpretation:\n\n- **Run `review_state`**: `needs_review` (open, awaiting human), `clean` (zero diffs), `processing` (CI still uploading),\n  `stale` (a newer run on the same PR has superseded this one — check `superseded_by_id`).\n- **Run `run_type`**: `storybook` (component snapshots) or `playwright` (full-page e2e snapshots).\n- **Snapshot `result`**: `unchanged`, `changed` (real diff), `new` (no baseline yet), `removed`.\n- **Snapshot `classification_reason`**: `tolerated_hash` (matches a known-tolerated hash, no action needed),\n  `below_threshold` (under the noise floor), `exact` (byte-identical), `\"\"` (real diff requiring review).\n- **Snapshot `review_state`**: `pending` or `approved`.\n- **Run `summary`**: `total \u002F changed \u002F new \u002F removed \u002F unchanged \u002F unresolved \u002F tolerated_matched` —\n  `unresolved` is what's actually blocking review.\n\n## Workflows\n\n### \"What's the VR status of this PR?\"\n\nThe single most common job. Map a PR number to its run state in two calls.\n\n1. `posthog:visual-review-runs-list { pr_number: \u003Cn>, limit: 5 }` — sort by `created_at` desc, take the latest non-stale one.\n2. If the run has `summary.changed > 0` or `summary.unresolved > 0`, drill in:\n   `posthog:visual-review-runs-snapshots-list { id: \u003Crun_id> }` and report the `changed` snapshots.\n\nReport back: PR number, run UUID, `review_state`, summary counts, and the `_posthogUrl` deep link so the\nuser can click straight to the diff viewer.\n\n### \"Is the diff real or unrelated?\"\n\nThe most useful judgment a code-aware agent can add. Combine three signals: **scope match**, **flake history**,\nand **the actual rendered images**. The agent should look at the screenshots — not just describe metadata.\n\n1. **Scope check** — `git diff master...HEAD --stat` (or against the PR's base branch) → list of touched paths.\n   Cross-reference with `posthog:visual-review-runs-snapshots-list { id }` filtered to `result: changed` → story identifiers.\n   Stories are namespaced like `\u003Carea>-\u003Cscene>--\u003Cstory>--\u003Ctheme>`; e.g. `scenes-app-settings-user--settings-user-profile--dark`\n   maps to `frontend\u002Fsrc\u002Fscenes\u002Fsettings\u002Fuser\u002F...`. Use this to translate story id → likely source path.\n\n2. **Visual inspection** — for each `changed` snapshot, the tool result contains `current_artifact.download_url`\n   and `baseline_artifact.download_url`. These are pre-signed S3 URLs to PNG files; pull them and look:\n\n   ```bash\n   curl -s -o \u002Ftmp\u002Fvr-baseline.png \"\u003Cbaseline_artifact.download_url>\"\n   curl -s -o \u002Ftmp\u002Fvr-current.png \"\u003Ccurrent_artifact.download_url>\"\n   ```\n\n   Then `Read` both files (the Read tool renders images visually) and compare. Things to call out:\n   - The actual visible delta (text changed, button moved, layout shift, color drift, missing element).\n   - Whether the change is consistent with the diff_pixel_count and diff_percentage in the metadata\n     (e.g. 54% diff but the images look near-identical → screenshot framing changed, not the UI).\n   - Whether the baseline and current have different dimensions (`width` \u002F `height` fields). Mismatched\n     dimensions usually mean the story rendered to a different viewport or didn't fully render before\n     screenshot — a flake signal, not a regression.\n\n3. **Flake history** — run the flake check below for any story that looks suspect.\n\n4. **Verdict** — combine all three:\n   - Scope plausible + visible regression matches the code change → real diff, recommend approval.\n   - Scope mismatch + dimensions mismatch + frequent prior changes → flake, recommend tolerating the hash.\n   - Scope plausible + visible regression looks unintended → push a fix; do not approve.\n\nAlways include a one-line description of what you saw in the images — the user uses this to decide whether to\ntrust your verdict without opening the VR UI themselves.\n\n### Flake check: \"Has this story been changing?\"\n\nOnce you have a suspect snapshot identifier:\n\n`posthog:visual-review-runs-snapshot-history-list { id: \u003Csnapshot_id> }` → returns prior outcomes for the same story.\n\nVerdicts:\n\n- Mostly `unchanged` and this run's diff is the outlier → likely a real regression caused by this PR.\n- Frequent `changed` across unrelated branches\u002Fmaster → flaky story; recommend tolerating the hash via the UI.\n- Recent `removed` or large-jump dimension change → baseline likely stale; recommend re-baselining on master.\n\n### Triaging the queue\n\nWhen the user is doing housekeeping rather than asking about a specific PR:\n\n1. `posthog:visual-review-runs-counts-retrieve` → total queue size.\n2. `posthog:visual-review-runs-list { review_state: needs_review, limit: 50 }` (paginate if needed).\n3. Group by `branch` author or `run_type` to surface clusters (e.g., \"12 PRs blocked on the same shared\n   component change\" usually means a single underlying root cause to address).\n4. Prefer surfacing runs whose `summary.changed > 0` over runs that are only `new` — `new` means no baseline\n   yet, which is usually trivial to approve; `changed` is the real review work.\n\n## Output expectations\n\nFor PR-status questions, lead with the verdict in one line, then 2-4 bullets of supporting context. Always\ninclude the `_posthogUrl` deep link to the run — humans need to see the rendered images to make the call,\nthe agent can only describe the metadata.\n\nFor triage \u002F aggregate questions, a short table beats prose. Group by what the user is going to act on.\n\n## What NOT to do\n\n- Do not approve or tolerate without explicit user confirmation. The verdict is yours to recommend; the\n  decision to ship belongs to the user. Once they say \"approve those\" \u002F \"tolerate that\", call the tool.\n- Do not assume the failing GitHub check on a PR is unrelated to VR — if a `visual-review` check is red on\n  a PR you're working on, that's the trigger to run this skill.\n- Do not declare a verdict from metadata alone when `result: changed`. Pull the baseline and current PNGs\n  and look at them; metadata can only say \"something changed\", not whether the change is intended.\n",{"data":53,"body":54},{"name":4,"description":6},{"type":55,"children":56},"root",[57,65,91,128,135,140,242,255,261,266,492,497,566,579,623,634,683,688,732,744,824,845,852,857,876,925,949,955,960,1193,1199,1205,1210,1267,1287,1293,1318,1585,1590,1596,1601,1612,1617,1656,1662,1667,1742,1748,1760,1765,1771,1803],{"type":58,"tag":59,"props":60,"children":61},"element","h1",{"id":4},[62],{"type":63,"value":64},"text","Triaging visual review runs",{"type":58,"tag":66,"props":67,"children":68},"p",{},[69,71,78,80,89],{"type":63,"value":70},"Visual Review is PostHog's screenshot-regression product: CI captures storybook + playwright screenshots,\ndiffs them against committed baseline hashes, and gates the PR until a human approves the visible changes.\nA PR with visual changes carries a ",{"type":58,"tag":72,"props":73,"children":75},"code",{"className":74},[],[76],{"type":63,"value":77},"visual-review",{"type":63,"value":79}," GitHub status check that stays red until each diffed\nsnapshot is approved or tolerated in the ",{"type":58,"tag":81,"props":82,"children":86},"a",{"href":83,"rel":84},"https:\u002F\u002Fus.posthog.com\u002Fproject\u002F2\u002Fvisual_review",[85],"nofollow",[87],{"type":63,"value":88},"VR UI",{"type":63,"value":90},".",{"type":58,"tag":66,"props":92,"children":93},{},[94,96,102,104,110,112,118,120,126],{"type":63,"value":95},"This skill teaches an agent how to answer the questions a human reviewer would actually ask, by chaining\nthe VR MCP tools — instead of reaching for ",{"type":58,"tag":72,"props":97,"children":99},{"className":98},[],[100],{"type":63,"value":101},"gh pr view",{"type":63,"value":103}," and tab-hopping to the VR web UI. The read tools\ncover status \u002F scope \u002F history \u002F triage. Two are reversible DB-only triage marks (",{"type":58,"tag":72,"props":105,"children":107},{"className":106},[],[108],{"type":63,"value":109},"approve-create",{"type":63,"value":111},",\n",{"type":58,"tag":72,"props":113,"children":115},{"className":114},[],[116],{"type":63,"value":117},"tolerate-create",{"type":63,"value":119},"); one ships the change (",{"type":58,"tag":72,"props":121,"children":123},{"className":122},[],[124],{"type":63,"value":125},"finalize-create",{"type":63,"value":127},") — it commits the baseline and greens the gate,\nand only that one needs explicit per-run human confirmation.",{"type":58,"tag":129,"props":130,"children":132},"h2",{"id":131},"when-this-skill-applies",[133],{"type":63,"value":134},"When this skill applies",{"type":58,"tag":66,"props":136,"children":137},{},[138],{"type":63,"value":139},"Trigger this skill on any of:",{"type":58,"tag":141,"props":142,"children":143},"ul",{},[144,212,217,222],{"type":58,"tag":145,"props":146,"children":147},"li",{},[148,150,156,158,163,164,169,170,175,176,181,182,187,188,193,194,199,200,205,206,211],{"type":63,"value":149},"A PR number, branch name, or commit SHA paired with words like ",{"type":58,"tag":151,"props":152,"children":153},"em",{},[154],{"type":63,"value":155},"visual review",{"type":63,"value":157},", ",{"type":58,"tag":151,"props":159,"children":160},{},[161],{"type":63,"value":162},"VR",{"type":63,"value":157},{"type":58,"tag":151,"props":165,"children":166},{},[167],{"type":63,"value":168},"snapshot",{"type":63,"value":157},{"type":58,"tag":151,"props":171,"children":172},{},[173],{"type":63,"value":174},"screenshot",{"type":63,"value":111},{"type":58,"tag":151,"props":177,"children":178},{},[179],{"type":63,"value":180},"storybook diff",{"type":63,"value":157},{"type":58,"tag":151,"props":183,"children":184},{},[185],{"type":63,"value":186},"playwright snapshot",{"type":63,"value":157},{"type":58,"tag":151,"props":189,"children":190},{},[191],{"type":63,"value":192},"baseline",{"type":63,"value":157},{"type":58,"tag":151,"props":195,"children":196},{},[197],{"type":63,"value":198},"approve",{"type":63,"value":157},{"type":58,"tag":151,"props":201,"children":202},{},[203],{"type":63,"value":204},"tolerated",{"type":63,"value":157},{"type":58,"tag":151,"props":207,"children":208},{},[209],{"type":63,"value":210},"quarantine",{"type":63,"value":90},{"type":58,"tag":145,"props":213,"children":214},{},[215],{"type":63,"value":216},"Questions about why a PR is blocked, what visually changed, or whether a diff is real.",{"type":58,"tag":145,"props":218,"children":219},{},[220],{"type":63,"value":221},"\"Is my run done?\" \u002F \"What's left to review?\" \u002F \"Has this story flaked recently?\"",{"type":58,"tag":145,"props":223,"children":224},{},[225,227,232,234,240],{"type":63,"value":226},"A failing ",{"type":58,"tag":72,"props":228,"children":230},{"className":229},[],[231],{"type":63,"value":77},{"type":63,"value":233}," GitHub check or a PR comment from the ",{"type":58,"tag":72,"props":235,"children":237},{"className":236},[],[238],{"type":63,"value":239},"posthog-bot",{"type":63,"value":241}," mentioning visual review.",{"type":58,"tag":66,"props":243,"children":244},{},[245,247,253],{"type":63,"value":246},"When the user asks for the rendered diff image itself, the ",{"type":58,"tag":81,"props":248,"children":250},{"href":83,"rel":249},[85],[251],{"type":63,"value":252},"VR web UI",{"type":63,"value":254},"\nis faster — direct them there. This skill is for everything around the diff: status, scope, history, triage.",{"type":58,"tag":129,"props":256,"children":258},{"id":257},"tools",[259],{"type":63,"value":260},"Tools",{"type":58,"tag":66,"props":262,"children":263},{},[264],{"type":63,"value":265},"Read tools (safe to call freely):",{"type":58,"tag":267,"props":268,"children":269},"table",{},[270,289],{"type":58,"tag":271,"props":272,"children":273},"thead",{},[274],{"type":58,"tag":275,"props":276,"children":277},"tr",{},[278,284],{"type":58,"tag":279,"props":280,"children":281},"th",{},[282],{"type":63,"value":283},"Tool",{"type":58,"tag":279,"props":285,"children":286},{},[287],{"type":63,"value":288},"Purpose",{"type":58,"tag":290,"props":291,"children":292},"tbody",{},[293,341,358,399,416,441,458,475],{"type":58,"tag":275,"props":294,"children":295},{},[296,306],{"type":58,"tag":297,"props":298,"children":299},"td",{},[300],{"type":58,"tag":72,"props":301,"children":303},{"className":302},[],[304],{"type":63,"value":305},"posthog:visual-review-runs-list",{"type":58,"tag":297,"props":307,"children":308},{},[309,311,317,319,325,326,332,333,339],{"type":63,"value":310},"List runs, filter by ",{"type":58,"tag":72,"props":312,"children":314},{"className":313},[],[315],{"type":63,"value":316},"pr_number",{"type":63,"value":318}," \u002F ",{"type":58,"tag":72,"props":320,"children":322},{"className":321},[],[323],{"type":63,"value":324},"commit_sha",{"type":63,"value":318},{"type":58,"tag":72,"props":327,"children":329},{"className":328},[],[330],{"type":63,"value":331},"branch",{"type":63,"value":318},{"type":58,"tag":72,"props":334,"children":336},{"className":335},[],[337],{"type":63,"value":338},"review_state",{"type":63,"value":340},". Start here.",{"type":58,"tag":275,"props":342,"children":343},{},[344,353],{"type":58,"tag":297,"props":345,"children":346},{},[347],{"type":58,"tag":72,"props":348,"children":350},{"className":349},[],[351],{"type":63,"value":352},"posthog:visual-review-runs-retrieve",{"type":58,"tag":297,"props":354,"children":355},{},[356],{"type":63,"value":357},"Full detail for a single run (status, summary counts, supersession).",{"type":58,"tag":275,"props":359,"children":360},{},[361,370],{"type":58,"tag":297,"props":362,"children":363},{},[364],{"type":58,"tag":72,"props":365,"children":367},{"className":366},[],[368],{"type":63,"value":369},"posthog:visual-review-runs-snapshots-list",{"type":58,"tag":297,"props":371,"children":372},{},[373,375,381,383,389,391,397],{"type":63,"value":374},"Per-snapshot results inside a run: identifier, ",{"type":58,"tag":72,"props":376,"children":378},{"className":377},[],[379],{"type":63,"value":380},"result",{"type":63,"value":382},", diff %, classification, baseline + current artifact URLs. Quarantined snapshots are excluded by default (see ",{"type":58,"tag":72,"props":384,"children":386},{"className":385},[],[387],{"type":63,"value":388},"quarantined_count",{"type":63,"value":390},"); pass ",{"type":58,"tag":72,"props":392,"children":394},{"className":393},[],[395],{"type":63,"value":396},"include_quarantined=true",{"type":63,"value":398}," to see them.",{"type":58,"tag":275,"props":400,"children":401},{},[402,411],{"type":58,"tag":297,"props":403,"children":404},{},[405],{"type":58,"tag":72,"props":406,"children":408},{"className":407},[],[409],{"type":63,"value":410},"posthog:visual-review-runs-snapshot-history-list",{"type":58,"tag":297,"props":412,"children":413},{},[414],{"type":63,"value":415},"A single story's last N runs across master\u002FPRs — the flake check.",{"type":58,"tag":275,"props":417,"children":418},{},[419,428],{"type":58,"tag":297,"props":420,"children":421},{},[422],{"type":58,"tag":72,"props":423,"children":425},{"className":424},[],[426],{"type":63,"value":427},"posthog:visual-review-runs-counts-retrieve",{"type":58,"tag":297,"props":429,"children":430},{},[431,433,439],{"type":63,"value":432},"Aggregate counts for queue triage (how many runs in ",{"type":58,"tag":72,"props":434,"children":436},{"className":435},[],[437],{"type":63,"value":438},"needs_review",{"type":63,"value":440},", etc.).",{"type":58,"tag":275,"props":442,"children":443},{},[444,453],{"type":58,"tag":297,"props":445,"children":446},{},[447],{"type":58,"tag":72,"props":448,"children":450},{"className":449},[],[451],{"type":63,"value":452},"posthog:visual-review-runs-tolerated-hashes-list",{"type":58,"tag":297,"props":454,"children":455},{},[456],{"type":63,"value":457},"Hashes the team has explicitly accepted as \"known flake \u002F acceptable variation\".",{"type":58,"tag":275,"props":459,"children":460},{},[461,470],{"type":58,"tag":297,"props":462,"children":463},{},[464],{"type":58,"tag":72,"props":465,"children":467},{"className":466},[],[468],{"type":63,"value":469},"posthog:visual-review-repos-list",{"type":58,"tag":297,"props":471,"children":472},{},[473],{"type":63,"value":474},"Repos (one per GitHub repo) — usually only one matters; useful for filtering.",{"type":58,"tag":275,"props":476,"children":477},{},[478,487],{"type":58,"tag":297,"props":479,"children":480},{},[481],{"type":58,"tag":72,"props":482,"children":484},{"className":483},[],[485],{"type":63,"value":486},"posthog:visual-review-repos-retrieve",{"type":58,"tag":297,"props":488,"children":489},{},[490],{"type":63,"value":491},"Repo metadata: baseline file paths, PR-comment configuration.",{"type":58,"tag":66,"props":493,"children":494},{},[495],{"type":63,"value":496},"Triage tools (reversible, DB-only — they record a review decision but do NOT change the baseline or the gate):",{"type":58,"tag":267,"props":498,"children":499},{},[500,514],{"type":58,"tag":271,"props":501,"children":502},{},[503],{"type":58,"tag":275,"props":504,"children":505},{},[506,510],{"type":58,"tag":279,"props":507,"children":508},{},[509],{"type":63,"value":283},{"type":58,"tag":279,"props":511,"children":512},{},[513],{"type":63,"value":288},{"type":58,"tag":290,"props":515,"children":516},{},[517,549],{"type":58,"tag":275,"props":518,"children":519},{},[520,529],{"type":58,"tag":297,"props":521,"children":522},{},[523],{"type":58,"tag":72,"props":524,"children":526},{"className":525},[],[527],{"type":63,"value":528},"posthog:visual-review-runs-approve-create",{"type":58,"tag":297,"props":530,"children":531},{},[532,534,540,541,547],{"type":63,"value":533},"Mark ",{"type":58,"tag":72,"props":535,"children":537},{"className":536},[],[538],{"type":63,"value":539},"changed",{"type":63,"value":318},{"type":58,"tag":72,"props":542,"children":544},{"className":543},[],[545],{"type":63,"value":546},"new",{"type":63,"value":548}," snapshots reviewed (approved) in the DB. Does NOT commit or green the gate — ship via finalize.",{"type":58,"tag":275,"props":550,"children":551},{},[552,561],{"type":58,"tag":297,"props":553,"children":554},{},[555],{"type":58,"tag":72,"props":556,"children":558},{"className":557},[],[559],{"type":63,"value":560},"posthog:visual-review-runs-tolerate-create",{"type":58,"tag":297,"props":562,"children":563},{},[564],{"type":63,"value":565},"Mark a single changed snapshot as a known tolerated alternate. Does NOT change the baseline — use for benign variants.",{"type":58,"tag":66,"props":567,"children":568},{},[569,571,577],{"type":63,"value":570},"Ship tool (irreversible, outward-facing — requires explicit per-run human confirmation; see ",{"type":58,"tag":81,"props":572,"children":574},{"href":573},"#the-finalize-gate",[575],{"type":63,"value":576},"the gate",{"type":63,"value":578},"):",{"type":58,"tag":267,"props":580,"children":581},{},[582,596],{"type":58,"tag":271,"props":583,"children":584},{},[585],{"type":58,"tag":275,"props":586,"children":587},{},[588,592],{"type":58,"tag":279,"props":589,"children":590},{},[591],{"type":63,"value":283},{"type":58,"tag":279,"props":593,"children":594},{},[595],{"type":63,"value":288},{"type":58,"tag":290,"props":597,"children":598},{},[599],{"type":58,"tag":275,"props":600,"children":601},{},[602,611],{"type":58,"tag":297,"props":603,"children":604},{},[605],{"type":58,"tag":72,"props":606,"children":608},{"className":607},[],[609],{"type":63,"value":610},"posthog:visual-review-runs-finalize-create",{"type":58,"tag":297,"props":612,"children":613},{},[614,616,621],{"type":63,"value":615},"Commit the approved baseline to the PR branch and green the GitHub ",{"type":58,"tag":72,"props":617,"children":619},{"className":618},[],[620],{"type":63,"value":77},{"type":63,"value":622}," check. This ships the change.",{"type":58,"tag":66,"props":624,"children":625},{},[626,628,633],{"type":63,"value":627},"Mark-reviewed call shape (",{"type":58,"tag":72,"props":629,"children":631},{"className":630},[],[632],{"type":63,"value":109},{"type":63,"value":578},{"type":58,"tag":141,"props":635,"children":636},{},[637,648],{"type":58,"tag":145,"props":638,"children":639},{},[640,646],{"type":58,"tag":72,"props":641,"children":643},{"className":642},[],[644],{"type":63,"value":645},"id",{"type":63,"value":647}," (required) — the run UUID. It's the route parameter, so the call fails without it.",{"type":58,"tag":145,"props":649,"children":650},{},[651,657,659,665,667,673,675,681],{"type":58,"tag":72,"props":652,"children":654},{"className":653},[],[655],{"type":63,"value":656},"snapshots: [{identifier, new_hash}]",{"type":63,"value":658}," — ",{"type":58,"tag":72,"props":660,"children":662},{"className":661},[],[663],{"type":63,"value":664},"new_hash",{"type":63,"value":666}," is the ",{"type":58,"tag":72,"props":668,"children":670},{"className":669},[],[671],{"type":63,"value":672},"content_hash",{"type":63,"value":674}," of each snapshot's ",{"type":58,"tag":72,"props":676,"children":678},{"className":677},[],[679],{"type":63,"value":680},"current_artifact",{"type":63,"value":682},". This only records the review in the DB; nothing is committed and the gate stays red until you finalize.",{"type":58,"tag":66,"props":684,"children":685},{},[686],{"type":63,"value":687},"Toleration call shape — both fields are required:",{"type":58,"tag":141,"props":689,"children":690},{},[691,700],{"type":58,"tag":145,"props":692,"children":693},{},[694,699],{"type":58,"tag":72,"props":695,"children":697},{"className":696},[],[698],{"type":63,"value":645},{"type":63,"value":647},{"type":58,"tag":145,"props":701,"children":702},{},[703,709,711,717,719,724,726,731],{"type":58,"tag":72,"props":704,"children":706},{"className":705},[],[707],{"type":63,"value":708},"snapshot_id",{"type":63,"value":710}," (required) — the UUID of the individual snapshot to tolerate (from ",{"type":58,"tag":72,"props":712,"children":714},{"className":713},[],[715],{"type":63,"value":716},"visual-review-runs-snapshots-list",{"type":63,"value":718},"). This identifies ",{"type":58,"tag":151,"props":720,"children":721},{},[722],{"type":63,"value":723},"which",{"type":63,"value":725}," snapshot inside the run; it does not replace the run ",{"type":58,"tag":72,"props":727,"children":729},{"className":728},[],[730],{"type":63,"value":645},{"type":63,"value":90},{"type":58,"tag":66,"props":733,"children":734},{},[735,737,742],{"type":63,"value":736},"Finalize call shape (",{"type":58,"tag":72,"props":738,"children":740},{"className":739},[],[741],{"type":63,"value":125},{"type":63,"value":743},") — the all-or-nothing ship action:",{"type":58,"tag":141,"props":745,"children":746},{},[747,757,782,803],{"type":58,"tag":145,"props":748,"children":749},{},[750,755],{"type":58,"tag":72,"props":751,"children":753},{"className":752},[],[754],{"type":63,"value":645},{"type":63,"value":756}," (required) — the run UUID.",{"type":58,"tag":145,"props":758,"children":759},{},[760,766,768,773,775,780],{"type":58,"tag":72,"props":761,"children":763},{"className":762},[],[764],{"type":63,"value":765},"approve_all: true",{"type":63,"value":767}," — approve every still-pending ",{"type":58,"tag":72,"props":769,"children":771},{"className":770},[],[772],{"type":63,"value":539},{"type":63,"value":774},"\u002F",{"type":58,"tag":72,"props":776,"children":778},{"className":777},[],[779],{"type":63,"value":546},{"type":63,"value":781}," snapshot before finalizing (tolerated ones are left alone). Use when you've verified every remaining diff is intended.",{"type":58,"tag":145,"props":783,"children":784},{},[785,787,793,795,801],{"type":63,"value":786},"Omit ",{"type":58,"tag":72,"props":788,"children":790},{"className":789},[],[791],{"type":63,"value":792},"approve_all",{"type":63,"value":794}," (default false) to finalize a run you've already reviewed snapshot-by-snapshot. Finalize is all-or-nothing: it fails with ",{"type":58,"tag":72,"props":796,"children":798},{"className":797},[],[799],{"type":63,"value":800},"409 not_fully_resolved",{"type":63,"value":802}," (and lists what's left) unless every changed\u002Fnew snapshot is approved, tolerated, or quarantined.",{"type":58,"tag":145,"props":804,"children":805},{},[806,808,814,816,822],{"type":63,"value":807},"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 ",{"type":58,"tag":72,"props":809,"children":811},{"className":810},[],[812],{"type":63,"value":813},"metadata.baseline_commit_sha",{"type":63,"value":815},". It's absent when nothing needed committing (everything resolved by toleration\u002Fquarantine — the gate still greens) or when the commit was skipped: no PR, or a ",{"type":58,"tag":72,"props":817,"children":819},{"className":818},[],[820],{"type":63,"value":821},"409 sha_mismatch",{"type":63,"value":823}," because the PR has newer commits (that one leaves the gate red — re-run CI on the latest commit and finalize again).",{"type":58,"tag":66,"props":825,"children":826},{},[827,829,835,837,843],{"type":63,"value":828},"If finalize fails with ",{"type":58,"tag":72,"props":830,"children":832},{"className":831},[],[833],{"type":63,"value":834},"409 stale_run",{"type":63,"value":836},", the run has been superseded — ",{"type":58,"tag":72,"props":838,"children":840},{"className":839},[],[841],{"type":63,"value":842},"visual-review-runs-list { pr_number }",{"type":63,"value":844}," and finalize the newest one. A successful finalize often kicks off a fresh CI run, which is normal.",{"type":58,"tag":846,"props":847,"children":849},"h3",{"id":848},"the-finalize-gate",[850],{"type":63,"value":851},"The finalize gate",{"type":58,"tag":66,"props":853,"children":854},{},[855],{"type":63,"value":856},"Finalize is the one irreversible, outward-facing action in this skill: it rewrites the baseline committed to the\nPR and greens the merge gate. Treat it like pushing to someone's branch — never automatic.",{"type":58,"tag":66,"props":858,"children":859},{},[860,862,867,869,874],{"type":63,"value":861},"Before ",{"type":58,"tag":151,"props":863,"children":864},{},[865],{"type":63,"value":866},"any",{"type":63,"value":868}," ",{"type":58,"tag":72,"props":870,"children":872},{"className":871},[],[873],{"type":63,"value":125},{"type":63,"value":875}," call, all of these must hold:",{"type":58,"tag":877,"props":878,"children":879},"ol",{},[880,898,908],{"type":58,"tag":145,"props":881,"children":882},{},[883,889,891,896],{"type":58,"tag":884,"props":885,"children":886},"strong",{},[887],{"type":63,"value":888},"You verified the diffs.",{"type":63,"value":890}," You pulled the current (and, for ",{"type":58,"tag":72,"props":892,"children":894},{"className":893},[],[895],{"type":63,"value":539},{"type":63,"value":897},", baseline) PNGs and looked at them, ran\nthe flake check on anything suspect, and reached a per-snapshot verdict. Metadata alone is never enough.",{"type":58,"tag":145,"props":899,"children":900},{},[901,906],{"type":58,"tag":884,"props":902,"children":903},{},[904],{"type":63,"value":905},"You presented the verdict and waited.",{"type":63,"value":907}," Show the user, per snapshot, what changed and your recommendation, then stop.",{"type":58,"tag":145,"props":909,"children":910},{},[911,923],{"type":58,"tag":884,"props":912,"children":913},{},[914,916,921],{"type":63,"value":915},"The user explicitly approved ",{"type":58,"tag":151,"props":917,"children":918},{},[919],{"type":63,"value":920},"this",{"type":63,"value":922}," run.",{"type":63,"value":924}," A broad \"get the gate green\" \u002F \"fix the PR\" is permission to\ninvestigate and recommend — NOT to finalize. When the task implies finalizing but the human hasn't said it for\nthis specific run, ask.",{"type":58,"tag":66,"props":926,"children":927},{},[928,933,935,940,942,947],{"type":58,"tag":72,"props":929,"children":931},{"className":930},[],[932],{"type":63,"value":109},{"type":63,"value":934}," and ",{"type":58,"tag":72,"props":936,"children":938},{"className":937},[],[939],{"type":63,"value":117},{"type":63,"value":941}," are reversible triage and don't need this gate — but they don't ship anything\neither. The moment you're about to ",{"type":58,"tag":72,"props":943,"children":945},{"className":944},[],[946],{"type":63,"value":125},{"type":63,"value":948}," and can't point to a specific human \"yes\" for this run, stop and ask.",{"type":58,"tag":129,"props":950,"children":952},{"id":951},"vocabulary-cheat-sheet",[953],{"type":63,"value":954},"Vocabulary cheat sheet",{"type":58,"tag":66,"props":956,"children":957},{},[958],{"type":63,"value":959},"These appear in tool output and matter for interpretation:",{"type":58,"tag":141,"props":961,"children":962},{},[963,1017,1047,1089,1135,1163],{"type":58,"tag":145,"props":964,"children":965},{},[966,976,978,983,985,991,993,999,1001,1007,1009,1015],{"type":58,"tag":884,"props":967,"children":968},{},[969,971],{"type":63,"value":970},"Run ",{"type":58,"tag":72,"props":972,"children":974},{"className":973},[],[975],{"type":63,"value":338},{"type":63,"value":977},": ",{"type":58,"tag":72,"props":979,"children":981},{"className":980},[],[982],{"type":63,"value":438},{"type":63,"value":984}," (open, awaiting human), ",{"type":58,"tag":72,"props":986,"children":988},{"className":987},[],[989],{"type":63,"value":990},"clean",{"type":63,"value":992}," (zero diffs), ",{"type":58,"tag":72,"props":994,"children":996},{"className":995},[],[997],{"type":63,"value":998},"processing",{"type":63,"value":1000}," (CI still uploading),\n",{"type":58,"tag":72,"props":1002,"children":1004},{"className":1003},[],[1005],{"type":63,"value":1006},"stale",{"type":63,"value":1008}," (a newer run on the same PR has superseded this one — check ",{"type":58,"tag":72,"props":1010,"children":1012},{"className":1011},[],[1013],{"type":63,"value":1014},"superseded_by_id",{"type":63,"value":1016},").",{"type":58,"tag":145,"props":1018,"children":1019},{},[1020,1030,1031,1037,1039,1045],{"type":58,"tag":884,"props":1021,"children":1022},{},[1023,1024],{"type":63,"value":970},{"type":58,"tag":72,"props":1025,"children":1027},{"className":1026},[],[1028],{"type":63,"value":1029},"run_type",{"type":63,"value":977},{"type":58,"tag":72,"props":1032,"children":1034},{"className":1033},[],[1035],{"type":63,"value":1036},"storybook",{"type":63,"value":1038}," (component snapshots) or ",{"type":58,"tag":72,"props":1040,"children":1042},{"className":1041},[],[1043],{"type":63,"value":1044},"playwright",{"type":63,"value":1046}," (full-page e2e snapshots).",{"type":58,"tag":145,"props":1048,"children":1049},{},[1050,1060,1061,1067,1068,1073,1075,1080,1082,1088],{"type":58,"tag":884,"props":1051,"children":1052},{},[1053,1055],{"type":63,"value":1054},"Snapshot ",{"type":58,"tag":72,"props":1056,"children":1058},{"className":1057},[],[1059],{"type":63,"value":380},{"type":63,"value":977},{"type":58,"tag":72,"props":1062,"children":1064},{"className":1063},[],[1065],{"type":63,"value":1066},"unchanged",{"type":63,"value":157},{"type":58,"tag":72,"props":1069,"children":1071},{"className":1070},[],[1072],{"type":63,"value":539},{"type":63,"value":1074}," (real diff), ",{"type":58,"tag":72,"props":1076,"children":1078},{"className":1077},[],[1079],{"type":63,"value":546},{"type":63,"value":1081}," (no baseline yet), ",{"type":58,"tag":72,"props":1083,"children":1085},{"className":1084},[],[1086],{"type":63,"value":1087},"removed",{"type":63,"value":90},{"type":58,"tag":145,"props":1090,"children":1091},{},[1092,1102,1103,1109,1111,1117,1119,1125,1127,1133],{"type":58,"tag":884,"props":1093,"children":1094},{},[1095,1096],{"type":63,"value":1054},{"type":58,"tag":72,"props":1097,"children":1099},{"className":1098},[],[1100],{"type":63,"value":1101},"classification_reason",{"type":63,"value":977},{"type":58,"tag":72,"props":1104,"children":1106},{"className":1105},[],[1107],{"type":63,"value":1108},"tolerated_hash",{"type":63,"value":1110}," (matches a known-tolerated hash, no action needed),\n",{"type":58,"tag":72,"props":1112,"children":1114},{"className":1113},[],[1115],{"type":63,"value":1116},"below_threshold",{"type":63,"value":1118}," (under the noise floor), ",{"type":58,"tag":72,"props":1120,"children":1122},{"className":1121},[],[1123],{"type":63,"value":1124},"exact",{"type":63,"value":1126}," (byte-identical), ",{"type":58,"tag":72,"props":1128,"children":1130},{"className":1129},[],[1131],{"type":63,"value":1132},"\"\"",{"type":63,"value":1134}," (real diff requiring review).",{"type":58,"tag":145,"props":1136,"children":1137},{},[1138,1147,1148,1154,1156,1162],{"type":58,"tag":884,"props":1139,"children":1140},{},[1141,1142],{"type":63,"value":1054},{"type":58,"tag":72,"props":1143,"children":1145},{"className":1144},[],[1146],{"type":63,"value":338},{"type":63,"value":977},{"type":58,"tag":72,"props":1149,"children":1151},{"className":1150},[],[1152],{"type":63,"value":1153},"pending",{"type":63,"value":1155}," or ",{"type":58,"tag":72,"props":1157,"children":1159},{"className":1158},[],[1160],{"type":63,"value":1161},"approved",{"type":63,"value":90},{"type":58,"tag":145,"props":1164,"children":1165},{},[1166,1176,1177,1183,1185,1191],{"type":58,"tag":884,"props":1167,"children":1168},{},[1169,1170],{"type":63,"value":970},{"type":58,"tag":72,"props":1171,"children":1173},{"className":1172},[],[1174],{"type":63,"value":1175},"summary",{"type":63,"value":977},{"type":58,"tag":72,"props":1178,"children":1180},{"className":1179},[],[1181],{"type":63,"value":1182},"total \u002F changed \u002F new \u002F removed \u002F unchanged \u002F unresolved \u002F tolerated_matched",{"type":63,"value":1184}," —\n",{"type":58,"tag":72,"props":1186,"children":1188},{"className":1187},[],[1189],{"type":63,"value":1190},"unresolved",{"type":63,"value":1192}," is what's actually blocking review.",{"type":58,"tag":129,"props":1194,"children":1196},{"id":1195},"workflows",[1197],{"type":63,"value":1198},"Workflows",{"type":58,"tag":846,"props":1200,"children":1202},{"id":1201},"whats-the-vr-status-of-this-pr",[1203],{"type":63,"value":1204},"\"What's the VR status of this PR?\"",{"type":58,"tag":66,"props":1206,"children":1207},{},[1208],{"type":63,"value":1209},"The single most common job. Map a PR number to its run state in two calls.",{"type":58,"tag":877,"props":1211,"children":1212},{},[1213,1232],{"type":58,"tag":145,"props":1214,"children":1215},{},[1216,1222,1224,1230],{"type":58,"tag":72,"props":1217,"children":1219},{"className":1218},[],[1220],{"type":63,"value":1221},"posthog:visual-review-runs-list { pr_number: \u003Cn>, limit: 5 }",{"type":63,"value":1223}," — sort by ",{"type":58,"tag":72,"props":1225,"children":1227},{"className":1226},[],[1228],{"type":63,"value":1229},"created_at",{"type":63,"value":1231}," desc, take the latest non-stale one.",{"type":58,"tag":145,"props":1233,"children":1234},{},[1235,1237,1243,1244,1250,1252,1258,1260,1265],{"type":63,"value":1236},"If the run has ",{"type":58,"tag":72,"props":1238,"children":1240},{"className":1239},[],[1241],{"type":63,"value":1242},"summary.changed > 0",{"type":63,"value":1155},{"type":58,"tag":72,"props":1245,"children":1247},{"className":1246},[],[1248],{"type":63,"value":1249},"summary.unresolved > 0",{"type":63,"value":1251},", drill in:\n",{"type":58,"tag":72,"props":1253,"children":1255},{"className":1254},[],[1256],{"type":63,"value":1257},"posthog:visual-review-runs-snapshots-list { id: \u003Crun_id> }",{"type":63,"value":1259}," and report the ",{"type":58,"tag":72,"props":1261,"children":1263},{"className":1262},[],[1264],{"type":63,"value":539},{"type":63,"value":1266}," snapshots.",{"type":58,"tag":66,"props":1268,"children":1269},{},[1270,1272,1277,1279,1285],{"type":63,"value":1271},"Report back: PR number, run UUID, ",{"type":58,"tag":72,"props":1273,"children":1275},{"className":1274},[],[1276],{"type":63,"value":338},{"type":63,"value":1278},", summary counts, and the ",{"type":58,"tag":72,"props":1280,"children":1282},{"className":1281},[],[1283],{"type":63,"value":1284},"_posthogUrl",{"type":63,"value":1286}," deep link so the\nuser can click straight to the diff viewer.",{"type":58,"tag":846,"props":1288,"children":1290},{"id":1289},"is-the-diff-real-or-unrelated",[1291],{"type":63,"value":1292},"\"Is the diff real or unrelated?\"",{"type":58,"tag":66,"props":1294,"children":1295},{},[1296,1298,1303,1304,1309,1311,1316],{"type":63,"value":1297},"The most useful judgment a code-aware agent can add. Combine three signals: ",{"type":58,"tag":884,"props":1299,"children":1300},{},[1301],{"type":63,"value":1302},"scope match",{"type":63,"value":157},{"type":58,"tag":884,"props":1305,"children":1306},{},[1307],{"type":63,"value":1308},"flake history",{"type":63,"value":1310},",\nand ",{"type":58,"tag":884,"props":1312,"children":1313},{},[1314],{"type":63,"value":1315},"the actual rendered images",{"type":63,"value":1317},". The agent should look at the screenshots — not just describe metadata.",{"type":58,"tag":877,"props":1319,"children":1320},{},[1321,1378,1547,1557],{"type":58,"tag":145,"props":1322,"children":1323},{},[1324,1329,1330,1336,1338,1344,1346,1352,1354,1360,1362,1368,1370,1376],{"type":58,"tag":884,"props":1325,"children":1326},{},[1327],{"type":63,"value":1328},"Scope check",{"type":63,"value":658},{"type":58,"tag":72,"props":1331,"children":1333},{"className":1332},[],[1334],{"type":63,"value":1335},"git diff master...HEAD --stat",{"type":63,"value":1337}," (or against the PR's base branch) → list of touched paths.\nCross-reference with ",{"type":58,"tag":72,"props":1339,"children":1341},{"className":1340},[],[1342],{"type":63,"value":1343},"posthog:visual-review-runs-snapshots-list { id }",{"type":63,"value":1345}," filtered to ",{"type":58,"tag":72,"props":1347,"children":1349},{"className":1348},[],[1350],{"type":63,"value":1351},"result: changed",{"type":63,"value":1353}," → story identifiers.\nStories are namespaced like ",{"type":58,"tag":72,"props":1355,"children":1357},{"className":1356},[],[1358],{"type":63,"value":1359},"\u003Carea>-\u003Cscene>--\u003Cstory>--\u003Ctheme>",{"type":63,"value":1361},"; e.g. ",{"type":58,"tag":72,"props":1363,"children":1365},{"className":1364},[],[1366],{"type":63,"value":1367},"scenes-app-settings-user--settings-user-profile--dark",{"type":63,"value":1369},"\nmaps to ",{"type":58,"tag":72,"props":1371,"children":1373},{"className":1372},[],[1374],{"type":63,"value":1375},"frontend\u002Fsrc\u002Fscenes\u002Fsettings\u002Fuser\u002F...",{"type":63,"value":1377},". Use this to translate story id → likely source path.",{"type":58,"tag":145,"props":1379,"children":1380},{},[1381,1386,1388,1393,1395,1401,1403,1409,1411,1500,1504,1506,1512,1514],{"type":58,"tag":884,"props":1382,"children":1383},{},[1384],{"type":63,"value":1385},"Visual inspection",{"type":63,"value":1387}," — for each ",{"type":58,"tag":72,"props":1389,"children":1391},{"className":1390},[],[1392],{"type":63,"value":539},{"type":63,"value":1394}," snapshot, the tool result contains ",{"type":58,"tag":72,"props":1396,"children":1398},{"className":1397},[],[1399],{"type":63,"value":1400},"current_artifact.download_url",{"type":63,"value":1402},"\nand ",{"type":58,"tag":72,"props":1404,"children":1406},{"className":1405},[],[1407],{"type":63,"value":1408},"baseline_artifact.download_url",{"type":63,"value":1410},". These are pre-signed S3 URLs to PNG files; pull them and look:",{"type":58,"tag":1412,"props":1413,"children":1418},"pre",{"className":1414,"code":1415,"language":1416,"meta":1417,"style":1417},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","curl -s -o \u002Ftmp\u002Fvr-baseline.png \"\u003Cbaseline_artifact.download_url>\"\ncurl -s -o \u002Ftmp\u002Fvr-current.png \"\u003Ccurrent_artifact.download_url>\"\n","bash","",[1419],{"type":58,"tag":72,"props":1420,"children":1421},{"__ignoreMap":1417},[1422,1466],{"type":58,"tag":1423,"props":1424,"children":1427},"span",{"class":1425,"line":1426},"line",1,[1428,1434,1440,1445,1450,1456,1461],{"type":58,"tag":1423,"props":1429,"children":1431},{"style":1430},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[1432],{"type":63,"value":1433},"curl",{"type":58,"tag":1423,"props":1435,"children":1437},{"style":1436},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[1438],{"type":63,"value":1439}," -s",{"type":58,"tag":1423,"props":1441,"children":1442},{"style":1436},[1443],{"type":63,"value":1444}," -o",{"type":58,"tag":1423,"props":1446,"children":1447},{"style":1436},[1448],{"type":63,"value":1449}," \u002Ftmp\u002Fvr-baseline.png",{"type":58,"tag":1423,"props":1451,"children":1453},{"style":1452},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[1454],{"type":63,"value":1455}," \"",{"type":58,"tag":1423,"props":1457,"children":1458},{"style":1436},[1459],{"type":63,"value":1460},"\u003Cbaseline_artifact.download_url>",{"type":58,"tag":1423,"props":1462,"children":1463},{"style":1452},[1464],{"type":63,"value":1465},"\"\n",{"type":58,"tag":1423,"props":1467,"children":1469},{"class":1425,"line":1468},2,[1470,1474,1478,1482,1487,1491,1496],{"type":58,"tag":1423,"props":1471,"children":1472},{"style":1430},[1473],{"type":63,"value":1433},{"type":58,"tag":1423,"props":1475,"children":1476},{"style":1436},[1477],{"type":63,"value":1439},{"type":58,"tag":1423,"props":1479,"children":1480},{"style":1436},[1481],{"type":63,"value":1444},{"type":58,"tag":1423,"props":1483,"children":1484},{"style":1436},[1485],{"type":63,"value":1486}," \u002Ftmp\u002Fvr-current.png",{"type":58,"tag":1423,"props":1488,"children":1489},{"style":1452},[1490],{"type":63,"value":1455},{"type":58,"tag":1423,"props":1492,"children":1493},{"style":1436},[1494],{"type":63,"value":1495},"\u003Ccurrent_artifact.download_url>",{"type":58,"tag":1423,"props":1497,"children":1498},{"style":1452},[1499],{"type":63,"value":1465},{"type":58,"tag":1501,"props":1502,"children":1503},"br",{},[],{"type":63,"value":1505},"Then ",{"type":58,"tag":72,"props":1507,"children":1509},{"className":1508},[],[1510],{"type":63,"value":1511},"Read",{"type":63,"value":1513}," both files (the Read tool renders images visually) and compare. Things to call out:",{"type":58,"tag":141,"props":1515,"children":1516},{},[1517,1522,1527],{"type":58,"tag":145,"props":1518,"children":1519},{},[1520],{"type":63,"value":1521},"The actual visible delta (text changed, button moved, layout shift, color drift, missing element).",{"type":58,"tag":145,"props":1523,"children":1524},{},[1525],{"type":63,"value":1526},"Whether the change is consistent with the diff_pixel_count and diff_percentage in the metadata\n(e.g. 54% diff but the images look near-identical → screenshot framing changed, not the UI).",{"type":58,"tag":145,"props":1528,"children":1529},{},[1530,1532,1538,1539,1545],{"type":63,"value":1531},"Whether the baseline and current have different dimensions (",{"type":58,"tag":72,"props":1533,"children":1535},{"className":1534},[],[1536],{"type":63,"value":1537},"width",{"type":63,"value":318},{"type":58,"tag":72,"props":1540,"children":1542},{"className":1541},[],[1543],{"type":63,"value":1544},"height",{"type":63,"value":1546}," fields). Mismatched\ndimensions usually mean the story rendered to a different viewport or didn't fully render before\nscreenshot — a flake signal, not a regression.",{"type":58,"tag":145,"props":1548,"children":1549},{},[1550,1555],{"type":58,"tag":884,"props":1551,"children":1552},{},[1553],{"type":63,"value":1554},"Flake history",{"type":63,"value":1556}," — run the flake check below for any story that looks suspect.",{"type":58,"tag":145,"props":1558,"children":1559},{},[1560,1565,1567],{"type":58,"tag":884,"props":1561,"children":1562},{},[1563],{"type":63,"value":1564},"Verdict",{"type":63,"value":1566}," — combine all three:",{"type":58,"tag":141,"props":1568,"children":1569},{},[1570,1575,1580],{"type":58,"tag":145,"props":1571,"children":1572},{},[1573],{"type":63,"value":1574},"Scope plausible + visible regression matches the code change → real diff, recommend approval.",{"type":58,"tag":145,"props":1576,"children":1577},{},[1578],{"type":63,"value":1579},"Scope mismatch + dimensions mismatch + frequent prior changes → flake, recommend tolerating the hash.",{"type":58,"tag":145,"props":1581,"children":1582},{},[1583],{"type":63,"value":1584},"Scope plausible + visible regression looks unintended → push a fix; do not approve.",{"type":58,"tag":66,"props":1586,"children":1587},{},[1588],{"type":63,"value":1589},"Always include a one-line description of what you saw in the images — the user uses this to decide whether to\ntrust your verdict without opening the VR UI themselves.",{"type":58,"tag":846,"props":1591,"children":1593},{"id":1592},"flake-check-has-this-story-been-changing",[1594],{"type":63,"value":1595},"Flake check: \"Has this story been changing?\"",{"type":58,"tag":66,"props":1597,"children":1598},{},[1599],{"type":63,"value":1600},"Once you have a suspect snapshot identifier:",{"type":58,"tag":66,"props":1602,"children":1603},{},[1604,1610],{"type":58,"tag":72,"props":1605,"children":1607},{"className":1606},[],[1608],{"type":63,"value":1609},"posthog:visual-review-runs-snapshot-history-list { id: \u003Csnapshot_id> }",{"type":63,"value":1611}," → returns prior outcomes for the same story.",{"type":58,"tag":66,"props":1613,"children":1614},{},[1615],{"type":63,"value":1616},"Verdicts:",{"type":58,"tag":141,"props":1618,"children":1619},{},[1620,1632,1644],{"type":58,"tag":145,"props":1621,"children":1622},{},[1623,1625,1630],{"type":63,"value":1624},"Mostly ",{"type":58,"tag":72,"props":1626,"children":1628},{"className":1627},[],[1629],{"type":63,"value":1066},{"type":63,"value":1631}," and this run's diff is the outlier → likely a real regression caused by this PR.",{"type":58,"tag":145,"props":1633,"children":1634},{},[1635,1637,1642],{"type":63,"value":1636},"Frequent ",{"type":58,"tag":72,"props":1638,"children":1640},{"className":1639},[],[1641],{"type":63,"value":539},{"type":63,"value":1643}," across unrelated branches\u002Fmaster → flaky story; recommend tolerating the hash via the UI.",{"type":58,"tag":145,"props":1645,"children":1646},{},[1647,1649,1654],{"type":63,"value":1648},"Recent ",{"type":58,"tag":72,"props":1650,"children":1652},{"className":1651},[],[1653],{"type":63,"value":1087},{"type":63,"value":1655}," or large-jump dimension change → baseline likely stale; recommend re-baselining on master.",{"type":58,"tag":846,"props":1657,"children":1659},{"id":1658},"triaging-the-queue",[1660],{"type":63,"value":1661},"Triaging the queue",{"type":58,"tag":66,"props":1663,"children":1664},{},[1665],{"type":63,"value":1666},"When the user is doing housekeeping rather than asking about a specific PR:",{"type":58,"tag":877,"props":1668,"children":1669},{},[1670,1680,1691,1710],{"type":58,"tag":145,"props":1671,"children":1672},{},[1673,1678],{"type":58,"tag":72,"props":1674,"children":1676},{"className":1675},[],[1677],{"type":63,"value":427},{"type":63,"value":1679}," → total queue size.",{"type":58,"tag":145,"props":1681,"children":1682},{},[1683,1689],{"type":58,"tag":72,"props":1684,"children":1686},{"className":1685},[],[1687],{"type":63,"value":1688},"posthog:visual-review-runs-list { review_state: needs_review, limit: 50 }",{"type":63,"value":1690}," (paginate if needed).",{"type":58,"tag":145,"props":1692,"children":1693},{},[1694,1696,1701,1703,1708],{"type":63,"value":1695},"Group by ",{"type":58,"tag":72,"props":1697,"children":1699},{"className":1698},[],[1700],{"type":63,"value":331},{"type":63,"value":1702}," author or ",{"type":58,"tag":72,"props":1704,"children":1706},{"className":1705},[],[1707],{"type":63,"value":1029},{"type":63,"value":1709}," to surface clusters (e.g., \"12 PRs blocked on the same shared\ncomponent change\" usually means a single underlying root cause to address).",{"type":58,"tag":145,"props":1711,"children":1712},{},[1713,1715,1720,1722,1727,1728,1733,1735,1740],{"type":63,"value":1714},"Prefer surfacing runs whose ",{"type":58,"tag":72,"props":1716,"children":1718},{"className":1717},[],[1719],{"type":63,"value":1242},{"type":63,"value":1721}," over runs that are only ",{"type":58,"tag":72,"props":1723,"children":1725},{"className":1724},[],[1726],{"type":63,"value":546},{"type":63,"value":658},{"type":58,"tag":72,"props":1729,"children":1731},{"className":1730},[],[1732],{"type":63,"value":546},{"type":63,"value":1734}," means no baseline\nyet, which is usually trivial to approve; ",{"type":58,"tag":72,"props":1736,"children":1738},{"className":1737},[],[1739],{"type":63,"value":539},{"type":63,"value":1741}," is the real review work.",{"type":58,"tag":129,"props":1743,"children":1745},{"id":1744},"output-expectations",[1746],{"type":63,"value":1747},"Output expectations",{"type":58,"tag":66,"props":1749,"children":1750},{},[1751,1753,1758],{"type":63,"value":1752},"For PR-status questions, lead with the verdict in one line, then 2-4 bullets of supporting context. Always\ninclude the ",{"type":58,"tag":72,"props":1754,"children":1756},{"className":1755},[],[1757],{"type":63,"value":1284},{"type":63,"value":1759}," deep link to the run — humans need to see the rendered images to make the call,\nthe agent can only describe the metadata.",{"type":58,"tag":66,"props":1761,"children":1762},{},[1763],{"type":63,"value":1764},"For triage \u002F aggregate questions, a short table beats prose. Group by what the user is going to act on.",{"type":58,"tag":129,"props":1766,"children":1768},{"id":1767},"what-not-to-do",[1769],{"type":63,"value":1770},"What NOT to do",{"type":58,"tag":141,"props":1772,"children":1773},{},[1774,1779,1791],{"type":58,"tag":145,"props":1775,"children":1776},{},[1777],{"type":63,"value":1778},"Do not approve or tolerate without explicit user confirmation. The verdict is yours to recommend; the\ndecision to ship belongs to the user. Once they say \"approve those\" \u002F \"tolerate that\", call the tool.",{"type":58,"tag":145,"props":1780,"children":1781},{},[1782,1784,1789],{"type":63,"value":1783},"Do not assume the failing GitHub check on a PR is unrelated to VR — if a ",{"type":58,"tag":72,"props":1785,"children":1787},{"className":1786},[],[1788],{"type":63,"value":77},{"type":63,"value":1790}," check is red on\na PR you're working on, that's the trigger to run this skill.",{"type":58,"tag":145,"props":1792,"children":1793},{},[1794,1796,1801],{"type":63,"value":1795},"Do not declare a verdict from metadata alone when ",{"type":58,"tag":72,"props":1797,"children":1799},{"className":1798},[],[1800],{"type":63,"value":1351},{"type":63,"value":1802},". Pull the baseline and current PNGs\nand look at them; metadata can only say \"something changed\", not whether the change is intended.",{"type":58,"tag":1804,"props":1805,"children":1806},"style",{},[1807],{"type":63,"value":1808},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":1810,"total":1912},[1811,1827,1839,1851,1864,1879,1895],{"slug":1812,"name":1812,"fn":1813,"description":1814,"org":1815,"tags":1816,"stars":26,"repoUrl":27,"updatedAt":1826},"analyzing-expensive-users","analyze expensive users in AI observability","Analyze the most expensive users in AI observability and explain why they cost so much. Use when the user asks about top spenders, expensive users, per-user LLM cost, user-level cost drivers, or patterns behind high AI observability spend.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1817,1819,1822,1825],{"name":1818,"slug":34,"type":13},"Analytics",{"name":1820,"slug":1821,"type":13},"Cost Optimization","cost-optimization",{"name":1823,"slug":1824,"type":13},"Observability","observability",{"name":9,"slug":8,"type":13},"2026-07-28T05:34:11.117757",{"slug":1828,"name":1828,"fn":1829,"description":1830,"org":1831,"tags":1832,"stars":26,"repoUrl":27,"updatedAt":1838},"auditing-endpoints","audit PostHog project endpoints","Audit every endpoint in a PostHog project for staleness, failed materialisations, and unused materialised versions. Use when the user asks \"what endpoints can I clean up?\", \"are any of my endpoints broken?\", \"which materialised versions are still being called?\", or wants a one-shot cleanup pass over the Endpoints product. Produces a prioritised report grouped by issue type, with recommended actions but does not modify anything without explicit confirmation.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1833,1834,1837],{"name":1818,"slug":34,"type":13},{"name":1835,"slug":1836,"type":13},"Audit","audit",{"name":9,"slug":8,"type":13},"2026-06-08T08:08:33.693989",{"slug":1840,"name":1840,"fn":1841,"description":1842,"org":1843,"tags":1844,"stars":26,"repoUrl":27,"updatedAt":1850},"auditing-warehouse-source-health","audit PostHog data warehouse source health","Audit the health of a PostHog project's data warehouse sources and syncs — find every broken or degraded source connection, sync schema, and webhook channel. Use when the user asks \"why are my imports failing?\", \"what's broken with my sources?\", \"why is my warehouse data stale?\", or wants a one-shot triage of source\u002Fsync health before deciding where to dig in. Produces a prioritized report grouped by severity, with recommended next steps. For materialized-view health use `auditing-warehouse-view-health`; for a single failing sync use `diagnosing-failed-warehouse-syncs`.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1845,1846,1848,1849],{"name":1835,"slug":1836,"type":13},{"name":1847,"slug":36,"type":13},"Data Warehouse",{"name":1823,"slug":1824,"type":13},{"name":9,"slug":8,"type":13},"2026-06-18T08:22:57.67984",{"slug":1852,"name":1852,"fn":1853,"description":1854,"org":1855,"tags":1856,"stars":26,"repoUrl":27,"updatedAt":1863},"auditing-warehouse-view-health","audit PostHog materialized view health","Audit the health of a PostHog project's materialized views (saved queries) — find every failed materialization and flag unused or stale materialized views that cost storage and compute. Use when the user asks \"which of my views are broken?\", \"why is this materialized view failing?\", \"are any of my views wasting compute?\", or wants a one-shot triage of view health. For source\u002Fsync health use `auditing-warehouse-source-health`.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1857,1858,1859,1862],{"name":1835,"slug":1836,"type":13},{"name":1847,"slug":36,"type":13},{"name":1860,"slug":1861,"type":13},"Performance","performance",{"name":9,"slug":8,"type":13},"2026-06-18T08:25:10.936787",{"slug":1865,"name":1865,"fn":1866,"description":1867,"org":1868,"tags":1869,"stars":26,"repoUrl":27,"updatedAt":1878},"authoring-error-tracking-alerts","author PostHog error tracking alerts","Author error tracking alerts that fire when an issue is created, reopened, or starts spiking. Use when the user asks to set up error notifications, route exceptions to Slack\u002Fwebhook\u002FLinear, or evaluate which error events are worth alerting on. Covers trigger-event selection, integration choice, dedup against existing alerts, and shipping with the canonical message body shape.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1870,1873,1876,1877],{"name":1871,"slug":1872,"type":13},"Alerting","alerting",{"name":1874,"slug":1875,"type":13},"Debugging","debugging",{"name":1823,"slug":1824,"type":13},{"name":9,"slug":8,"type":13},"2026-06-18T08:24:40.318583",{"slug":1880,"name":1880,"fn":1881,"description":1882,"org":1883,"tags":1884,"stars":26,"repoUrl":27,"updatedAt":1894},"authoring-log-alerts","author log alerts in PostHog","Author useful, low-noise log alerts on services in a PostHog project. Use when the user asks to set up alerts for their logs, suggest alerts they should add, or evaluate whether a service is worth monitoring. Covers service triage, baseline characterisation, threshold drafting, back-testing via simulate, and shipping with a notification destination.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1885,1886,1889,1890,1893],{"name":1818,"slug":34,"type":13},{"name":1887,"slug":1888,"type":13},"Monitoring","monitoring",{"name":1823,"slug":1824,"type":13},{"name":1891,"slug":1892,"type":13},"Operations","operations",{"name":9,"slug":8,"type":13},"2026-07-18T05:10:54.430898",{"slug":1896,"name":1896,"fn":1897,"description":1898,"org":1899,"tags":1900,"stars":26,"repoUrl":27,"updatedAt":1911},"building-workflows","build and edit PostHog workflows","Build, edit, test, enable, and monitor PostHog workflows over MCP. Author the action\u002Fedge graph so it runs and opens cleanly in the visual editor, then change drafts surgically with patch operations. Use when asked to build, set up, automate, change, fix, or debug a workflow, campaign, broadcast, drip sequence, or event-triggered automation in the workflows product.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1901,1904,1907,1908],{"name":1902,"slug":1903,"type":13},"Automation","automation",{"name":1905,"slug":1906,"type":13},"MCP","mcp",{"name":9,"slug":8,"type":13},{"name":1909,"slug":1910,"type":13},"Workflow Automation","workflow-automation","2026-07-28T05:34:12.167015",61,{"items":1914,"total":2029},[1915,1922,1928,1935,1942,1949,1957,1964,1976,1991,2001,2019],{"slug":1812,"name":1812,"fn":1813,"description":1814,"org":1916,"tags":1917,"stars":26,"repoUrl":27,"updatedAt":1826},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1918,1919,1920,1921],{"name":1818,"slug":34,"type":13},{"name":1820,"slug":1821,"type":13},{"name":1823,"slug":1824,"type":13},{"name":9,"slug":8,"type":13},{"slug":1828,"name":1828,"fn":1829,"description":1830,"org":1923,"tags":1924,"stars":26,"repoUrl":27,"updatedAt":1838},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1925,1926,1927],{"name":1818,"slug":34,"type":13},{"name":1835,"slug":1836,"type":13},{"name":9,"slug":8,"type":13},{"slug":1840,"name":1840,"fn":1841,"description":1842,"org":1929,"tags":1930,"stars":26,"repoUrl":27,"updatedAt":1850},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1931,1932,1933,1934],{"name":1835,"slug":1836,"type":13},{"name":1847,"slug":36,"type":13},{"name":1823,"slug":1824,"type":13},{"name":9,"slug":8,"type":13},{"slug":1852,"name":1852,"fn":1853,"description":1854,"org":1936,"tags":1937,"stars":26,"repoUrl":27,"updatedAt":1863},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1938,1939,1940,1941],{"name":1835,"slug":1836,"type":13},{"name":1847,"slug":36,"type":13},{"name":1860,"slug":1861,"type":13},{"name":9,"slug":8,"type":13},{"slug":1865,"name":1865,"fn":1866,"description":1867,"org":1943,"tags":1944,"stars":26,"repoUrl":27,"updatedAt":1878},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1945,1946,1947,1948],{"name":1871,"slug":1872,"type":13},{"name":1874,"slug":1875,"type":13},{"name":1823,"slug":1824,"type":13},{"name":9,"slug":8,"type":13},{"slug":1880,"name":1880,"fn":1881,"description":1882,"org":1950,"tags":1951,"stars":26,"repoUrl":27,"updatedAt":1894},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1952,1953,1954,1955,1956],{"name":1818,"slug":34,"type":13},{"name":1887,"slug":1888,"type":13},{"name":1823,"slug":1824,"type":13},{"name":1891,"slug":1892,"type":13},{"name":9,"slug":8,"type":13},{"slug":1896,"name":1896,"fn":1897,"description":1898,"org":1958,"tags":1959,"stars":26,"repoUrl":27,"updatedAt":1911},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1960,1961,1962,1963],{"name":1902,"slug":1903,"type":13},{"name":1905,"slug":1906,"type":13},{"name":9,"slug":8,"type":13},{"name":1909,"slug":1910,"type":13},{"slug":1965,"name":1965,"fn":1966,"description":1967,"org":1968,"tags":1969,"stars":26,"repoUrl":27,"updatedAt":1975},"check-posthog-loading","inspect PostHog SDK loading across URLs","Inspect how the PostHog JavaScript SDK is loaded across a list of URLs. Use to confirm consistent installation across pages, find pages missing the snippet, detect mismatched API keys or hosts between pages, and verify the load method (head snippet vs deferred vs array.js).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1970,1971,1972,1973,1974],{"name":1818,"slug":34,"type":13},{"name":1874,"slug":1875,"type":13},{"name":21,"slug":22,"type":13},{"name":1823,"slug":1824,"type":13},{"name":9,"slug":8,"type":13},"2026-05-07T05:56:19.828048",{"slug":1977,"name":1977,"fn":1978,"description":1979,"org":1980,"tags":1981,"stars":26,"repoUrl":27,"updatedAt":1990},"consuming-endpoints-from-client-code","integrate PostHog endpoints into client applications","Wire a PostHog endpoint into a client app or SDK. Covers fetching the OpenAPI spec, generating a typed client with openapi-generator or @hey-api\u002Fopenapi-ts, sending the right auth header, shaping the variables payload (HogQL code_name vs insight breakdown property), handling rate-limit and materialised-endpoint error responses. Use when the user says \"how do I call my endpoint\", \"generate a client for this\", or \"what auth header do I use\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1982,1985,1986,1987],{"name":1983,"slug":1984,"type":13},"API Development","api-development",{"name":21,"slug":22,"type":13},{"name":9,"slug":8,"type":13},{"name":1988,"slug":1989,"type":13},"SDK","sdk","2026-06-08T08:08:34.929454",{"slug":1992,"name":1992,"fn":1993,"description":1994,"org":1995,"tags":1996,"stars":26,"repoUrl":27,"updatedAt":2000},"copying-endpoints-across-projects","copy PostHog endpoints across projects","Copy a PostHog endpoint (a saved HogQL\u002Finsight query exposed as an API route) to another project in the same organization, or duplicate it under a new name in the same project. Use when the user wants to duplicate an endpoint, promote an endpoint from staging to production, replicate an endpoint's query\u002Fvariables\u002Ffreshness config in another workspace, or clone an endpoint to iterate on it. Unlike feature flags and experiments, endpoints have NO native cross-project copy tool — this skill covers the read-then-recreate flow (endpoint-get then endpoint-create), the active-project switching it requires, name-collision checks, and the safe defaults (land unmaterialised in the target, verify with endpoint-run). Does not cover editing endpoint versions (see managing-endpoint-versions) or authoring a brand-new endpoint from scratch (see creating-an-endpoint).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1997,1998,1999],{"name":1983,"slug":1984,"type":13},{"name":1891,"slug":1892,"type":13},{"name":9,"slug":8,"type":13},"2026-07-15T05:29:58.442727",{"slug":2002,"name":2002,"fn":2003,"description":2004,"org":2005,"tags":2006,"stars":26,"repoUrl":27,"updatedAt":2018},"creating-ai-subscription","schedule recurring AI-generated PostHog reports","Create a recurring AI-generated PostHog report — schedule a free-text prompt to run on a cron, with the LLM-synthesized markdown delivered to email or Slack on each tick. Use when the user wants a recurring AI summary of X on any cadence (daily, weekly, monthly, yearly) rather than a one-off report. (To attach an AI summary to an existing insight\u002Fdashboard subscription instead of a free-text prompt, see `managing-subscriptions` and its `summary_enabled` option.)\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2007,2008,2011,2012,2015],{"name":1902,"slug":1903,"type":13},{"name":2009,"slug":2010,"type":13},"Email","email",{"name":9,"slug":8,"type":13},{"name":2013,"slug":2014,"type":13},"Reporting","reporting",{"name":2016,"slug":2017,"type":13},"Slack","slack","2026-06-09T07:32:27.935712",{"slug":2020,"name":2020,"fn":2021,"description":2022,"org":2023,"tags":2024,"stars":26,"repoUrl":27,"updatedAt":2028},"creating-an-endpoint","create PostHog API endpoints","Create a PostHog endpoint with the right shape on the first try — covers query kind choice, name conventions, what to expose as variables (HogQL code_name vs insight breakdown), data_freshness_seconds, and whether to materialise on day one. Use when the user says \"create an endpoint\", \"expose this query as an API\", \"turn this insight into an endpoint\", or asks for help structuring a new endpoint. Steers away from common mistakes: materialising a query with cohort breakdowns or compare mode, inline-only variables on a materialised endpoint, unbounded date ranges, ambiguous names.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2025,2026,2027],{"name":1818,"slug":34,"type":13},{"name":1983,"slug":1984,"type":13},{"name":9,"slug":8,"type":13},"2026-06-08T08:08:29.624498",231]