Webページや画像の変更前後を同じ条件で撮影し、画面の差を比べるためのスクリーンショットと、必要に応じて共有用Markdownを作成します。
- UI変更の前後を比較したいとき
- PR用の画面比較資料を作りたいとき
- 特定のページ要素だけ撮影したいとき
アプリの操作や変更後の動作を確かめ、画面録画やスクリーンショット、測定結果などの証拠をまとめて、指定先に結果を届けます。
Records visual proof while testing UI behavior — the agent tests the app hands-on via computer use while a screen recording with structured test/assertion annotations captures the session — then posts the video and a results summary to the requested destination. Use when changed runtime behavior needs observable verification, including headless environments (scripted screenshots and probes) and non-UI changes (measured numbers, output pairs).
実行スコア 未検証
インストール方法を見る変更後の動作を確かめ、内容に合った証拠を記録して結果をまとめます。GUIを操作できる環境では、エージェントがアプリを実際に操作する様子を録画し、テスト開始や検証結果の注釈を付けます。画面を使えない環境では、スクリプトで画面を撮影し、テストごとの結果を記録します。APIや性能の変更なら測定値、描画変更なら画像とピクセル比較など、画面操作以外の証拠も扱います。レポートにはテスト内容、環境、対象リビジョン、結果、注意事項を記載します。
UIの変更が実際に動くことを、レビュー担当者にも見える形で示したいときに向いています。GUIのない環境での確認や、API・性能など画面に現れない変更の検証にも使えます。
録画にはPython 3、FFmpegとffprobeが必要で、OSごとの画面収録条件もあります。GUI操作には操作可能な画面と認証済みブラウザーセッションが必要です。ヘッドレス確認にはBash、Node 20以上、npm、Chromiumのシステムライブラリを使います。証拠の投稿には gh などが必要です。投稿先は依頼で指定された範囲に限ります。
この紹介文は、公開されている SKILL.md をもとに AI(OpenAI Codex)が作成しました。正確な仕様は下の原文を確認してください。
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Record proof of behavior and deliver it to the requested destination.
Choose evidence proportional to the change. Use the recorder for interactive flows, scripted captures for headless UI checks, and output pairs for CLI or API changes. Documentation-only edits need content checks and verification of runnable examples, not a recording. Reuse suitable evidence already captured in the task. Publish only to destinations included in the requested work.
The recording is the capture of you testing the app via computer use: start the
recorder, then drive the app yourself — click, type, navigate — through each
test target. Every action in the video is the test being performed live; the
recording has no value as evidence unless it shows that interactive session.
If the harness has no computer-use tools but a GUI exists, drive the app with
cua-driver instead (see below) — it is still your live session.
The bundled recorder, scripts/evidence.py, captures the display with FFmpeg
on Linux, macOS, and Windows, timestamps each annotation you add while
testing, burns them into the video on stop, and verifies the result with
ffprobe. It writes evidence.mp4, report.md, and manifest.json into the
session folder.
EVIDENCE below means the path to scripts/evidence.py inside this skill's
folder (wherever the skill is installed, e.g.
~/.claude/skills/evidence-driven-testing/scripts/evidence.py). It needs only
Python 3 and FFmpeg.
Check first: python3 $EVIDENCE doctor — verifies ffmpeg, ffprobe,
libx264, and the ass filter (ready), then which screen-capture source
works on this machine (capture_ready and the source auto will pick).
Exits non-zero only when the toolchain is missing; read capture_ready
before recording.
Platforms (--source auto picks the first available):
| OS | Source | Needs |
|---|---|---|
| Linux X11 / XWayland | x11 (x11grab) | DISPLAY set |
| Linux Wayland | wayland (wf-recorder) | WAYLAND_DISPLAY set, wf-recorder on PATH, and a compositor confirmed to support wlr-screencopy — either a known wlroots one (Sway, Hyprland, river, Wayfire, labwc, dwl, niri) or verified via wayland-info. GNOME and KDE Wayland are not capturable this way; doctor says so. Use x11 through XWayland for X11 apps, or a fallback recorder. --source wayland still forces it |
| macOS | avfoundation | Screen Recording permission granted to the terminal / agent host app; doctor lists screen indexes for --screen-index |
| Windows | gdigrab | any standard ffmpeg build; powershell for process checks |
Capture is the full screen by default; --geometry WxH and --offset X,Y
crop a region on x11, wayland, and gdigrab. XWayland only sees X11 windows,
so prefer the wayland source when the app under test is Wayland-native.
Crash-safe raw capture: the raw recording is MPEG-TS (raw.ts), so if
the recorder is killed hard or crashes, what was captured still probes and
renders. stop remuxes or re-encodes it into a standard evidence.mp4.
How stopping works: on Linux the recorder is signalled through a pidfd.
On macOS and Windows, and on Linux when the kernel or a seccomp policy
refuses pidfds, start launches a small supervisor process that owns
the ffmpeg child, and stop asks it (via stop.request in the session
folder) to interrupt, then terminate, then kill; it writes
recorder-exit.json when done. Nothing ever signals a bare PID, so a
recycled PID can't be hit. If the supervisor dies while the recorder is
still running, stop refuses and tells you which PID to stop by hand. If
it died before it could even record which process it started, stop stays
blocked until you have checked for a stray recorder yourself and rerun it
with --accept-untracked-recorder; the report then carries that caveat.
Fallback recorders when doctor reports no capture source (for
example Wayland without wf-recorder): cua-driver recording start <dir> /
stop (see the cua-driver section), or the OS recorder (macOS:
screencapture -v out.mov). On these paths there is no annotation overlay,
so keep the annotation protocol as files — an assertions.md listing each
setup / test_start / assertion with its result and the approximate
video timestamp, exactly as in the headless path.
Never present --source test (the synthetic pattern generator) as UI
evidence. It exists to smoke-test the toolchain; the repo's
tests/test_evidence.py exercises it.
git rev-parse HEAD and
git branch --show-current (or the deployment URL) — the recorder stamps
them into the report.Begin the screen recording before the first meaningful action:
python3 $EVIDENCE start \
--output .artifacts/<task-name> \
--title "<what is being verified>" \
--commit "$(git rev-parse HEAD)" --branch "$(git branch --show-current)" \
--environment "<OS / browser / display / deployment>"
It prints JSON with a session path and the chosen source; keep the
path (SESSION=...) for every later command. The source is auto-detected
and the whole screen is captured; pass --source, --geometry,
--offset, --display/--xauthority (X11), --screen-index (macOS), or
--output-name (Wayland) only when doctor or the situation calls for it.
Add a setup annotation describing the starting context:
python3 $EVIDENCE annotate "$SESSION" --type setup \
--message "Logged in, navigating to connectors page"
Perform every interaction through computer use on the live app — the recording captures your session, so the testing and the evidence are the same act. Work at a watchable pace: let the UI settle after each action so state changes are visible on video.
At each named test's start, add a test_start annotation in Jest style:
python3 $EVIDENCE annotate "$SESSION" --type test_start \
--message "It should execute the tool directly when permission is 'always'"
After each check, add an assertion annotation with --result passed,
failed, or untested:
python3 $EVIDENCE annotate "$SESSION" --type assertion --result passed \
--message "Tool ran without a permission prompt"
Rules for assertions:
untested with the reason — never skip silently.passed.Stop recording after the final assertion:
python3 $EVIDENCE stop "$SESSION"
This stops the capture (gracefully, so the recorder flushes; escalating
only if it ignores the request), burns the annotations into evidence.mp4,
probes the result, and writes report.md and manifest.json next to it.
It prints "verified": true on success; if rendering fails the session is
marked finalization_failed — fix the reported cause and run stop again
(a retry does not signal the recorder twice). If the recorder process can no
longer be signalled safely (it died, or its PID now belongs to another
process), the session is marked recorder_lost. Running stop again
finalizes whatever video was captured, but only once that recorder process
is confirmed gone — if it is still alive, stop it first, or the video would
be rendered while still being written.
Confirm the recording captured the key moments before sharing: extract a
frame at each assertion timestamp (ffmpeg -ss <t> -i evidence.mp4 -frames:v 1 frame.png) and check the state and the label are visible.
Fill in the Caveats section of report.md; never leave the placeholder.
report.md is the report: what was tested, environment + exact commit,
pass/fail per test, caveats. Extend it rather than rewriting from scratch.gh pr comment cannot attach a local video — upload
evidence.mp4 through the PR's comment box in an authenticated browser, or
upload it to a host and link it (for example the before-and-after upload
adapters). Reopen the comment and confirm the video plays before claiming it
is posted.cua-driver; with no GUI at all, use the headless path instead.untested and say why.When a display exists but the agent has no built-in computer-use capability, use cua-driver (macOS / Windows / Linux) as the actuator. It is still you testing the app live — the recording rule holds unchanged; only the input mechanism differs.
cua-driver doctor before recording. If a
cua-driver skill is installed, read it and follow its protocol — the
snapshot-before-action invariant is mandatory.launch_app → get_window_state (accessibility tree
element_token (click, type_text, press_key)
→ verify_state for the expected postcondition. Each verify_state check
maps 1:1 onto an assertion annotation.doctor reports capture_ready: yes, keep using the bundled
recorder above for the video and the annotations; cua-driver only supplies
the input.cua-driver recording start <output-dir> / cua-driver recording stop is the recorder (the output directory is required, and the daemon
must be running: cua-driver serve). Video capture is on by default and is
finalized to <output-dir>/recording.mp4 on stop — but on Windows/Linux it
shells out to ffmpeg, so a missing ffmpeg or display yields only the
per-turn trajectory folders (before/after screenshots, action.json,
click.png), no video. After stopping, verify recording.mp4 exists
before citing it; if it is absent, fix the recorder or present the
per-turn before/after screenshots as numbered captures per the headless
protocol.assertions.md listing each test_start / assertion with its
result, exactly as in the headless path.When the agent has no desktop to record, keep the same assertion discipline; swap the recorder for scripted capture:
Save everything to .artifacts/<task-name>/ (gitignore it — evidence gets
uploaded, never committed). Keep the capture script beside the captures so
the run is repeatable.
Screenshots: the before-and-after CLI (@vercel/before-and-after)
captures URLs or elements and its pairs feed PR embeds directly. In
containers/VMs where Chrome fails with "No usable sandbox", set
AGENT_BROWSER_ARGS="--no-sandbox".
Video / multi-step flows: a one-off Playwright script, run without adding playwright to the project's dependencies:
bash /path/to/evidence-driven-testing/scripts/run-playwright.sh record.mjs
The helper installs the pinned Playwright version from its bundled manifest
and lockfile with npm ci in a temporary directory, copies the script
beside that installation, installs Chromium if needed, and removes the
temporary directory on exit. It preserves the caller's working directory,
so relative artifact paths still point into your project. Node 20+ and npm are
required; the browser cache remains available for later runs. Keep the script
self-contained: relative imports and adjacent data files are not copied.
Use the project's existing Playwright setup for scripts with local imports.
When upgrading capture tooling, update scripts/playwright/package.json,
regenerate its lockfile with npm, and rerun the capture checks.
npx --package=playwright adds executables to PATH; it does not make the
package importable from an arbitrary ESM script. Minimal record.mjs:
import { chromium } from "playwright";
const browser = await chromium.launch();
try {
const context = await browser.newContext({
recordVideo: { dir: ".artifacts/<task-name>/" },
});
try {
const page = await context.newPage();
await page.goto("http://localhost:3000/path-under-test");
// Drive the flow and check each expected state here.
} finally {
await context.close(); // Finalizes the video even if an assertion fails.
}
} finally {
await browser.close();
}
Trim or compress with ffmpeg if the file is large.
The annotation protocol becomes files: number captures in test order
with the assertion in the name — 01-precondition-signed-in.png,
02-it-saves-on-blur-passed.png — and keep an assertions.md in the
artifacts folder listing each test_start / assertion with its result
(passed / failed / untested + reason).
probe-output.txt.lsof -i :<port> — or where lsof isn't installed,
ss -ltnp "sport = :<port>" to find the listener's PID, then
ps -p <pid> -o args= to confirm it's yours.before-and-after before.png after.png --markdown).まだレビューはありません。使ってみた感想をお寄せください。
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。
Webページや画像の変更前後を同じ条件で撮影し、画面の差を比べるためのスクリーンショットと、必要に応じて共有用Markdownを作成します。
複数の機能で重複する処理を整理し、業務ルールを担うアクションと再利用できる処理を担うサービスの分け方や移行手順を示します。
PRやMRに寄せられたGreptileの指摘を確認し、対象を絞った修正と再レビューを繰り返して、現行リビジョンの評価と未対応事項を整理します。
通常のトリガーで大きなPRを処理できない場合に、`greploop` のワークフローを `@greptile-apps` トリガーで実行する互換用エントリーポイントです。
機能追加や修正に着手する前に、作業ごとのGit worktreeとブランチを用意し、既存の担当作業や変更範囲を確認して安全に編集を進めます。
コミット文やPR、ドキュメント、返信など、人が読む文章からAIらしい定型表現を取り除き、意味と口調を保ちながら具体的で自然な文に整えます。