From Flagrare
Drives a real browser through every reachable route from a first-time user's perspective, capturing screenshots and producing a severity-ranked UX findings table with location, diagnosis, and fix suggestions.
How this skill is triggered — by the user, by Claude, or both
Slash command
/flagrare:ux-auditThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A goal-driven walkthrough of the running app from a first-time user's perspective. The pass ends only when every reachable route has been visited, every visible affordance on those routes has been exercised, and every observation has been logged with a severity, a location, a reason, and a recommended fix.
A goal-driven walkthrough of the running app from a first-time user's perspective. The pass ends only when every reachable route has been visited, every visible affordance on those routes has been exercised, and every observation has been logged with a severity, a location, a reason, and a recommended fix.
This is not a smoke test (which validates a single feature against acceptance criteria) and not an accessibility audit (which has its own tooling). This skill answers a different question: if a real human picked up this app cold and tried to use it, where would they stumble, hesitate, get confused, or feel patronized?
The persona matters. Drop the engineer-with-context lens; adopt the new-user lens. A button labelled Set Your Light is not "clear because the team decided" — it is jargon to the new user. Record it as jargon.
Teams ship features they can no longer see. Designers, PMs, and engineers all develop blindness to their own product — they know which button does what, so they stop noticing that the button is mislabelled, that the empty state is hostile, that the "Ash" mode is a void, that the modal traps the user, that the toast says "this project has been quiet for weeks" about a project the user created twelve seconds ago. Static checks don't catch these. Unit tests don't catch these. PRs don't catch these. A human cold-walking the app catches them — but humans are expensive and forget what they noticed five minutes later.
This skill is the cheap, consistent, written-down version of that walk. The output is a markdown artifact (not a slide deck, not a JIRA dump) that the team can read, prioritise, and act on the same day.
Hard requirement. Before any other tool call, you MUST call /goal yourself. This is not a suggestion to the user. You, the executing model, must invoke the goal tool directly. Without it, context compaction and turn limits will cause early termination -- the audit visits 15-40 routes and the model will quit by route 5 without a durable goal holding it in place.
The user may specify a scope when invoking the skill:
Call /goal with text adapted to the scope:
Full scope (default):
Drive the running app from a first-time user's perspective. Exhaust every reachable route and every visible affordance on those routes. Produce a severity-ranked findings table in
.ux-audit/FINDINGS.mdalong with numbered screenshots. Do not stop until coverage is complete.
Scoped:
Drive the running app from a first-time user's perspective. Exhaust every route and affordance within: [user's specified scope]. Produce a severity-ranked findings table in
.ux-audit/FINDINGS.mdalong with numbered screenshots. Do not stop until coverage of the specified scope is complete.
After setting the goal, also create a Todo list (one item per route within scope, populated in Step 2). The Todo list tracks coverage; the goal prevents the harness from letting you stop. Both are required. Neither is optional.
Chrome DevTools MCP must be available. This skill requires take_screenshot, take_snapshot, navigate_page, and click/fill from Chrome DevTools MCP. If the tools are not available in this session, fix it yourself without blocking. Be fully autonomous -- do not stop and wait for the user at any point in this checklist.
A. Is the chrome-devtools-mcp plugin installed?
chrome-devtools-mcp:chrome-devtools in the available skills listnpm i -g chrome-devtools-mcp@latest (disable sandbox) → npm i -g chrome-devtools-mcp@latest --prefix ~/.local (if EACCES) → pnpm add -g chrome-devtools-mcp@latestB. Is Chrome running with remote debugging?
open -a "Google Chrome" --args --remote-debugging-port=9222google-chrome --remote-debugging-port=9222 &pkill -f "Google Chrome" (macOS) or pkill chrome (Linux), wait 2 seconds, then launch with the flag.C. Are the MCP tools appearing?
chrome-devtools-mcp:chrome-devtools-cli skill if available, or run chrome-devtools status to verify connection./reload-plugins -- Chrome is now running with debugging, but Claude Code needs to reconnect its MCP server." This is the ONE thing that may require user action.D. While waiting for reload (if needed), start Step 2.
Rules:
/reload-plugins or restarting Claude Code if the MCP server won't connect after Chrome is running.Dev server must be running. Check if it's already running (lsof -i :3000 or similar for common ports, or check the project's package.json scripts for the dev port). If not running, start it yourself in the background. If it requires specific env vars or setup you can't determine, ask the user for the start command -- but try npm run dev or pnpm dev first.
The app's filesystem is the source of truth for reachable pages. Scan it before opening a browser. If a scope was specified in Step 1, filter the route list to only routes within that scope (but still enumerate from source to ensure nothing is missed within the scoped area).
Detect the framework from the project layout:
| Layout | Framework | Where routes live |
|---|---|---|
src/routes/**/+page.svelte | SvelteKit | find src/routes -name '+page.svelte' |
src/app/**/page.tsx | Next.js App Router | find src/app -name 'page.tsx' |
pages/**/*.tsx | Next.js Pages Router | find pages -name '*.tsx' -not -path '*/api/*' |
src/pages/**/*.vue | Nuxt / Vite-Vue | find src/pages -name '*.vue' |
app/views/**/*.html.erb | Rails | find app/views -name '*.html.erb' |
templates/**/*.html | Django / Flask | find templates -name '*.html' |
src/routes.ts / App.tsx with <Route> | React Router | grep -r 'path=' src/ | grep -i route |
If the framework isn't on this list, look for a router/config file and ask the user where routes live. Don't guess — a missed route is a missed finding.
Filter out:
/api/*, controller files without templates)Produce a flat list of URLs to visit. Note which are auth-gated. If you don't know which test credentials to use, ask the user once — don't try to register your own account silently unless the app supports self-serve signup and the user confirmed it's OK.
Use Chrome DevTools MCP for this skill — not Playwright. Chrome DevTools gives you the accessibility tree (take_snapshot), screenshots (take_screenshot), console messages, network requests, and direct click/fill/navigate. Playwright is for converting findings into permanent specs later (out of scope here).
The user must be able to see what you are doing. After connecting to Chrome DevTools:
bringToFront: true or the equivalent option on every navigate_page call. The user should be watching the audit happen in real time -- if they can't see it, something is wrong.Set the viewport. Default to mobile-first (390x844, iPhone 14) unless the user explicitly says desktop or the app has no responsive layout. Most modern apps are used on a phone; auditing only at desktop misses the entire mobile experience.
Create the output folder:
mkdir -p .ux-audit
All screenshots and the findings file live here. Numbered prefixes (01-landing.png, 02-register.png, ...) so they sort chronologically.
Open the start URL and take_snapshot to confirm the page rendered. Capture the title and visible structure. If the page is blank or 500s, stop — fix the server before continuing.
For every route in your enumerated list, do this loop:
navigate_page to the route's URL..ux-audit/NN-route-name.png. (Use Read on the screenshot afterward — your judgment depends on actually seeing it.)take_snapshot) to enumerate every interactive element by uid.Treat each of these as a candidate finding. Most will be real; document them with severity even when the team will defend the choice — the team can override, but the audit must be honest.
The full heuristic list lives in references/finding-triggers.md. Read it once at the start of a long audit; refer back when in doubt.
The discipline that makes this skill useful: append findings to .ux-audit/FINDINGS.md after every route, not in one big batch at the end. The reason is mechanical — by route 15, you will have forgotten the texture of route 3. Write while it's fresh.
Use the template at references/findings-template.md to create the file once at the start. Each finding gets one row in the table:
| # | Severity | Location | Issue | Why it's painful | Recommended fix |
|---|----------|----------|-------|------------------|-----------------|
| L01 | Medium | `/login` | Browser-native HTML5 tooltip on dark theme | Light bubble obscures submit button on mobile | Inline validation with app's existing toast pattern |
ID prefix conventions (totally optional but useful for grep later):
L## landing/marketingR## register / A## authON## onboardingT## today / dashboardF## fleet / list pageSeverity rubric (from references/severity-rubric.md):
Resist the urge to inflate everything to High. The summary is more useful when the High list is short and damning.
After the route loop is complete, write the Executive Summary at the top of .ux-audit/FINDINGS.md (above the table). This is the deliverable most teams will actually read.
Include:
The summary is the only thing some stakeholders will read. Make it self-contained — they should be able to understand the state of the app without reading the table.
End the audit with one short message to the user:
FINDINGS.mdDo not propose fixes inline (the table already does that). Do not start implementing fixes (that's a different skill — /flagrare:atdd-plan). The audit's job is to surface; the team's job is to triage.
The hardest part of this skill is not stopping early. Models default to "I've seen enough." That's wrong here — the goal is exhaustive, not representative. Patterns to combat early termination:
/goal was already called in Step 1. If for any reason it wasn't, call it now. It blocks termination until the goal text holds true.This skill is intentionally rigid about coverage but flexible about technique. Adapt these freely:
After this skill runs, the project contains:
.ux-audit/
├── FINDINGS.md ← table + executive summary
├── 01-landing.png
├── 02-register.png
├── …
└── NN-final-state.png
That's the whole deliverable. No JSON, no slides, no separate triage file. One markdown, one folder of screenshots, ready to drop into Slack / Notion / PR review.
npx claudepluginhub flagrare/agent-skills --plugin flagrareProvides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.