Skip to content

About

Your agent said "fixed." Here's the replay. Before/after browser evidence for AI code changes — CLI + herdr plugin.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

patchreplay

Your agent said "fixed." Here's the replay.

patchreplay records the same browser steps against your app before and after an AI agent's change, then tells you, honestly, what changed. You get a side-by-side GIF, a video report, and a Markdown block you can paste into your PR.

English | 日本語

patchreplay: before fails, after passes

  • No config, no existing tests needed. patchreplay starts both versions of your Vite app, asks the coding agent you already use (Claude Code or Codex) to write a short check, and runs it on both.
  • Honest verdicts. ✅ only when before reaches an assertion and fails it, and after passes. The wording follows the change: Fixed (the bug reproduces before and is gone after), Added (a new feature appears only after) or Verified. A feature that didn't exist yet is shown as ○ not there yet, not as a red failure. A page that didn't load or a click that couldn't happen gives ⚠️ inconclusive, never "fixed". The other results are ➖ no difference, ❌ after fails, 📷 captured only and ☑️ after only (no baseline).
  • Never touches your work. Snapshots are git objects written through a temporary index; both versions run in throwaway worktrees.
  • Built for herdr. When an agent pane finishes a turn, patchreplay records the proof automatically. It also works without herdr.

Requirements

  • Node 20+, git, and a Vite app that runs without logging in. Verified on macOS (Apple Silicon) with herdr 0.9.5, Node 24 and Vite 7. Linux should work but is untested.
  • To have the check written for you, Claude Code or Codex CLI must be installed and logged in. Without one, you get a plain capture, or you can write the scenario yourself.
  • The first run downloads Playwright's headless Chromium (about 100 MB). A replay takes about 1–2 minutes, about half of it spent writing the check.

What is sent where

Builds, dev servers, browsers and reports all stay on your machine. The one exception is writing the check: patchreplay makes one headless call per replay to the agent CLI you already use (claude -p or codex exec --sandbox read-only). That CLI sends the following to its configured model provider (for example Anthropic or OpenAI):

  • the diff
  • the task title
  • the AFTER page's accessibility tree
  • in herdr mode, the last lines of the agent's terminal

That call counts against your plan or API usage like any other prompt. To send nothing, use --generator none or your own .patchreplay/scenario.json.

The call runs from an empty temporary directory with tools disabled: no shell, file or MCP access, and no project hooks or settings. Page content and diffs are passed in as clearly marked data. The returned steps are validated before anything runs. Terminal excerpts are used for that call only. They are never written to reports, and the prompt is saved only with PATCHREPLAY_DEBUG=1. Reports stay in .patchreplay/ until you share them.

Quick start (any terminal)

# in a Vite app with uncommitted changes from your agent
npx patchreplay run --open

By default it compares your working tree with HEAD. To capture exactly one agent turn, save a baseline first:

npx patchreplay baseline        # before you prompt the agent
# … agent edits files …
npx patchreplay run --open

Or let it watch: once edits go quiet for 10 seconds, it records automatically.

npx patchreplay watch --dir

Output goes to .patchreplay/runs/<id>/ (git-excluded automatically):

File What
replay.gif Side-by-side before/after, one frame per step, verdict at the end
report.html Both videos, a step table with screenshots, console errors, PR snippet
replay.md Paste into your PR (drag replay.gif into the comment box)
scenario.json The check that ran. Copy it to .patchreplay/scenario.json to pin it

herdr plugin

herdr plugin install maromocooo/patchreplay
herdr plugin pane open --plugin patchreplay --entrypoint watch

The watch tab follows every agent pane. When an agent in a Vite repo starts working, patchreplay saves a baseline. When the agent settles, it replays before and after and shows a herdr notification. One tab watches all your workspaces.

If an agent finishes another turn while a replay is recording, that turn is queued and replayed next against the state that was just verified. Nothing is silently folded into a baseline. If a replay fails, its changes stay pending for the next run.

Entry point Kind What
watch tab Auto-record every finished agent turn
run popup Record now for the focused agent's repo
open-latest action Open the latest report for the focused agent
baseline action Save a baseline for the focused agent now

Bind the popup to a key in ~/.config/herdr/config.toml if you like:

[[keys.command]]
key = "prefix+P"
type = "plugin_action"
command = "patchreplay.open-latest"

Apps with an API server or real data

Replays click through your app for real. If your dev server reads or writes real data (a local DB, a data directory), point it at a throwaway location. Otherwise a generated check could edit or delete your data.

Add patchreplay.config.json next to package.json and commit it. Watch mode uses it too.

{
  "devCmd": ["npx", "concurrently", "-k", "tsx server/index.ts", "vite --port {port} --strictPort"],
  "env": { "API_PORT": "{port2}", "APP_DATA_DIR": "{tmp}/data" },
  "url": "http://127.0.0.1:{port}/",
  "ready": ["http://127.0.0.1:{port}/api/health"]
}
Placeholder Filled with
{port} A free port for the app URL
{port2} A second free port, e.g. for an API server
{tmp} An empty directory, separate for BEFORE and AFTER and deleted afterwards
  • ready lists URLs that must respond before a replay starts, so a slow API doesn't make the two versions differ by accident.
  • devCmd is an argv array (no shell).

Options

patchreplay run [--base <ref>] [--task <text>] [--scenario <file>]
               [--generator claude|codex|none|auto] [--dev-cmd "<cmd with {port}>"]
               [--no-gif] [--open]
  • --generator none skips the agent and records a plain page capture (📷 captured only).
  • --dev-cmd handles non-Vite servers, for example --dev-cmd "npm run dev -- --port {port}".

Scenario format

{
  "title": "Empty state hides after adding an item",
  "expectation": "Adding an item hides the empty-state message",
  "steps": [
    { "action": "goto", "path": "/" },
    { "action": "fill", "role": "textbox", "value": "Oat milk" },
    { "action": "click", "role": "button", "name": "Add" },
    { "action": "expectHidden", "text": "Nothing on the list yet." }
  ]
}

Actions: goto, click, dblclick, hover, fill, press, wait, waitFor, scroll, setViewport, expectVisible, expectHidden, expectText, expectCount. Target elements with role + name, text, or selector.

How it works

  1. Snapshot. The working tree, including untracked files and excluding ignored ones, is written as a git commit through a temporary index and pinned under refs/patchreplay/*. Your index, HEAD and files are never touched.
  2. Worktrees. Before and after are checked out into temporary worktrees, with node_modules linked from your checkout.
  3. Servers. Each version's dev server starts on its own free port. They run one at a time.
  4. Check. Once the app has finished loading, the generator sees the diff, the task and the AFTER page's accessibility tree, and returns at most 25 steps. patchreplay validates them before running anything. If a generated check fails on AFTER, which usually means the check is wrong about the page, the generator gets one chance to correct it with the failure and a fresh snapshot. Both versions then run the corrected check, and the report says it was rewritten.
  5. Replay. Playwright runs the same steps on both versions and records video and per-step screenshots. In the GIF, each step's target is outlined, and small targets such as a status-bar label get a magnified inset so the change is readable.
  6. Verdict. Computed from assertion results only. A good-looking video is never treated as a pass.
    • If dependencies changed between the two versions, the verdict carries a visible caveat.
    • Generated scenarios are validated before they run: goto only accepts paths on your app, and leaving the app's origin ends the run.
    • Ctrl-C stops dev servers and removes worktrees.

Limits (v0.1)

  • Vite apps without login. Other dev servers work through --dev-cmd, but they are untested.
  • A generated check can be wrong, and the report always shows what ran. If a check matters, pin it with .patchreplay/scenario.json.
  • If the lockfile changed between before and after, the linked node_modules may not match the before version.
  • macOS and Linux.

Develop

npm install && npm test
herdr plugin link "$PWD"

MIT © maromocooo

About

Your agent said "fixed." Here's the replay. Before/after browser evidence for AI code changes — CLI + herdr plugin.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages