Install
$ agentstack add skill-ardaraz-verify-ui-verify-ui Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Dangerous shell/eval execution.
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ● Dynamic code execution Used
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
verify-ui
Record a short, annotated, machine-validated proof video of a UI change in the project's running web app. The clip shows only the changed behavior. Chapter cards name what is under test, markers frame each changed surface, and the harness refuses to bless a clip whose delivered frames do not literally contain them.
This skill is agent-host-neutral and relocatable. SKILL_ROOT below means the absolute directory containing this SKILL.md. Resolve it from the skill path your host gives you and call the scripts by absolute path. Do not assume an agent vendor, a home-directory layout, or a current working directory.
Argument
A route, page name, or free-text description of what to check:
/verify-ui /billing/invoices- explicit route/verify-ui the renamed totals column- describe it; infer the route from
the change just made (and the project's app notes, see below)
/verify-ui doctor- do not record anything. Run
bash "$SKILL_ROOT/scripts/vui-doctor.sh" and show its report. If it flags problems, run bash "$SKILL_ROOT/scripts/vui-doctor.sh" clean, then run check once more and show the clean result.
The project contract (how this skill stays project-agnostic)
Everything project-specific lives in the target project, under /.verify-ui/:
config.sh- plain shell assignments. Recognized keys:
VUI_BASE_URL (app origin, e.g. http://localhost:8080), VUI_SESSION (playwright-cli session name override), anything else your hooks read.
hooks/ensure-servers- executable. Make the app reachable. Exit 0 =
reachable. Exit 2 = blocked, with the reason and exact remedy printed.
hooks/ensure-auth- executable. Make the browser session logged in.
Exit 0 = ready. Exit 2 = blocked (reason + remedy printed). Exit 3 = the server is down, not an auth problem.
app/*.md- optional app notes: navigation map, data setup, domain quirks.
No .verify-ui/ directory means the defaults apply: the app is assumed reachable (or probed via VUI_BASE_URL), and no login is performed.
Sessions are isolated per project by default (a hash of the project root), so parallel projects on one machine never share a browser or steal each other's tabs.
Operating rules (read first)
- Visual proof is the deliverable, not a nice-to-have. A run is finished
only when you have (a) a screenshot you actually opened and inspected, and (b) a recording with a Recording: line. If the browser path is blocked (server, auth, data), STOP and report the blocker with its printed remedy. Never substitute code reading, a headless test run, or screenshots-only and call it verified.
- Announce each phase in one line before it runs - `servers → auth →
navigate → record`. A cold boot or a login can take minutes. Without a status line it reads as a hang.
- Drive playwright-cli only through
$PW(the wrapper below). Never
prepend a Node bin dir to PATH to reach the CLI - that Node leaks into every later command in the shell, and a dev server started afterwards can boot under the wrong Node.
- If blocked by an environment problem this skill does not own (broken
build, missing data, failing hook), stop and relay what the hook printed. Do not rabbit-hole fixing the project's environment.
Knowledge base (references/)
Read only what the task needs:
references/playwright-cli-cheatsheet.md- exact command syntax
(fill vs type, single-expression eval, run-code, clicks and refs, canvas coordinates, allowed write roots). Read before driving the browser if unsure of a verb.
references/recording-and-reporting.md- the two-phase recording
recipe, length cap, per-change clips, and the report template. Read before recording.
/.verify-ui/app/*.md- the project's own notes
(routes, data setup, domain quirks). Read the relevant file when the project ships them.
Steps
1. Resolve the scripts
PW="$SKILL_ROOT/scripts/pw.sh" # playwright-cli wrapper (own Node, per-project session)
HOOK="$SKILL_ROOT/scripts/vui-hook.sh" # project hook runner
R="$SKILL_ROOT/scripts/vui-record.sh" # recording harness
REPO="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" # project root
2. Ensure the app is reachable
> Say: "Checking servers…"
bash "$HOOK" ensure-servers
- Exit 0 - continue.
- Exit 2 - blocked. Relay the printed reason and remedy, then STOP. A cold
boot can take minutes, so if the hook prints a long-running command, run it without a foreground timeout (use your host's background mechanism) and continue when it completes.
3. Ensure an authenticated browser session
> Say: "Restoring login session…"
bash "$HOOK" ensure-auth
- Exit 0 - a browser session is open and ready. Continue.
- Exit 3 - the server is down or unhealthy. This is NOT an auth problem.
Go back to step 2. Do not attempt a login.
- Exit 2 - blocked. Relay the printed reason and remedy, then STOP.
Credentials must never appear in your output. If the hook prints instructions for a human login step, relay them and wait as instructed.
4. PHASE 1 - navigate and prepare the target state OFF-CAMERA
> Say: "Navigating to …"
Resolve the route from the argument, the change just made, and the project's app notes. Reach the target the way a user would - for SPA and lazy-loaded surfaces, exercise the real in-app path (menu, soft navigation, dropdown), not only a hand-built deep link, or you can "verify" a render the user never hits.
Do all setup here, before any recording: navigate, wait for the page to settle, open the record, select the tab, prepare data, clear popovers and banners, consolidate to one tab (bash "$PW" tab-list → close extras → select the app tab), and cache the refs and selectors you will click in phase 2.
If setup fails (dead route, missing data, access denied, broken page) - STOP and report the setup failure. Do not record a long setup video. A recording starts only once the target state is reachable.
5. PHASE 2 - record via the harness ONLY
> Say: "Recording the change…"
Start recording only after the browser is already at the exact state. The clip is a short proof of the new behavior - not a replay of login, navigation, or data setup. Hard cap ≈ 60-90s.
Drive the recording exclusively through vui-record.sh - never hand-roll resize, video-start, or overlay plumbing. In headed mode the screencast records the OS window, not the emulated viewport: on a small screen the OS clamps the window, so a resize 1920 1080 viewport silently records as a top-left crop that cuts markers and chapter cards, while innerWidth keeps reporting 1920. The harness proves viewport-window parity empirically per recording (corner-beacon probe clip), auto-fits the viewport to what the window truly shows, records at native resolution, embeds mp4 chapter atoms, and at finish refuses to bless a clip whose delivered frames do not literally contain the chapter cards and markers.
bash "$R" start "$PW" "$REPO" # resize → parity probe → video-start. Exit 2/3 = the window cannot show a ≥1280px viewport: relay the printed remedy, do NOT record around it
bash "$R" chapter 'Change under test' ''
# REAL clicks between harness calls (bash "$PW" click from a snapshot) - a synthetic
# eval(()=>el.click()) toggles DOM state but the menu closes again on the next focus event,
# so it never shows on camera. Dwell (sleep 2-3) per step.
bash "$R" annotate '' 'TICKET-123: ' ['']
bash "$R" chapter 'Expected result' ''
bash "$R" finish # screenshot + stop + mp4 + validates the DELIVERED frames - give this a generous timeout (up to 5 min)
Marker variants: annotate-absence [container] (hidden field inside a visible group), annotate-between [container] (hidden block between sections). File exports: a Playwright download writes straight to disk with no visible download UI, so after the on-camera export click run bash "$R" download-proof '' - it parses the file (needs the xlsx package in the project) and holds a proof card that finish validates like a chapter card. Never claim an export verified from a clip that only shows the button click. All annotate variants take an optional trailing CSS selector: when the anchor text exists in more than one place, the call exits 4 with ambiguous: N until you pass the container of the intended copy. Never resize between start and finish. Never leave document.body.style.zoom set when annotating.
At minimum: one chapter naming the change, one naming the expected result, and one annotate per surface - finish exits 5 ("DO NOT REPORT") if either is missing from the actual frames. Two non-negotiables:
- Cover EVERY changed surface, not just one. Enumerate the surfaces the
change touches and show each - one cohesive clip with a chapter and marker per surface, or one short clip per change.
- A surface without a visible marker is NOT verified.
annotateis the
only marking path - it asserts matched:true + inViewport:true + an unambiguous anchor + no zoom (exit 4 on any failure: fix the anchor and call again; never record unmarked), and finish re-proves each marker in the extracted video frames. The helper scrolls off-screen anchors into view, draws at the final location, then keeps the box glued to the element every animation frame. Do not scroll manually after annotating. Off-viewport changes must show the travel: if a changed surface starts below the fold, leave it off-screen when recording starts and let the on-camera annotate call scroll to it - the visible travel is part of the proof.
If the change itself fails after recording starts, keep a brief failure clip (finish still validates the mechanics), then stop - the discrepancy goes in the report.
6. Read the proof, then report
finish already stopped the take, took the screenshot, converted the mp4, extracted a frame per chapter and per marker, and hard-checked: full frame at start, middle, and end, canvas width, duration cap (pass finish 150 only for a justified longer multi-surface clip), chapter-card and marker pixels in the delivered frames, and mp4 duration against the source. Exit 5 means the clip is NOT reportable - fix exactly what it names and re-record. Never report around it.
Your remaining duties (the pixel checks prove presence, you confirm meaning):
- Open the screenshot and verify the change is actually rendered and
behaving - on every surface the change affects.
- Open every
Frame:png thatfinishprinted - confirm each shows the
right surface and the marker caption you intended.
bash "$PW" snapshotif you need the DOM to describe what is on screen.
7. Report
Lead with the screenshot and a compact per-surface result (one bullet per surface: what you did, what you saw, pass or fail against the expected change). Describe any discrepancy honestly - never claim success without visual confirmation.
Every report after recording started ends with the recording path(s), absolute, one per change: Recording: /.playwright-cli/videos/verify-ui-.mp4. A report without a Recording: line is incomplete, and so is one with a covered surface that has no visible marker. The only exception: setup failed before the target state was reachable. If a recording failed to save, say so explicitly instead of omitting it.
Close the browser when you finish. Run bash "$PW" close as the last action, after you have read the screenshot and frames. Close on the early-stop paths too. Skip only when asked to leave the window open. close quits this project's session only. Keep close-all and kill-all for stale-session recovery, because those quit every session on the machine, including other projects'.
Notes
- Recording harness (
$SKILL_ROOT/scripts/):vui-record.sh
(start/chapter/annotate/annotate-absence/annotate-between/download-proof/ finish/abort - owns the parity probe, native-resolution canvas, chapter atoms, frame validation), frame-analysis.py (pixel oracle), annotate.js (page overlays including the parity beacons). Recording outside the harness is a regression - the window-crop failure mode is invisible to every API-level check.
- Write root: playwright-cli only writes under the checkout that started
the daemon. vui-record.sh start detects a mismatch, records there, and finish copies the mp4, screenshot, and frames back into this project's .playwright-cli/videos/.
- Recover a zombie or abandoned session: run
bash "$SKILL_ROOT/scripts/vui-doctor.sh" clean - it fixes only daemons that are provably broken or ownerless, by PID, and never touches a healthy named session. Reach for bash "$PW" kill-all only if the doctor cannot fix it (kill-all closes every session on the machine, including other projects'). Then bash "$HOOK" ensure-auth again.
- Do not
gotothe app without step 2 first - you will land on an error or
login page.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: arDaraz
- Source: arDaraz/verify-ui
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.