unhappypath
What this skill does
Runs the unhappypath scanner — a deterministic CLI that finds missing unhappy-path UI in Next.js/React apps:
- Loading — user sees blank screen while data fetches
- Empty — list renders nothing with no explanation or CTA
- Error — API failure shows no message or retry
- Pending — buttons/forms allow double-submit
It does not run the browser or call an LLM. It reads source files and reports findings with file + line + rule ID.
Prerequisites
Install or build unhappypath once:
# From npm (when published)
npx unhappypath --help
# From clone
git clone https://github.com/paladini/unhappypath.git
cd unhappypath && npm ci && npm run build
# then use: node /path/to/unhappypath/dist/cli.js .
Workflow (follow exactly)
Scan from the user's app root (where
package.jsonis):npx unhappypath . # or: node /path/to/unhappypath/dist/cli.js .Parse output — note score, band, and every finding (
RTE-*,QRY-*,MUT-*,FRM-*).Fix in priority order:
- Routes (
RTE-*) — addloading.tsx,error.tsx,not-found.tsx,global-error.tsx - Queries (
QRY-*) — addif (isLoading),if (isError), empty-data branches - Mutations (
MUT-*) — disable buttons while pending; never use emptycatch {} - Forms (
FRM-*) — wireisSubmitting/ disabled submit
- Routes (
Re-run until score ≥ target (default 75, production 90):
npx unhappypath . --min-score 75Report final score and list any remaining findings.
Fix recipes
| ID | Fix |
|---|---|
| RTE-01 | Add loading.tsx in route segment or parent app/ |
| RTE-02 | Add not-found.tsx; use notFound() for missing resources |
| RTE-03 | Add 'use client' error.tsx with reset() retry button |
| RTE-04 | Add app/global-error.tsx |
| QRY-01 | if (isLoading) return <Loading /> |
| QRY-02 | if (isError) return <ErrorUI error={error} /> |
| QRY-03 | if (!data?.length) return <EmptyState /> |
| MUT-02 | disabled={pending} + pending state around async handler |
| FRM-01 | disabled={isSubmitting} on submit button |
Full catalog: https://github.com/paladini/unhappypath/blob/main/docs/FINDINGS.md
Rules
- Always run the CLI — never substitute an LLM-based code review for unhappypath.
- Prefer minimal diffs in flagged files unless a shared wrapper (e.g.
<UIStates>) is clearly better. - Prefer skeletons over spinners for loading; always offer retry on errors.
- If a finding looks like a false positive, note the ID and explain why — do not silently ignore.