Diagnose Playwright Failure as Product Bug
appsmithorg/appsmith
Investigates a stubbornly failing Playwright test as a possible product bug, using error output, screenshots, traces and server code, and writes a structured bug report.
A skill your agent uses when the operator wants to verify in the browser that a change works — asks "how do I test this locally?", "give me the steps", "QA this", references a worktree/PR/ticket…
$ npx skills add getlago/lago-front --skill qa-session -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install getlago/lago-front qa-session --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/getlago/lago-front.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/qa-session .claude/skills/qa-session && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "qa-session" agent skill from https://github.com/getlago/lago-front/tree/main/.agents/skills/qa-session into .claude/skills/qa-session/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "qa-session", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/getlago/lago-front/tree/main/.agents/skills/qa-sessionType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add getlago/lago-front --skill qa-session -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install getlago/lago-front qa-session --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/getlago/lago-front.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/qa-session .agents/skills/qa-session && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "qa-session" agent skill from https://github.com/getlago/lago-front/tree/main/.agents/skills/qa-session into .agents/skills/qa-session/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "qa-session", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add getlago/lago-front --skill qa-session -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install getlago/lago-front qa-session --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/getlago/lago-front.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/qa-session .cursor/skills/qa-session && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "qa-session" agent skill from https://github.com/getlago/lago-front/tree/main/.agents/skills/qa-session into .cursor/skills/qa-session/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "qa-session", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/getlago/lago-front.git --path .agents/skills/qa-session--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add getlago/lago-front --skill qa-session -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install getlago/lago-front qa-session --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/getlago/lago-front.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/qa-session .gemini/skills/qa-session && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "qa-session" agent skill from https://github.com/getlago/lago-front/tree/main/.agents/skills/qa-session into .gemini/skills/qa-session/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "qa-session", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install getlago/lago-front qa-sessionInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add getlago/lago-front --skill qa-session -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/getlago/lago-front.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/qa-session .github/skills/qa-session && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "qa-session" agent skill from https://github.com/getlago/lago-front/tree/main/.agents/skills/qa-session into .github/skills/qa-session/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "qa-session", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add getlago/lago-front --skill qa-session -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install getlago/lago-front qa-session --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/getlago/lago-front.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/qa-session .opencode/skills/qa-session && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "qa-session" agent skill from https://github.com/getlago/lago-front/tree/main/.agents/skills/qa-session into .opencode/skills/qa-session/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "qa-session", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
qa-sessionA skill your agent uses when the operator wants to verify in the browser that a change works — asks "how do I test this locally?", "give me the steps", "QA this", references a worktree/PR/ticket…
QA Session is an agent skill from getlago/lago-front. Use when the operator wants to verify in the browser that a change works — asks "how do I test this locally?", "give me the steps", "QA this", references a worktree/PR/ticket built in this session, or reports something not working during manual testing (button does nothing, section missing, block blank).
Its SKILL.md is about 3.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Testing & QA, covering QA and bug reports and Git worktrees. It works with Playwright. The repository describes itself as: Open Source Metering and Usage Based Billing. The licence is AGPL-3.0.
8 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 79b5b3d. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
gitdockerghFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use git, docker and gh, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
QA Session loads about 3.8k tokens when it runs. Until then it costs about 79 tokens; SKILL.md has 2,086 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from getlago/lago-front at commit 79b5b3d, republished under its AGPL-3.0 licence (© getlago). 2,086 words, ~3,844 tokens.
.claude/skills/qa-session/SKILL.md (or your agent's skills folder).Turn a diff into UI steps, reproduce the old bug on main, then prove the fix removes it. Every step is derived from the code (routes, labels, gates) — never guessed.
What QA has to disprove is the reported symptom, not the diff. A fix can be correct, its tests green, its own control run red-then-green, and still leave the ticket's bug in place — the diff answers the analysis, and the analysis can have found a real but different defect. Everything below is built so that failure mode cannot end in a PASS.
manual (operator clicks, you give steps + triage) or auto (you drive the browser).Either missing → AskUserQuestion, stop until answered.
auto mode drives two browsers and they are not interchangeable. Never the built-in Browser pane, and never type credentials in either.
mcp__claude-in-chrome__*) carries the operator's session, so it reaches the app
with no login. Use it for navigation, DOM and computed-style probes, and plain clicks. It has NO
middle-click action at all, and its input channel can die mid-run, delivering zero events to the page
while every call still returns success. Prefer browser_batch; re-read refs after every navigation
(stale refs click the backdrop and close drawers).mcp__plugin_playwright_playwright__*) has real CDP input: browser_click takes
button: "middle" and modifiers: ["ControlOrMeta"], browser_press_key sends genuine keypresses,
browser_tabs lists what a gesture opened. Its browser is a separate profile with NO app session, so ask
the operator to log in there once — after that the whole real-gesture round runs unattended.Any check whose verdict depends on a browser default — middle-click, modifier-click, a keypress — MUST run
on Playwright. A dispatched MouseEvent or KeyboardEvent exercises the app's handlers and nothing else,
so a round driven that way has verified the handler, not the gesture: report it as such.
Prove the instrument before trusting a negative. Install a capture listener, fire one harmless click, and confirm an event actually reached the page. A dead input channel reads exactly like an app ignoring the click.
Resolve the target down to a worktree name first — that name is what the slot registry is keyed on and what the container names derive from:
$LOOP_STATE_DIR/<ISSUE-ID>/state.md (default ~/.claude/loop-state) for worktree, branch, port.branch: matches, same as loop-revise:BRANCH=$(gh pr view <PR> --json headRefName --jq .headRefName)
grep -l "^branch: ${BRANCH}$" "${LOOP_STATE_DIR:-$HOME/.claude/loop-state}"/*/state.md../.worktree-slots
from the front/ checkout (name:front_port:front_base:api_port:api_base), else docker ps.lago-worktree keys a slot by the branch with / replaced by -, so normalize before looking one up —
WT=${BRANCH//\//-} — otherwise every slashed branch misses its own slot and reads as "not running".
http://localhost:<front_port>; containers lago_front_wt_${SAN} and lago_api_wt_${SAN}, with
SAN=$(echo "$WT" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/_/g'). An empty api_port in the slot
means the worktree has no API of its own and proxies the shared stack, whose API is lago_api_dev.504 Outdated Optimize Dep / blank page → clear vite cache THEN restart (first load is slow):docker exec <container> sh -c 'rm -rf /app/node_modules/.vite' || true
docker restart <container>Read the ticket's own repro steps first, then the diff + spec — in that order, so the report frames the
diff and not the other way round. Enumerate the ticket's attachments (get_issue → attachments, plus
list_comments): a video, screenshot or Slack thread often carries the only repro there is. You cannot watch
a video — say so explicitly, and ask the operator for the gesture and the surface rather than substituting a
plausible one.
No ticket (PR, branch or free-text target): the report is whatever the operator handed over — PR body, their own message. Ask for the exact gesture, payload and surface when it is not there; never substitute a plausible one. Everywhere below, "ticket" and "spec" mean that source instead, and with no acceptance criteria the AC control (Step 4a) collapses into the report control — say so rather than deriving ACs from the diff.
Then check what gates the surface:
featureFlag: FeatureFlagEnum.X on the route in src/core/router/*; enum value = DB string.
Flip it on the organization whose slug is in the URL under test, in the API container resolved in
Step 1 (lago_api_wt_${SAN}, or lago_api_dev on the shared stack). Organization.first is an
arbitrary row: it can enable the flag on an org nobody is testing and leave the tested route gated.docker exec -it <api_container> bin/rails runner 'o = Organization.find_by!(slug: "<slug>"); o.update!(feature_flags: (o.feature_flags | ["<flag>"])); puts o.feature_flags.inspect'permissions: on the route, premiumIntegrations gates./<slug>/...).Numbered steps, each with: exact URL · exact visible label (button, menu item, drawer title, read from the
component and translations/base.json) · expected result · old-bug behavior. No internals in the steps.
/design-system/* pages differ structurally from the
real one — they grow instead of scrolling, have no fixed-height/overflow-auto wrapper, no aside, no real
data. Those differences are exactly what hides layout, scroll and clipping defects. Using a harness for
speed is fine; list the structural deltas, then re-run check 1 on the real surface.Reproduce the bug on unfixed code before verifying the fix — otherwise a PASS proves nothing. Two separate controls, both on main:
They are not interchangeable, and (a) passing says nothing about (b). If (b) does not reproduce on main — the reported gesture works fine on unfixed code — then the analysis found a real defect that is not the reported one: stop, say it plainly, and hunt the reported symptom before signing anything off. Verdict is capped at PARTIAL until (b) reproduces.
Same trick both times:
Preferred (same worktree, git status --short must be empty) — revert the whole branch diff, which
git checkout main -- <paths> cannot do for paths the branch adds, deletes or renames:
git diff --binary main...HEAD > /tmp/qa-control.patch # --binary: without it an image or font in the diff won't re-apply
git apply -R /tmp/qa-control.patch # worktree now runs main's code, vite HMR reloads
# run the failing check, confirm the old behavior
git apply /tmp/qa-control.patch # back to the branch code — mandatory, see belowRe-applying the same patch forward is what restores adds, deletes and renames symmetrically.
The forward re-apply is not optional and never skipped. Every way out of the control run goes
through it: the check reproducing, not reproducing, erroring, the browser leg dying mid-run in auto
mode, and the stop above when (b) doesn't reproduce. Skip it and the branch is left running main's code
under a dirty tree that reads as the operator's own uncommitted edits. Restore, confirm
git status --short is empty, and only then report — including when reporting a stop.
Alternative: another running worktree whose branch doesn't touch those files (git diff main...HEAD --stat)
— they share the DB, so the same fixture URL works on both ports.
Record which route was used. If neither is possible, say so plainly and do not claim causality.
Same steps on the fixed app. Screenshot every expected-result checkpoint. Include a reload check when the value also arrives from a second path (hydration, refetch), so the fix isn't masking a regression there.
!!document.querySelector('[data-test=x]') passes on an element rendered
off-screen, clipped or collapsed. For anything floating (menu, toolbar, popper, tooltip, drawer) assert the
geometry: rect inside the visible box of its scroll container, non-zero size, not covered.history.pushState and history.replaceState and count the calls: that is what separates one navigation
from two, and a suppressed navigation from a replace onto an identical target.scrollTop 0 and with the container
scrolled. An absolutely-positioned overlay inside a scrolled position: relative container is a standing
trap — its offset must include scrollTop/scrollLeft, and at scroll 0 a broken one looks perfect.Read the handler BEFORE calling anything a bug.
| Symptom | Check first |
|---|---|
| Button no-ops silently | early-return validation gate in the save handler |
| Menu entry / page missing | feature flag or permission on the route |
Blank page, 504 Outdated Optimize Dep | vite cache → Step 1 |
| Stale behavior after a rebuild | container running old code → restart |
| A real gesture does nothing at all | prove the input channel is alive before blaming the app (Step 0) |
| Middle-click appears to move the current tab too | re-run it once the page has settled: a click landing mid-hydration can do both |
| Click does nothing on part of a block | hitbox is the inner content, not the row |
| Menu / popper / tooltip "never opens" | it may be in the DOM but positioned out of view — compare its rect with the scroll container's, check offsetParent, scrollTop in the offset math, clipping and z-index |
| Looks off (spacing, alignment) | measure from the CSS source and fix the computed delta, never by eye |
| A control states an absence ("no default", "none available") | re-read once the data settles — it must render nothing while its query is in flight, never assert the negative early |
A raw enum or a repeated label in the UI (stripe, label == sublabel) | a display mapping was skipped; find the value's label map instead of printing the field |
src/ edits (CSS included) hot-reload — the operator just reloads. Restart only for dependency/config changes.
Append results to $LOOP_STATE_DIR/<ISSUE-ID>/qa.md, or $LOOP_STATE_DIR/qa/<branch-or-PR>.md when there
is no ISSUE-ID: one row per check, mode, PASS/FAIL, the control outcome, what was deliberately not covered,
anomalies with root cause. Genuine side-findings → propose as a
separate ticket; never fix unasked.
Parity with main is not a finding. Before reporting anything as a defect, a risk, or a decision for the
operator, run the same check on main. A gap that behaves identically there is out of scope: say so once and
close it, never escalate it as a choice to be made. The same yardstick applies to a fix of your own — audit
its blast radius, and when a defect can be corrected either at the call site or in a shared component, choose
the call site.
Then close the reply with this block as the very last thing — nothing after it:
## Verdict: PASS | PARTIAL | FAIL
<one line why>
Control on main (AC): bug reproduced | not reproduced | not possible (<reason>)
Control on main (reported repro, reporter's own steps): reproduced | not reproduced | not possible (<reason>)
Surface: <product surface tested> (<dev harness only, if that is all that was covered>)
Next: <nothing to do | what needs another round | what is still broken>/design-system/*, whose layout can't reproduce the product surface's scroll or clipping.main already had as a finding, or handing it to the operator as a decision.© getlago, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/qa-session of getlago/lago-front.
Open the folder on GitHubat commit 79b5b3d
QA Session next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| QA Session this skillgetlago/lago-front | 163 | — | ~3.8k | Automated safety check: Pass | AGPL-3.0 | |
| Diagnose Playwright Failure as Product Bugappsmithorg/appsmith | 41k | — | ~1.5k | Automated safety check: Pass | Apache-2.0 | |
| Evidence-Driven Testingmichaelshimeles/skills | 1.3k | 1 repos | ~3.9k | Automated safety check: Pass | None | |
| Verify Omnigent End-to-Endomnigent-ai/omnigent | 11k | — | ~1.6k | Automated safety check: Pass | Apache-2.0 | |
| Verifymorapelker/hive | 470 | — | ~709 | Automated safety check: Pass | MIT | |
| Hands On Testktnyt/cclsp | 675 | — | ~1.7k | Automated safety check: Pass | MIT |
appsmithorg/appsmith
Investigates a stubbornly failing Playwright test as a possible product bug, using error output, screenshots, traces and server code, and writes a structured bug report.
michaelshimeles/skills
Records an annotated screen recording of the agent testing an app hands-on, then posts the video and a results summary to the PR and tracker issue.
omnigent-ai/omnigent
Spins up an isolated Omnigent server, runner and mock model to prove a user-facing behavior or bug fix with recorded evidence instead of reasoning from code.
morapelker/hive
Build, launch, and drive this worktree's Hive app over CDP to verify a change end-to-end with playwright-cli
ktnyt/cclsp
Performs manual hands-on testing of a web application using playwright-cli.
DebugBase/glance
Run E2E browser tests on any web application using Glance MCP.
getlago/lago-front
A skill your agent uses when asked to babysit, monitor, shepherd, or keep working on a GitHub pull request until it is green, review-ready, approved, mergeable, or ready to merge.
getlago/lago-front
Triage a CVE / Dependabot alert in a JS/TS project and recommend the least-invasive fix.
getlago/lago-front
Extract a Formik form section into a TanStack Form drawer with Zod validation, following the plan form migration pattern.
getlago/lago-front
Phase 2 of the loop pipeline for lago-front. An agent skill from getlago/lago-front.
getlago/lago-front
Cleanup phase of the loop pipeline for lago-front, for the worktree layout only.
getlago/lago-front
Harvest phase of the loop pipeline for lago-front. An agent skill from getlago/lago-front.
Works with
Categories
A skill your agent uses when the operator wants to verify in the browser that a change works — asks "how do I test this locally?", "give me the steps", "QA this", references a worktree/PR/ticket…. QA Session is an agent skill from getlago/lago-front.", "give me the steps", "QA this", references a worktree/PR/ticket built in this session, or reports something not working during manual testing (button does nothing, section missing, block blank).
QA Session fits situations like: the operator wants to verify in the browser that a change works — asks how do I test this locally?; give me the steps; references a worktree/PR/ticket built in this session; reports something not working during manual testing (button does nothing.
Run `npx skills add getlago/lago-front --skill qa-session -a claude-code`. Or copy the skill folder (.agents/skills/qa-session in getlago/lago-front) into .claude/skills/qa-session in your project. Claude Code loads it when a task matches its description.
Run `npx skills add getlago/lago-front --skill qa-session -a codex`. Or copy the skill folder (.agents/skills/qa-session in getlago/lago-front) into .agents/skills/qa-session in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add getlago/lago-front --skill qa-session -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/qa-session, .gemini/skills/qa-session, .github/skills/qa-session and .opencode/skills/qa-session in your project.
Going by SKILL.md and its folder, QA Session needs the command-line tools its instructions call (git, docker and gh). Our summary lists: Docker.
SKILL.md contains no URLs. Its commands use git, docker and gh, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
QA Session is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.8k tokens (SKILL.md is roughly 15k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with QA Session: Diagnose Playwright Failure as Product Bug (appsmithorg/appsmith, 41k stars), Evidence-Driven Testing (michaelshimeles/skills, 1.3k stars), Verify Omnigent End-to-End (omnigent-ai/omnigent, 11k stars) and Verify (morapelker/hive, 470 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
getlago (a GitHub organization) maintains it in getlago/lago-front, which has 163 GitHub stars. The repository holds 17 skills in this directory. The repository was last updated on October 7, 2026.
Source: getlago/lago-front on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.