Install any skill in seconds. Free to start, no credit card required.
Get Started Free →State-first design pass — inventories and implements all non-happy states (loading, empty, error, partial, conflict, offline) before the happy path, and refactors impossible boolean state to proper state machines. Use when starting a new screen, reviewing an existing one for edge-case gaps, or when the user says "handle the error state" / "add loading states" / "what happens when data is missing". Invoke when the user asks for unhappy on their UI, or mentions 'unhappy' alongside design / UI / fr
.claude/skills/educlopez-unhappy/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 4% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 17% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 26% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 11% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 64% | 0% |
<!-- HARNESS MIRROR — do not edit here. Canonical source: skills/ or commands/. After editing source, copy into cli/assets/<harness>/ and repo-root harness mirrors. -->
Context: this sub-skill is one lens of the broader ui-craft skill. If the ui-craft skill is also installed, read its SKILL.md first for Discovery + Anti-Slop + Craft Test, then apply the specific lens below.
Design every non-happy state for the UI at $ARGUMENTS. Load the ui-craft skill and read references/state-design.md.
Step 1 — Inventory. List every data source and interactive surface in the target. For each, enumerate its states:
| Surface | idle | loading | empty | error | partial | conflict | offline | |---------|------|---------|-------|-------|---------|----------|---------|
Mark each cell as designed (exists in code), missing (must add), or N/A (not applicable — e.g., a read-only view has no conflict state).
Step 2 — Fill the missing states. For each missing state, either stub it inline or add a follow-up task comment. Use references/state-design.md for:
Step 3 — Audit the happy path. Flag every spot where the happy path assumes resource presence without checking. Fix with early-returns, state guards, or discriminated-union state handling. Booleans like isLoading && !error && data that allow impossible states are findings — refactor to a proper state machine or reducer.
Step 4 — Optimistic UI + reconciliation. For offline-likely actions (saves, sends, edits, toggles), implement optimistic UI with reconciliation on reconnect. Queue writes locally. Surface any rejected writes — never swallow them.
Knob gating (CRAFT_LEVEL):
| CRAFT_LEVEL | Required states to stub | |-------------|-------------------------| | ≤ 4 | idle, loading, error | | 5-7 | idle, loading, empty, error, success | | 8+ | all six — add partial, conflict, offline |
If CRAFT_LEVEL is unknown, default to 7.
Convergence note: To iterate until all required states are present, load skills/ui-craft/references/loops.md and run preset state-coverage (budget = the default loop budget defined in loops.md): after stubbing the highest-priority missing required state, re-inventory until all knob-required states are present or budget exhausted. Emit the pre-flight cost notice before iteration 1.
Output: edit the code directly. After each file, print the Review Format table from SKILL.md:
| Before | After | Why | | --- | --- | --- | | no loading state on <ProjectList> | skeleton rows matching final layout, 200ms delay | prevents "is it broken?" perception; avoids CLS | | generic "Error" toast | inline error with specific cause + retry + support ID | recoverability (heuristic 9) |
One row per state added. No full diffs.
Next step: /harden — implement the states you just designed (rung 1).
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 21,714 | 4,987 | -77% | 1 | 1 | 0% | 5,243 | 975 | -81% | 0 | 0 | — |
case-06 | pass→pass | 16,898 | 27,010 | +60% | 1 | 1 | 0% | 2,754 | 6,958 | +153% | 0 | 0 | — |
case-02 | fail→fail | 5,163 | 4,408 | -15% | 1 | 1 | 0% | 286 | 977 | +242% | 0 | 0 | — |
case-03 | fail→fail | 22,880 | 4,160 | -82% | 1 | 1 | 0% | 4,472 | 950 | -79% | 0 | 0 | — |
case-04 | fail→fail | 28,172 | 4,455 | -84% | 1 | 1 | 0% | 6,195 | 1,066 | -83% | 0 | 0 | — |
case-05 | fail→pass | 7,158 | 2,799 | -61% | 1 | 1 | 0% | 1,240 | 1,291 | +4% | 0 | 0 | — |
case-07 | fail→fail | 13,883 | 5,720 | -59% | 1 | 1 | 0% | 2,806 | 1,162 | -59% | 0 | 0 | — |
case-08 | pass→pass | 7,655 | 10,011 | +31% | 1 | 1 | 0% | 1,514 | 2,682 | +77% | 0 | 0 | — |
case-09 | pass→pass | 8,557 | 10,160 | +19% | 1 | 1 | 0% | 1,636 | 2,714 | +66% | 0 | 0 | — |
case-10 | pass→fail | 7,770 | 5,471 | -30% | 1 | 1 | 0% | 1,645 | 1,082 | -34% | 0 | 0 | — |
case-11 | pass→fail | 16,633 | 5,058 | -70% | 1 | 1 | 0% | 2,708 | 1,108 | -59% | 0 | 0 | — |
case-12 | pass→pass | 3,819 | 1,097 | -71% | 1 | 1 | 0% | 613 | 950 | +55% | 0 | 0 | — |
case-13 | fail→pass | 7,329 | 4,671 | -36% | 1 | 1 | 0% | 1,239 | 1,450 | +17% | 0 | 0 | — |
case-14 | pass→fail | 10,238 | 4,440 | -57% | 1 | 1 | 0% | 1,903 | 1,031 | -46% | 0 | 0 | — |
case-15 | fail→pass | 7,532 | 4,973 | -34% | 1 | 1 | 0% | 1,232 | 1,556 | +26% | 0 | 0 | — |
case-16 | pass→pass | 17,690 | 9,926 | -44% | 1 | 1 | 0% | 3,197 | 2,541 | -21% | 0 | 0 | — |
case-17 | fail→pass | 11,040 | 7,702 | -30% | 1 | 1 | 0% | 1,996 | 2,217 | +11% | 0 | 0 | — |
case-18 | fail→pass | 7,965 | 8,732 | +10% | 1 | 1 | 0% | 1,629 | 2,668 | +64% | 0 | 0 | — |
case-19 | pass→pass | 11,078 | 10,627 | -4% | 1 | 1 | 0% | 2,005 | 2,544 | +27% | 0 | 0 | — |
case-20 | pass→pass | 16,739 | 17,726 | +6% | 1 | 1 | 0% | 3,561 | 4,201 | +18% | 0 | 0 | — |
case-21 | pass→fail | 9,011 | 4,213 | -53% | 1 | 1 | 0% | 1,965 | 1,007 | -49% | 0 | 0 | — |
case-22 | pass→fail | 23,293 | 4,326 | -81% | 1 | 1 | 0% | 2,563 | 969 | -62% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 12 counted toward the lift figure. The other 10 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of 0 percentage points is the difference between those two pass rates over the 12 comparable cases. 5 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.