> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tempo.new/llms.txt
> Use this file to discover all available pages before exploring further.

# Visual Review

> Pixel-diff the storyboards you track on every pull request, and keep the PR red until a person approves each change.

# Visual Review

Visual review turns your canvases into a regression test. Mark a storyboard as **tracked**, and every pull request captures it, compares it with the version on your default branch, and posts a `visual-review` check on the PR. The check stays red until someone approves each changed, new, or removed storyboard in Tempo's review portal — approving flips it green instantly, no CI re-run.

Nothing lands in your repo except one workflow file: baselines are captured by CI and stored by Tempo.

## How it works

1. **Tracked is opt-in.** Only component storyboards carrying the `vrt` prop are captured.
2. **Every push captures.** A GitHub Actions workflow runs the published `@tempo-ai/visual-review` CLI: the check goes *pending* within about a minute, the capture and comparison finish roughly ten minutes later, and the PR gets a sticky comment linking the report.
3. **A person approves.** In the portal, each diff is approved or rejected (rejecting requires a comment). Approvals are keyed to the pixel change, so a re-push with identical pixels stays approved.
4. **Main is the baseline.** Pushes to your default branch publish the baselines the next PRs compare against.

## Before you start

* The repo is on **GitHub** and its CI is **GitHub Actions** (the only supported CI today).
* Canvases already work in Tempo (`tempo/tempo.config.json` exists).
* The repo is **connected as a project** in your Tempo organization (Home → *Connect your codebase*). That connection is the opt-in; there is no token to create.
* The [**Tempo Labs AI GitHub App**](https://github.com/apps/tempo-labs-ai/installations/new) is installed on the repo — the same app you install to connect repos. Approvals post the check through it, so without it the check never turns green. A GitHub admin of the repo's owner installs it.

## Set it up

The fastest path is to let the agent do the plumbing.

<Steps>
  <Step title="Ask the agent">
    In a chat on the repo, say **"Set up visual review for this repo."** The agent runs a read-only check of every layer (canvas host, tracked storyboards, CI, workflow, connection, GitHub App, required check, first capture) and tells you what is missing before changing anything.
  </Step>

  <Step title="Review what it writes">
    After you say yes, it adds `.github/workflows/visual-review.yml` from the template the CLI ships (an existing workflow is never overwritten), tracks a small first set of storyboards, and verifies each one renders identically three times so your baseline will not flake.
  </Step>

  <Step title="Open the PR">
    The PR that adds the workflow is also its first run: everything reports as **new**, and the check goes pending within a minute of the push.
  </Step>

  <Step title="Approve the first set">
    Open the report from the check (or the sticky PR comment), approve the new storyboards, and watch the check turn green.
  </Step>

  <Step title="Make it required">
    Once the first capture has landed, a repo admin adds `visual-review` as a required status check (Settings → Branches → your default branch). Choose **Any source** (or the Tempo Labs AI app) as the status source — never GitHub Actions, or the approval can't satisfy it.
  </Step>
</Steps>

<Info>
  Prefer to do it by hand? The workflow template is `templates/visual-review.yml` inside the `@tempo-ai/visual-review` npm package. Keep every `npx --yes @tempo-ai/visual-review@latest …` line as it is — Tempo's own repository runs those exact commands.
</Info>

## Tracking storyboards

Add the `vrt` prop to a component storyboard in its canvas file, or use **Track visual regression** in the storyboard's menu on the Design tab.

```tsx theme={null}
<Storyboard id="Button" component={Button} layout={{ x: 0, y: 0, width: 320, height: 180 }} vrt />

{/* Per-storyboard tuning: threshold 0–0.5, masked regions in storyboard px */}
<Storyboard id="Chart" component={Chart} layout={{ x: 400, y: 0, width: 640, height: 360 }}
  vrt={{ threshold: 0.2, ignore: [{ x: 0, y: 0, w: 640, h: 40 }] }} />

{/* Paused: stays in the manifest, neither captured nor gated */}
<Storyboard id="Feed" component={Feed} layout={{ x: 0, y: 400, width: 640, height: 360 }} vrt={{ skip: true }} />
```

* Component storyboards only; route and HTML storyboards are not tracked.
* Tracked storyboards must render deterministically. Live clocks, random data, network content, and in-flight animation produce diffs on every push. Ask the agent to verify a storyboard before you push, or fix the input and retry.
* Start small — design-system boards are the best first candidates — and grow the set as it proves stable.

## Reviewing a pull request

| Check state                      | Meaning                                                                    |
| -------------------------------- | -------------------------------------------------------------------------- |
| Pending                          | Capturing and comparing (about ten minutes after the push)                 |
| Failing — *N of M need approval* | Open the report and approve or reject each change                          |
| Failing — *blocking error*       | A tracked storyboard failed to render; fix it, the error can't be approved |
| Passing                          | Every change is approved, or nothing changed                               |

Two escape hatches, both deliberate:

* The `visual-review:bypass` label posts success without capturing. Use it for incidents only.
* Put `<!-- tempo-no-visual-change -->` in the PR body **only** when you are certain the PR changes no UI and no tracked storyboard. Any doubt means leave it out and let capture prove it.

<Warning>
  Never add the no-visual-change marker to a PR template. GitHub keeps HTML comments in the PR body, so every PR would silently skip capture.
</Warning>

## Troubleshooting

| Symptom                           | Where to look                                                                                                                                                                                                                  |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| The check never appears           | The workflow must exist on the PR branch with `id-token: write`. Pull requests from forks can't upload captures.                                                                                                               |
| Pending forever                   | Ask the agent to run the visual review check-up; its *first run* row shows whether the capture reached Tempo and whether it failed. Capture failures are almost always the install step — the same fix as for the canvas host. |
| Approvals don't flip the check    | The Tempo Labs AI app isn't installed on the repo, or the required check is bound to GitHub Actions instead of *Any source*.                                                                                                   |
| Everything is "new" on a later PR | The workflow's `push` trigger must name your real default branch; that run publishes the baselines.                                                                                                                            |
| One storyboard flakes             | Fix the nondeterministic input, or pause it with `vrt={{ skip: true }}` until you can. Don't untrack it to make a PR green.                                                                                                    |
