browser-qa-loop
Skill78 starsChanged 6 days agoApache-2.0View on GitHub
Run the browser QA loop against a UI change: a playwright capture harness drives real-input scenarios while `bun run beep qa record` captures video and a witness event log, `beep qa extract` pulls per-gesture frame strips, GIFs, and contact sheets, an Opus 5.5 vision-judge agent judges the evidence into a schema-validated inventory, Fable fixes the findings, and the loop repeats until zero required findings. Use for any milestone that changes pointer gestures, layout, animation, or user-facing UI — jsdom green is not click-works green, and a post-gesture screenshot is not a mid-gesture proof.
In this repository38 other files it gives its agents.
- AGENTS.mdAGENTS.md
- explorations/AGENTS.mdAGENTS.md
- adhdSkill
- atom-reactivity-specialistSkill
- closeoutSkill
- codex-findingsSkill
- crispenSkill
- effect-first-developmentSkill
- exploreSkill
- grillingSkill
- grill-meSkill
- grill-with-docsSkill
- jsdoc-annotation-specialistSkill
- motion-evidence-reviewSkill
- onepassword-secret-refsSkill
- ontology-architectSkill
- ontology-conceptualizerSkill
- ontology-curatorSkill
- ontology-foundational-auditorSkill
- ontology-mapperSkill
- ontology-requirementsSkill
- ontology-scoutSkill
- ontology-validatorSkill
- operator-handoffSkill
- orchestrateSkill
- plasma-sensitive-entrySkill
- portlessSkill
- qa-session-opsSkill
- quality-review-fix-loopSkill
- reflectSkill
- remote-development-agentsSkill
- schema-first-developmentSkill
- shadcnSkill
- sparql-expertSkill
- teachSkill
- turborepoSkill
- unslopSkill
- yeetSkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 63
Check report.md for clock-sync confidence and budget warnings.
- Very specific: line 137
Start the app via its portless script (e.g.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Browser QA Loop
The loop that closed dock-substrate-landing (6 rounds, 4 P0s + 8 P1s that suites and hosted checks missed) and ontology-workbench-migration M4. Run it before declaring any gesture-bearing UI milestone done.
History — 0.2.0: recording-based evidence (video + witness events + extraction),
structured qa-inventory/v1 judgment, Lane B real-Chrome recipe, portless
guidance corrected. 0.3.0: Lane B deprecated (human-gated portal, silent
black captures); Lane C (Xvfb + XTEST) named as its replacement. 0.1.0:
screenshots-only loop.
Why it exists
- jsdom stubs
setPointerCapture: native pointer capture swallows button clicks invisibly to unit tests (shipped twice in one package before this loop existed). - Post-hoc screenshots cannot see mid-gesture failures. The dock-react
pointer fixes (selection smear across panels during a sash drag, a
pointercancelorphaning resize state) are only visible during the drag — frame strips extracted from a recording are the only artifact class that can prove or falsify them. - Vision judging catches what assertions cannot express: contrast, crowding, clipped content, confusing affordances, hover states that never apply, transitions that jump instead of ease.
- Programmatic assertions catch what vision cannot: key hygiene, node identity (keep-alive), console invariants, group topology, selection state.
The loop
- Capture — copy
resources/qa-capture-template.mjsbeside your app as.beep/qa-capture.mjs(gitignored) and adapt the scenario list. Run it through the recorder:bun run beep qa record --lane playwright --app <app> --round N— this starts the event collector, injects the witness (event log + fake cursor + sync beacon), records video via playwrightrecordVideo, and runs your harness. Scenarios still write{ name, screenshots[], assertions[], consoleErrors[], notes[] }into.beep/qa/round-N/manifest.json. Drive REAL input (mouse.down/move/up,keyboard.press) — never synthetic DOM events — and drive gestures SLOWLY (≥ 20 steps, ≥ 1.5 s) so extraction has frame density. Exit line:CAPTURE-GREENorCAPTURE-FAILURES: n. Fix capture failures before judging. - Extract —
bun run beep qa extract --session .beep/qa/round-Ncorrelates the witness clock to video time (sync beacon / OBS anchor), then writes per-gesture evidence into the round dir:frames/strips,clips/GIFs+snippets,sheets/contact sheets, each stamped withXMP-beepQAprovenance. Checkreport.mdfor clock-sync confidence and budget warnings. - Judge —
bun run beep qa judge-pack --round Nbuildsjudge/(timeline, file manifest with byte sizes, rendered prompt fromresources/judge-prompt.md). Launch the vision judge as an Agent-tool subagent pinned tomodel: "claude-opus-5-5"(never theopusalias): it reads<round>/judge/prompt.mdand the evidence files that prompt names, edits nothing, and its final message is the verdict. Save that final message verbatim to<round>/judge/stdout.txt. Thenbun run beep qa judge-ingest --round N --from <round>/judge/stdout.txtdecodes the JSON verdict, cross-checks every evidence path and event ref, and writesinventory.json+ rendersinventory.md. The exit gate isinventory.json'srequiredCount, not a grepped line. - Fix — Fable fixes P0+P1 (P2 at discretion), with unit/interaction tests
where the bug class is testable. Adapter/pointer fixes must respect the
pressStartsOnButtonguard pattern. - Repeat / Record — bump the round, rerun capture → extract → judge.
Exit when a round reports
requiredCount: 0AND capture is green. The final round'sinventory.json+session.jsonare the packet's QA evidence; reference them from the milestone PR body. GIFs may be embedded in PR bodies for humans.
<!-- beep-models:begin qa-judge -->| Role | Surface | Model | Effort |
| qa.judge | claude-code | claude-opus-5-5 | — |
<!-- beep-models:end qa-judge -->Evidence policy
- The judge never ingests GIFs or video — animated media is unreliable for
vision models. Frame strips and contact sheets are the judge's motion
evidence;
judge/timeline.mdgives it the ground-truth event timing to correlate against. GIFs exist for humans and PR bodies. - Byte budget: judge payload ≤ 8 MB total, ≤ 400 KB per file; sheets/strips
have different formats: extraction plans cap strip-frame width at 960
pixels, while contact sheets are JPEG grids. Use the extraction plan and
frame manifests for the actual frame count and timestamps. Over budget,
judge-packdrops assertion-green static screenshots first, then thins strips — every drop is recorded injudge/manifest.jsonso the judge knows what it did not see.
Structured inventory contract
qa-inventory/v1 schemas live in
packages/tooling/library/qa-capture/src/QaInventory.schemas.ts. The judge
emits ONE fenced JSON block; judge-ingest is the only writer of
inventory.json/inventory.md; beep qa judge-lint --round N re-validates
any round (use it in campaign exit checks). The prompt's lens list is bound to
the QaLens schema; run bun run beep lint judge-rubric after changing it.
Findings carry evidence refs
(artifact path + event sequence refs + frame ranges) and a resolvedInRound
field maintained across rounds.
Lane B: real-Chrome OBS round — DEPRECATED 2026-08-01
Do not start new rounds on this lane. The PipeWire portal requires human
consent by design, so an OBS round can never run unattended, and a capture
whose restore token has gone stale records an entirely black video that every
downstream step accepts (deleting the beep-qa scene does NOT delete the
input, so CreateInput never re-runs and no picker appears — remove the INPUT
to force a fresh pick). Both failure modes are recorded as SYS-01/SYS-02 in
goals/recorded-qa-acceptance/ledgers/findings.md.
Replacement: Lane C (Xvfb + XTEST), not yet productionized. Xvfb +
headed Chrome (--ozone-platform=x11) + xdotool XTEST input + ffmpeg
x11grab + CDP for assertions. XTEST enters through the X server's input
pipeline, so Chrome cannot distinguish it from hardware — it anchors real
native text selections, which CDP provably cannot — and it needs no human and
no portal. Until the lane ships as --lane x11, treat native-input classes as
UNPROVEN rather than reaching for OBS: see the campaign packet's lane-decision
row for the evidence and the follow-up.
The OBS recipe below is retained only for an existing session that already has a working scene:
- Start the app via its portless script (e.g.
bun run --cwd apps/storybook storybook). bun run beep qa record --lane obs --app <app> --round N(--url <absolute-url>is the alternative; the target also supplies the collector's allowed origin) — provisions thebeep-qaOBS scene (one-time PipeWire portal window pick; the restore token persists) and starts recording.- Launch codex against real Chrome with the routing wording from the
codex-browser-automationmemory verbatim: "use the chrome:control-chrome skill and the Chrome extension backend; do not use browser:control-in-app-browser and do not select iab." - Inject the witness with one JS call in the tab:
document.head.appendChild(Object.assign(document.createElement("script"), { src: "http://127.0.0.1:43117/witness.js?session=<id>&cursor=0" }))Drive each checklist gesture; dropbun run beep qa mark "<scenario>"between gestures. bun run beep qa stop→ extract → judge exactly as Lane A.
Dev servers
Canonical URLs are http://<app>.beep.localhost:1355 via the portless-wrapped
scripts — never raw ports. Portless names are machine-global and a duplicate
registration fails loudly (no silent collision), so for a concurrent
worktree lane run a lane-suffixed name:
portless storybook-<lane>.beep sh -c 'storybook dev -p "$PORT"' →
http://storybook-<lane>.beep.localhost:1355. Never --force over another
lane's route. PORTLESS=0 is diagnostic-only.
Scenario checklist (adapt per surface)
Boot/default layout + persistence-key hygiene; every launcher entry
(focus-or-open); closed-by-default panels; tab overflow at narrow width;
every drop quadrant + one completed split; Escape-cancels-drag; float →
move → dock-back (watch console for StrictMode/useDisposable invariants);
keep-alive node identity across re-layout; theme toggle both ways; sash
resize against minima; reload restores. Gesture coverage (recorded): slow
sash drag across panel text; tab drag between groups; floating pane move +
grip resize; drop-quadrant hover previews; Escape AND pointercancel
injection mid-drag; hover states on tabs/menus; theme-toggle transition
correlated against recorded transitionstart/transitionend events.
Environment notes
- The vision judge is the Opus 5.5 Agent-tool subagent from the Judge step; it only reads the round's files. Captures run on the operator side: neither the judge nor an opt-in codex sandbox opens listeners (vitest browser mode, dev servers).
- Lane B depends on the codex extension-host bridge being healthy — see the
codex-browser-automationmemory for the repair and routing recipe. Lane A (beep qa record --lane playwright) is the always-available fallback. - Session mechanics, lane choice, OBS provisioning, and collector/witness
troubleshooting live in the
qa-session-opsskill; evidence-reading mechanics inmotion-evidence-review. - Long publishes/proofs during the loop: nohup-detached + Monitor, never a harness background task (10-minute cap kills them).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

