Install
openclaw skills install @bergschloss/product-ux-auditAudit product logic, UX heuristics, user flows, edge cases, and modularity for a specified feature or flow, with read-only multi-phase analysis.
openclaw skills install @bergschloss/product-ux-auditUse this skill when the user asks for:
STRICT READ-ONLY: Never modify, refactor, or create files inside the project repository. Only write reports to the _Reports output folder. Do not run mutating commands, migrations, or scripts.
For security/auth/crypto/data-integrity audits, use forensic-audit instead. For pure code-quality/refactor reviews, use code-review or simplify.
Produce a structured, evidence-based audit of how a product (or a specific feature/flow) behaves from the user's and business's perspective — independent of whether the code is "secure" or "clean". Goals:
apps/web client-facing, apps/desktop client, apps/desktop-operator, apps/desktop-admin). Carry this per-flow app/persona label through every phase — e.g. don't apply Phase 2's elderly-client accessibility lens (#11) to an apps/desktop-operator/apps/desktop-admin screen unless evidence suggests the same users use it.$outDir = "$env:USERPROFILE\Desktop\_Reports\product-audit_$(Get-Date -Format 'yyyy-MM-dd_HHmm')". Create it; abort if it fails.git rev-parse --short HEAD, git branch --show-current, git status --short.# Next.js 14 App Router pages/routes + Fastify API routes
rg --files apps/web/src/app apps/api/src --glob "page.tsx" --glob "route.ts" --glob "*.ts"
rg "app\.(get|post|put|delete|patch)|fastify\.(get|post|put|delete|patch)|export default function" --type ts --type tsx -l
# Electron IPC bridges & SSE streams (apps/desktop*, apps/api)
rg "ipcMain\.handle|ipcRenderer\.invoke|reply\.raw\.write|text/event-stream" --type ts -l
apps/*/src layout first if unfamiliar).
Use Glob to check whether each in-scope page.tsx has sibling loading.tsx/error.tsx/not-found.tsx (App Router convention for loading/error UI) — note absences for Phase 3.# Stubs / unfinished logic
rg "TODO|FIXME|not implemented|HACK" --type ts --type tsx
# Silent failure / swallowed errors
rg "catch\s*\(.*\)\s*\{\s*\}" --type ts --type tsx
# Where error/loading states exist (and by omission, where they don't)
rg "isLoading|isPending|isError|skeleton|Spinner" --type tsx -l
rg "catch|onError|throw new Error" --type ts --type tsx -l
# Duplicated validation (cross-check FE vs BE in Phase 5)
rg "\.min\(|\.max\(|\.required\(|z\.string\(\)" --type ts --type tsx -l
# [Phase Title]
**Date**: YYYY-MM-DD HH:MM
**Repo**: [repo root path]
**Git HEAD**: [short hash] ([branch])
**Scope**: [feature/flow(s) under audit]
---
[file:line or screen/step] SEVERITY — short title
**Observed**: what the code/UI actually does (cite file:line)
**Expected/Standard**: what product logic, heuristic, or convention implies
**User impact**: confusion, data loss, dead end, inconsistent state, etc.
**Fix direction**: concrete next step (no code unless trivial)
Severity: CRITICAL / HIGH / MEDIUM / LOW / NOTE. Severity reflects user/business impact, not exploitability.
A finding is actionable only if it has a concrete file:line / screen reference AND a specific, real consequence for a user or the business. Generic UX best-practice statements without a concrete anchor in this codebase are not findings — drop them or fold them into context for an actionable one.
[CheckoutForm.tsx:142] MEDIUM — submit button stays enabled during pending request, allowing duplicate charges on double-clickRole: Senior Product Strategist + Solution Architect.
Deliverable: $outDir\audit_0_flow-map.md — table of flows, steps, files, roles, external deps.
Role: Senior Product Strategist (prompt source: "Product Logic Audit").
For each in-scope flow, check:
Deliverable: $outDir\audit_1_product-logic.md — findings in standard format, severity = Critical/High/Medium/Low.
Role: UX Expert.
For each in-scope screen/flow, score 1-10 against each heuristic and give 1-2 concrete improvements where score < 8:
text-xs, arbitrary text-[Npx]), and are destructive/irreversible actions (cancel session, delete account, end call) clearly confirmed rather than a single accidental tap? Skip this heuristic for operator/admin-only screens unless evidence suggests the same concern applies.Base scores on actual component code/markup (loading states, error messages, confirmation dialogs, copy, Tailwind classes), not assumptions.
Deliverable: $outDir\audit_2_heuristics.md — per-screen table (heuristic × score × note) + summary of weakest 3 heuristics across the product.
Role: UX Forensic Analyst + QA Edge-Case Hunter.
For each in-scope flow:
queue-sse.ts), does the UI show a reconnecting/stale state when the connection drops, or does it silently show outdated data? For Electron apps, what happens when the app wakes from OS sleep — does it refetch/reconnect, or sit on a dead connection? Check whether the SSE handler registers reply.raw.on('close', ...) (or equivalent) to detect client disconnects, and whether the client's EventSource/SSE consumer has an onerror/reconnect path.ipcRenderer.invoke call fails or times out (e.g. RustDesk launch failure), does the renderer surface an error state, or does the UI hang in isLoading/spinner indefinitely? Also check the relevant BrowserWindow's webPreferences for contextIsolation: true — if it's missing or false, flag it (note in summary that depth coverage belongs to forensic-audit, but a flow-breaking IPC bridge issue is in scope here).Deliverable: $outDir\audit_3_friction-edgecases.md — pain-point map (prioritized) + edge-case matrix (scenario | handled? | file:line | severity) + happy/unhappy path table.
Role: UX Researcher.
For the primary persona/goal in scope, produce:
Deliverable: $outDir\audit_4_journey-map.md.
Role: Solution Architect (prompt source: "Architecture Review" + "Modularization").
This is not a security pass (see forensic-audit for that). Focus on whether the codebase structure matches product structure:
@imma-help/db / @imma-help/desktop-shared and consumed via those packages — or does apps/web, apps/api, or an apps/desktop* app reach into another app's src directly, or duplicate DB/schema logic locally instead of importing the shared package?forensic-audit.Deliverable: $outDir\audit_5_architecture.md — module map (table: feature → primary files → cross-deps) + refactoring suggestions with rationale. Optional Mermaid diagram of flow/module boundaries.
Only run if the user provides competitor names, target industry, or specific standards to check against — do not invent competitors or fetch external data without being asked.
Deliverable: $outDir\audit_6_benchmark.md.
Before writing the master summary, validate every CRITICAL/HIGH finding from Phases 1, 2, 3, and 5.
Agent (subagent_type "claude", no shared context, read-only) per batch of findings. Give it only the finding text + repo path — not your reasoning. Ask it to verify each finding against the actual code/UI and answer for each: Confirmed / Overstated (downgrade severity) / Not an issue (drop), with a one-line reason.For Phase 2 (heuristic scores) specifically, challenge any score that seems to assume unverified intent — re-derive the score strictly from what's in the code/markup.
Apply the verdicts (drop/downgrade/keep) before building the rollup table. Note in the master summary how many findings were dropped/downgraded and why — this is a signal of audit quality, not a failure.
Write $outDir\audit_master_summary.md:
| Phase | CRITICAL | HIGH | MEDIUM | LOW | NOTE |
|----------------------|----------|------|--------|-----|------|
| 1 Product Logic | N | N | N | N | N |
| 3 Friction/Edgecases | N | N | N | N | N |
| 5 Architecture | N | N | N | N | N |
| TOTAL | N | N | N | N | N |
After all phase files and the master summary are written, concatenate everything into one combined file: $outDir\FINAL_product-audit_$(Get-Date -Format 'yyyy-MM-dd_HHmm').md.
Order: audit_master_summary.md first, then audit_0_flow-map.md, audit_1_product-logic.md, audit_2_heuristics.md, audit_3_friction-edgecases.md, audit_4_journey-map.md (if produced), audit_5_architecture.md, audit_6_benchmark.md (if produced) — separate each section with a --- and a # <original filename> heading so the source phase stays traceable. This single file is the primary artifact to hand to the user; the per-phase files remain for traceability/reference.
$outDir under _Reports.