jdi-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/AGENTS.md +209 -0
  2. package/ARCHITECTURE.md +210 -0
  3. package/COMMANDS.md +241 -0
  4. package/CREATE-EXAMPLE.md +385 -0
  5. package/CREATE.md +315 -0
  6. package/EXTENSION.md +141 -0
  7. package/LICENSE +21 -0
  8. package/MEMORY.md +471 -0
  9. package/PORTABILITY.md +438 -0
  10. package/README.md +789 -0
  11. package/bin/git-hooks/post-commit +16 -0
  12. package/bin/git-hooks/pre-commit +21 -0
  13. package/bin/jdi-build.ps1 +381 -0
  14. package/bin/jdi-build.sh +332 -0
  15. package/bin/jdi-doctor.ps1 +403 -0
  16. package/bin/jdi-doctor.sh +400 -0
  17. package/bin/jdi-install-caveman.ps1 +97 -0
  18. package/bin/jdi-install-caveman.sh +99 -0
  19. package/bin/jdi-install-playwright.ps1 +319 -0
  20. package/bin/jdi-install-playwright.sh +284 -0
  21. package/bin/jdi-install.ps1 +154 -0
  22. package/bin/jdi-install.sh +132 -0
  23. package/bin/jdi-uninstall.ps1 +309 -0
  24. package/bin/jdi-uninstall.sh +264 -0
  25. package/bin/jdi-update.ps1 +215 -0
  26. package/bin/jdi-update.sh +209 -0
  27. package/bin/jdi.js +460 -0
  28. package/bin/lib/jdi-monitor.ps1 +66 -0
  29. package/bin/lib/jdi-monitor.sh +74 -0
  30. package/bin/lib/jdi-truncate.ps1 +96 -0
  31. package/bin/lib/jdi-truncate.sh +99 -0
  32. package/bin/lib/ui.js +197 -0
  33. package/core/agents/jdi-adopter.md +465 -0
  34. package/core/agents/jdi-architect.md +894 -0
  35. package/core/agents/jdi-asker.md +153 -0
  36. package/core/agents/jdi-bootstrap.md +247 -0
  37. package/core/agents/jdi-planner.md +254 -0
  38. package/core/agents/jdi-researcher.md +303 -0
  39. package/core/commands/jdi-adopt.md +155 -0
  40. package/core/commands/jdi-bootstrap.md +81 -0
  41. package/core/commands/jdi-create.md +80 -0
  42. package/core/commands/jdi-discuss.md +80 -0
  43. package/core/commands/jdi-do.md +200 -0
  44. package/core/commands/jdi-loop.md +315 -0
  45. package/core/commands/jdi-new.md +131 -0
  46. package/core/commands/jdi-plan.md +73 -0
  47. package/core/commands/jdi-ship.md +146 -0
  48. package/core/commands/jdi-verify.md +159 -0
  49. package/core/skills/clean-code/SKILL.md +261 -0
  50. package/core/skills/dry/SKILL.md +150 -0
  51. package/core/skills/frontend-rules/SKILL.md +386 -0
  52. package/core/skills/frontend-validator/SKILL.md +567 -0
  53. package/core/skills/kiss/SKILL.md +178 -0
  54. package/core/skills/solid/SKILL.md +281 -0
  55. package/core/skills/yagni/SKILL.md +207 -0
  56. package/core/templates/agent.md +72 -0
  57. package/core/templates/doer-specialist.md +216 -0
  58. package/core/templates/reviewer-specialist.md +405 -0
  59. package/core/templates/skill.md +66 -0
  60. package/package.json +70 -0
  61. package/runtimes/antigravity/agents.md +74 -0
  62. package/runtimes/antigravity/skills/clean-code/SKILL.md +252 -0
  63. package/runtimes/antigravity/skills/dry/SKILL.md +141 -0
  64. package/runtimes/antigravity/skills/frontend-rules/SKILL.md +376 -0
  65. package/runtimes/antigravity/skills/frontend-validator/SKILL.md +559 -0
  66. package/runtimes/antigravity/skills/jdi-adopt/SKILL.md +155 -0
  67. package/runtimes/antigravity/skills/jdi-adopter/SKILL.md +436 -0
  68. package/runtimes/antigravity/skills/jdi-architect/SKILL.md +872 -0
  69. package/runtimes/antigravity/skills/jdi-asker/SKILL.md +125 -0
  70. package/runtimes/antigravity/skills/jdi-asker/references/context-template.md +34 -0
  71. package/runtimes/antigravity/skills/jdi-asker/references/decision-format.md +19 -0
  72. package/runtimes/antigravity/skills/jdi-asker/scripts/find_phase_dir.sh +25 -0
  73. package/runtimes/antigravity/skills/jdi-bootstrap/SKILL.md +81 -0
  74. package/runtimes/antigravity/skills/jdi-create/SKILL.md +80 -0
  75. package/runtimes/antigravity/skills/jdi-discuss/SKILL.md +80 -0
  76. package/runtimes/antigravity/skills/jdi-discuss/scripts/run_command.sh +62 -0
  77. package/runtimes/antigravity/skills/jdi-do/SKILL.md +200 -0
  78. package/runtimes/antigravity/skills/jdi-loop/SKILL.md +315 -0
  79. package/runtimes/antigravity/skills/jdi-new/SKILL.md +131 -0
  80. package/runtimes/antigravity/skills/jdi-plan/SKILL.md +73 -0
  81. package/runtimes/antigravity/skills/jdi-planner/SKILL.md +225 -0
  82. package/runtimes/antigravity/skills/jdi-researcher/SKILL.md +274 -0
  83. package/runtimes/antigravity/skills/jdi-ship/SKILL.md +146 -0
  84. package/runtimes/antigravity/skills/jdi-verify/SKILL.md +159 -0
  85. package/runtimes/antigravity/skills/kiss/SKILL.md +169 -0
  86. package/runtimes/antigravity/skills/solid/SKILL.md +272 -0
  87. package/runtimes/antigravity/skills/yagni/SKILL.md +198 -0
  88. package/runtimes/claude/CLAUDE.md +91 -0
  89. package/runtimes/claude/agents/jdi-adopter.md +430 -0
  90. package/runtimes/claude/agents/jdi-architect.md +864 -0
  91. package/runtimes/claude/agents/jdi-asker.md +119 -0
  92. package/runtimes/claude/agents/jdi-bootstrap.md +213 -0
  93. package/runtimes/claude/agents/jdi-planner.md +221 -0
  94. package/runtimes/claude/agents/jdi-researcher.md +269 -0
  95. package/runtimes/claude/commands/jdi-adopt.md +155 -0
  96. package/runtimes/claude/commands/jdi-bootstrap.md +81 -0
  97. package/runtimes/claude/commands/jdi-create.md +80 -0
  98. package/runtimes/claude/commands/jdi-discuss.md +80 -0
  99. package/runtimes/claude/commands/jdi-do.md +200 -0
  100. package/runtimes/claude/commands/jdi-loop.md +315 -0
  101. package/runtimes/claude/commands/jdi-new.md +131 -0
  102. package/runtimes/claude/commands/jdi-plan.md +73 -0
  103. package/runtimes/claude/commands/jdi-ship.md +146 -0
  104. package/runtimes/claude/commands/jdi-verify.md +159 -0
  105. package/runtimes/claude/settings.example.json +132 -0
  106. package/runtimes/claude/skills/clean-code/SKILL.md +247 -0
  107. package/runtimes/claude/skills/dry/SKILL.md +136 -0
  108. package/runtimes/claude/skills/frontend-rules/SKILL.md +369 -0
  109. package/runtimes/claude/skills/frontend-validator/SKILL.md +553 -0
  110. package/runtimes/claude/skills/kiss/SKILL.md +164 -0
  111. package/runtimes/claude/skills/solid/SKILL.md +267 -0
  112. package/runtimes/claude/skills/yagni/SKILL.md +193 -0
  113. package/runtimes/copilot/agents/jdi-adopter.agent.md +430 -0
  114. package/runtimes/copilot/agents/jdi-architect.agent.md +864 -0
  115. package/runtimes/copilot/agents/jdi-asker.agent.md +119 -0
  116. package/runtimes/copilot/agents/jdi-bootstrap.agent.md +213 -0
  117. package/runtimes/copilot/agents/jdi-planner.agent.md +221 -0
  118. package/runtimes/copilot/agents/jdi-researcher.agent.md +269 -0
  119. package/runtimes/copilot/copilot-instructions.md +80 -0
  120. package/runtimes/copilot/prompts/jdi-adopt.prompt.md +155 -0
  121. package/runtimes/copilot/prompts/jdi-bootstrap.prompt.md +81 -0
  122. package/runtimes/copilot/prompts/jdi-create.prompt.md +80 -0
  123. package/runtimes/copilot/prompts/jdi-discuss.prompt.md +80 -0
  124. package/runtimes/copilot/prompts/jdi-do.prompt.md +200 -0
  125. package/runtimes/copilot/prompts/jdi-loop.prompt.md +315 -0
  126. package/runtimes/copilot/prompts/jdi-new.prompt.md +131 -0
  127. package/runtimes/copilot/prompts/jdi-plan.prompt.md +73 -0
  128. package/runtimes/copilot/prompts/jdi-ship.prompt.md +146 -0
  129. package/runtimes/copilot/prompts/jdi-verify.prompt.md +159 -0
  130. package/runtimes/opencode/AGENTS.md +87 -0
  131. package/runtimes/opencode/agents/jdi-adopter.md +434 -0
  132. package/runtimes/opencode/agents/jdi-architect.md +861 -0
  133. package/runtimes/opencode/agents/jdi-asker.md +123 -0
  134. package/runtimes/opencode/agents/jdi-bootstrap.md +217 -0
  135. package/runtimes/opencode/agents/jdi-planner.md +225 -0
  136. package/runtimes/opencode/agents/jdi-researcher.md +273 -0
  137. package/runtimes/opencode/commands/jdi-adopt.md +155 -0
  138. package/runtimes/opencode/commands/jdi-bootstrap.md +81 -0
  139. package/runtimes/opencode/commands/jdi-create.md +80 -0
  140. package/runtimes/opencode/commands/jdi-discuss.md +80 -0
  141. package/runtimes/opencode/commands/jdi-do.md +200 -0
  142. package/runtimes/opencode/commands/jdi-loop.md +315 -0
  143. package/runtimes/opencode/commands/jdi-new.md +131 -0
  144. package/runtimes/opencode/commands/jdi-plan.md +73 -0
  145. package/runtimes/opencode/commands/jdi-ship.md +146 -0
  146. package/runtimes/opencode/commands/jdi-verify.md +159 -0
  147. package/runtimes/opencode/opencode.example.jsonc +169 -0
  148. package/runtimes/opencode/skills/clean-code/SKILL.md +247 -0
  149. package/runtimes/opencode/skills/dry/SKILL.md +136 -0
  150. package/runtimes/opencode/skills/frontend-rules/SKILL.md +369 -0
  151. package/runtimes/opencode/skills/frontend-validator/SKILL.md +553 -0
  152. package/runtimes/opencode/skills/kiss/SKILL.md +164 -0
  153. package/runtimes/opencode/skills/solid/SKILL.md +267 -0
  154. package/runtimes/opencode/skills/yagni/SKILL.md +193 -0
  155. package/templates-jdi-folder/config.json +18 -0
  156. package/templates-jdi-folder/registry.md +31 -0
  157. package/templates-jdi-folder/reviewers.md +33 -0
  158. package/templates-jdi-folder/skills-registry.md +32 -0
  159. package/templates-jdi-folder/specialists.md +39 -0
@@ -0,0 +1,150 @@
1
+ ---
2
+ name: dry
3
+ description: DRY (Don't Repeat Yourself). 1 source of truth per piece of knowledge. Detects real duplication (same decision in 2+ places) and separates from apparent duplication (same code, different reasons). Applies in any language.
4
+ type: skill
5
+ applies_to: |
6
+ Loaded by doer before writing new code.
7
+ Loaded by reviewer at gate 5 to detect duplication in diff.
8
+ loaded_by:
9
+ - jdi-doer-{slug}
10
+ - jdi-reviewer-{slug}
11
+ runtime_overrides:
12
+ antigravity:
13
+ triggers:
14
+ - "DRY"
15
+ - "code duplication"
16
+ - "Don't Repeat Yourself"
17
+ - "duplicate refactor"
18
+ ---
19
+
20
+ # Skill: DRY
21
+
22
+ > Every piece of knowledge has **one** authoritative, unambiguous representation in the system.
23
+
24
+ DRY is not about copying code. It's about **duplicated knowledge** — business rule, formula, format, decision, present in 2+ places and that change **together** when the requirement changes.
25
+
26
+ ## Rules
27
+
28
+ ### 1. Knowledge duplication != code coincidence
29
+
30
+ **Knowledge duplication (violates DRY):**
31
+ - Tax calculation in 2 places
32
+ - CPF validation in 3 services
33
+ - Date format schema scattered across the app
34
+ - Same timeout constant in 4 files
35
+
36
+ When the rule changes, you change in N places — miss one, system becomes inconsistent.
37
+
38
+ **Code coincidence (does NOT violate DRY):**
39
+ - 2 functions with 5 identical lines but different domains
40
+ - Framework boilerplate repeated (every controller has `[Authorize]`)
41
+ - Similar iteration loop in 2 unrelated contexts
42
+
43
+ Forcing abstraction here couples things that shouldn't be coupled.
44
+
45
+ ### 2. Rule of 3
46
+
47
+ - 1 occurrence: leave it
48
+ - 2 occurrences: pay attention, but don't abstract yet
49
+ - 3 occurrences: abstract (probably real knowledge duplication)
50
+
51
+ Skipping this rule produces **premature abstraction** — worse than duplication because callers are already coupled to the wrong interface.
52
+
53
+ ### 3. Types of DRY
54
+
55
+ **Code DRY:** reusable functions/classes for repeated logic
56
+ **Data DRY:** 1 source schema (generates DTO + validator + DB + docs)
57
+ **Process DRY:** 1 build script that serves dev + CI + prod
58
+ **Documentation DRY:** docs generated from code, not written in parallel
59
+
60
+ ### 4. Single Source of Truth (SSoT)
61
+
62
+ For each piece of knowledge, identify:
63
+ - **Where the truth lives** (DB schema, env config, business rule)
64
+ - **Who derives from it** (DTOs, types, docs, UI)
65
+ - **Derivation tool** (codegen, schema migration, type inference)
66
+
67
+ Never: manually edit both the source and the derived.
68
+
69
+ ### 5. When NOT to apply DRY
70
+
71
+ - **Premature abstraction**: 2 similar callers but with diverging future evolutions -> leave duplicated
72
+ - **Cross-boundary**: duplicating across microservices > coupling via shared lib
73
+ - **Test setup**: readable redundant tests > shared magical helpers
74
+ - **Wrong abstraction**: better duplicate than extract wrong (Sandi Metz: "duplication is far cheaper than the wrong abstraction")
75
+
76
+ ## Anti-patterns
77
+
78
+ | Anti-pattern | Why it violates |
79
+ |---|---|
80
+ | Copy-paste without extraction after 3rd occurrence | Duplicated knowledge, each caller silently diverges |
81
+ | Utility helper with 15 unrelated functions | "DRY" became ball of mud — bundles unrelated things |
82
+ | Abstraction after 2nd duplication with extension hooks "just in case" | Premature abstraction + YAGNI violated together |
83
+ | Same constant hardcoded in 4 files | Single source of truth absent — extract to config |
84
+ | Validation logic duplicated client + server | Code OK, but should share schema (Zod, Pydantic, JSON Schema) |
85
+ | Comment explaining what code does | Doc duplicates code, will go out of sync |
86
+
87
+ ## Procedure
88
+
89
+ ### Doer (before writing)
90
+
91
+ 1. Is there an identical rule/calculation/constant elsewhere in the codebase? If so, refer/import. Don't duplicate.
92
+ 2. Going to create the 2nd occurrence? OK, but mentally mark it.
93
+ 3. Going to create the 3rd? Stop. Refactor first into abstraction, then use.
94
+
95
+ ### Reviewer (gate 5)
96
+
97
+ Per-language specific greps (examples):
98
+
99
+ ```bash
100
+ # Duplicated magic constants
101
+ grep -RnE '\b86400\b|\b3600\b|\b1024\b' src/
102
+
103
+ # Same string in 3+ places
104
+ sort src/ | uniq -c | sort -rn | head -20 # coarse heuristic
105
+
106
+ # Duplicated email/CPF/etc validation
107
+ grep -RnE 'regex.*@|EmailRegex|CpfValidator|cpf_pattern' src/
108
+
109
+ # Hardcoded URLs/endpoints
110
+ grep -RnE 'https?://[a-z0-9.-]+\.[a-z]{2,}' src/ --include='*.ts' --include='*.cs' --include='*.py'
111
+ ```
112
+
113
+ 3+ matches of the same pattern in different files -> WARN.
114
+
115
+ ## Inputs
116
+
117
+ - Diff or content of the modified file
118
+ - Context: project stack for adapted greps
119
+
120
+ ## Outputs
121
+
122
+ Does NOT produce a file. Modifies judgement:
123
+ - Doer chooses to reuse/extract
124
+ - Reviewer marks WARN with pointer to refactor
125
+
126
+ ## Examples
127
+
128
+ ### Example 1: 3 services calculating tax
129
+
130
+ Wrong:
131
+ ```
132
+ service A: total * 0.18
133
+ service B: amount * 0.18
134
+ service C: value * 0.18
135
+ ```
136
+
137
+ Right: extract `TaxCalculator.applyVat(amount)` or `const VAT_RATE = 0.18` in shared config.
138
+
139
+ Reviewer marks WARN: "tax 0.18 hardcoded in 3 services. Extract to `config/tax.{ts,cs,py}`."
140
+
141
+ ### Example 2: Code coincidence (does NOT violate DRY)
142
+
143
+ ```
144
+ function findUser(id) { return db.query(...) }
145
+ function findOrder(id) { return db.query(...) }
146
+ ```
147
+
148
+ Same structure, different domains. **Don't** extract `findEntity(id, table)` — will force abstraction that will diverge (user has soft-delete, order has cache, etc).
149
+
150
+ Reviewer ignores — code coincidence is OK.
@@ -0,0 +1,386 @@
1
+ ---
2
+ name: jdi-frontend-rules
3
+ description: Universal UI/UX and accessibility rules for any web interface. Framework-agnostic - works for React, Vue, Svelte, Solid, Angular, Blazor, Razor, Twig, Jinja, ERB, Blade, and any template engine. Based on WCAG 2.2 AA, Nielsen heuristics, Material/Apple HIG.
4
+ type: skill
5
+ applies_to: |
6
+ Loaded when PROJECT.md has `frontend.has_frontend: true`.
7
+ Doer applies as guide BEFORE writing/editing UI files.
8
+ Reviewer applies as checklist at gate 5 (security/perf rules) before gate 7 (UI live).
9
+ loaded_by:
10
+ - jdi-doer-{slug} (conditional on frontend.has_frontend)
11
+ - jdi-reviewer-{slug} (conditional on frontend.has_frontend)
12
+ runtime_overrides:
13
+ antigravity:
14
+ triggers:
15
+ - "frontend rules"
16
+ - "UI patterns"
17
+ - "web accessibility"
18
+ - "WCAG"
19
+ - "UX best practices"
20
+ - "validate interface"
21
+ ---
22
+
23
+ # Skill: jdi-frontend-rules
24
+
25
+ UI/UX standards that CANNOT be violated - regardless of stack. Concepts > syntax. Works for SPA, SSR, MPA, hybrid, any template engine.
26
+
27
+ ## When to apply
28
+
29
+ Whenever code touches a visible human interface:
30
+
31
+ - Files `.tsx, .jsx, .vue, .svelte, .astro, .qwik, .solid` (JS-based components)
32
+ - Files `.razor, .cshtml` (Blazor / Razor Pages / MVC)
33
+ - Files `.html, .twig, .jinja, .j2, .erb, .blade.php, .hbs, .liquid, .mustache, .ejs, .pug` (template engines)
34
+ - CSS/Tailwind/SCSS/Less affecting layout, contrast, focus, or accessibility
35
+ - ARIA / semantic HTML in any language
36
+
37
+ Does NOT apply to: API-only backends, CLI tools, services without UI.
38
+
39
+ ## Universal rules (hard gates)
40
+
41
+ ### 1. Accessibility - WCAG 2.2 level AA
42
+
43
+ All mandatory. Violation = BLOCK on review.
44
+
45
+ - **Color contrast**:
46
+ - Normal text: minimum 4.5:1 against background
47
+ - Large text (18pt+ or 14pt+ bold): minimum 3:1
48
+ - UI components and graphics: minimum 3:1
49
+ - Verify in hover/focus/disabled states too
50
+ - **Visible focus**: never `outline: none` or `outline: 0` without a replacement. Focus must be perceptible in strong light and on a cheap monitor. `:focus-visible` is the standard
51
+ - **Keyboard navigation**: 100% of interactions reachable via keyboard. Tab follows logical visual order. No trap (modal without Esc, dropdown without Escape/arrows)
52
+ - **Semantic HTML first**:
53
+ - `<button>` for action (even if styled as a link)
54
+ - `<a href>` for navigation (even if styled as a button)
55
+ - `<form>` for forms (Enter submits, native validation works)
56
+ - Headings in order (`h1` -> `h2` -> `h3`, no level skipping)
57
+ - `<nav>, <main>, <header>, <footer>, <aside>, <section>, <article>` when appropriate
58
+ - `<ul>/<ol>` for lists, not repeated `<div>`
59
+ - **ARIA when needed**:
60
+ - Icon-only button: `aria-label="descriptive action"`
61
+ - Form error: `role="alert"` or `aria-live="assertive"`
62
+ - Loading region: `aria-busy="true"` + `aria-live="polite"`
63
+ - Toggle/expand: `aria-expanded="true|false"` + `aria-controls`
64
+ - Modal: `role="dialog"` + `aria-modal="true"` + `aria-labelledby`
65
+ - Tooltip: `aria-describedby`
66
+ - ARIA NEVER REPLACES semantic HTML. ARIA only complements
67
+ - **Skip link**: first tab order offers "Skip to main content"
68
+ - **Minimum touch target**: 44x44 CSS px (Apple HIG / WCAG 2.5.5). Increase on mobile with `padding`, not margin
69
+ - **Color is not the only indicator**:
70
+ - Red error needs icon OR explicit text
71
+ - Colored link needs underline OR different visual weight
72
+ - Active nav state needs border/weight, not just color
73
+ - Color blindness affects 8% of men. Always color + shape + text
74
+ - **Form labels**: every `<input>, <textarea>, <select>` with:
75
+ - Associated `<label htmlFor="id">`, OR
76
+ - `aria-label="..."`, OR
77
+ - `aria-labelledby="id-of-another-element"`
78
+ - Placeholder DOES NOT count as label (disappears when user types)
79
+ - **Associated error**: field error connected via `aria-describedby="error-id"`. Error text has matching `id`
80
+ - **Language**: `<html lang="pt-BR">` declared. Without this screen reader reads English for pt-BR text
81
+ - **prefers-reduced-motion**: respect. Animations should disable via `@media (prefers-reduced-motion: reduce)`
82
+
83
+ ### 2. Mandatory states on every UI surface
84
+
85
+ Every screen/component that loads or mutates data must cover all 5:
86
+
87
+ - **Loading**:
88
+ - Skeleton with shape matching real content (avoids layout shift)
89
+ - OR spinner/progress if shape unpredictable
90
+ - Visible minimum 200ms (avoids flash that flickers)
91
+ - Maximum 10s without extra feedback - after that explain "almost there" or offer cancel
92
+ - **Empty**:
93
+ - Never empty screen. Always message + icon + actionable CTA
94
+ - Text orients next step: "Create your first X by clicking Y"
95
+ - Don't confuse empty with error (empty is success, error is failure)
96
+ - **Error**:
97
+ - Specific message: what failed + how to fix
98
+ - NEVER "Something went wrong" / "Unexpected error" as final message to user
99
+ - Visible recovery action: retry, go back, contact support
100
+ - Inline validation errors + general message if needed
101
+ - **Success**:
102
+ - Visible confirmation - toast is OK for non-destructive actions
103
+ - Destructive action (delete, transfer) needs undo OR prior confirmation
104
+ - Toast disappears in 4-6s; destructive actions with undo have 5-10s
105
+ - **Disabled**:
106
+ - ALWAYS with visible reason: tooltip, helper text, or hint
107
+ - Silent disabled = bug ("why can't I click?")
108
+ - Consider alternative: don't disable, let click and show specific error
109
+
110
+ ### 3. Feedback timing - Nielsen heuristics
111
+
112
+ - **< 100ms**: feels instant. No indicator needed
113
+ - **100ms to 1s**: acceptable without indicator. Cursor may change to waiting
114
+ - **1s to 10s**: progress indicator required. Spinner or bar
115
+ - **> 10s**: progress + estimated time OR allow cancel
116
+ - **Indeterminate and > 30s**: offer background notification, free up UI
117
+ - **Optimistic UI**: like/save/toggle - update UI immediately, rollback if it fails
118
+
119
+ ### 4. Forms - universal patterns
120
+
121
+ - **Validation**:
122
+ - On blur for individual field (after user leaves field)
123
+ - On submit for general validation
124
+ - On change ONLY for positive feedback (e.g., password strength)
125
+ - NEVER on keypress for error ("missing character") - tiring
126
+ - **Inline errors**: next to/below the wrong field, WITH optional general top-of-form message. Never just top
127
+ - **Required**:
128
+ - Red asterisk is NOT enough - add text "(required)" or a clear mark before submit
129
+ - Indicate required at design time, not after the error
130
+ - Modern alternative: mark optionals ("Phone (optional)")
131
+ - **Autocomplete**: correct `autocomplete` attribute: `email, current-password, new-password, name, given-name, family-name, tel, postal-code, etc`. Enables browser autofill
132
+ - **Inputmode + type**:
133
+ - `type="email"` shows keyboard with @ on mobile
134
+ - `inputmode="numeric"` for OTP/PIN/ZIP
135
+ - `type="tel"` for phone
136
+ - `type="url"` for URL
137
+ - `type="date"` for date (with fallback if browser doesn't support)
138
+ - **Submit**:
139
+ - DO NOT disable button before user tries - teaches wrong and hides cause
140
+ - Disable ONLY during in-flight request (avoids double submit)
141
+ - Loading state on the button (text + inline spinner)
142
+ - **Password**:
143
+ - "Show password" toggle (eye icon)
144
+ - Always force HTTPS - never send password in plain HTTP
145
+ - Show requirements before user types (8+ chars, etc)
146
+ - **Destructive confirmation**:
147
+ - Irreversible actions (delete account, drop data) require typing name/word or explicit checkbox
148
+ - Plain "are you sure?" modal is insufficient for truly destructive action
149
+
150
+ ### 5. Navigation
151
+
152
+ - **Current location**: active nav highlighted (weight + color + indicator). Breadcrumbs in deep hierarchy
153
+ - **Browser back button**: respect history. Modal doesn't use `pushState` without reason. Single-page nav uses router that emits real history
154
+ - **Custom 404**: friendly page with search or sitemap, not blank screen
155
+ - **Logo links home**: universal convention
156
+ - **Search**: if app has search, keyboard shortcut `/` or `Ctrl+K` (convention)
157
+
158
+ ### 6. Responsive - mobile-first
159
+
160
+ - **Design starts at 320px** and grows - not the other way around
161
+ - **Breakpoints based on content**, not devices: point where layout breaks, not "iPhone 12"
162
+ - **No horizontal scroll on mobile** (except intentional carousel). Audit with viewport 375px
163
+ - **Touch-friendly spacing**: minimum 8px between clickable targets
164
+ - **Hover-only is bad on mobile**: anything needing hover needs fallback (long press, tap to reveal)
165
+ - **Density**: mobile needs more space than desktop for the same legibility
166
+
167
+ ### 7. UX performance - Core Web Vitals
168
+
169
+ - **CLS < 0.1** (Cumulative Layout Shift):
170
+ - `width` + `height` on every `<img>` (avoids jump on load)
171
+ - `font-display: swap` with metric-compatible fallback
172
+ - Reserve space for ads/embeds/skeletons
173
+ - **LCP < 2.5s** (Largest Contentful Paint):
174
+ - Optimized hero image (WebP/AVIF + responsive `srcset`)
175
+ - Critical CSS inline
176
+ - Preload critical resource (`<link rel="preload">`)
177
+ - **INP < 200ms** (Interaction to Next Paint):
178
+ - No heavy JS blocking main thread during interaction
179
+ - Debounce on input handlers
180
+ - Web Workers for heavy computation
181
+ - **TTFB < 800ms** (Time To First Byte):
182
+ - Static cache, CDN, lazy loading
183
+ - **Optimistic UI**: already mentioned - update immediately
184
+
185
+ ### 8. Visual hierarchy
186
+
187
+ - **1 primary action per view**. Multiple = paralyzed decision (Hicks Law)
188
+ - **Secondary visually smaller**: ghost, outline, or link
189
+ - **Whitespace separates groups** - no little box (border) for everything
190
+ - **Fixed spacing scale**: 4/8/16/24/32/48/64 (multiples of 4 or 8). No `margin: 13px`
191
+ - **Type scale**: max 5-6 sizes in the entire app. More than that = visual chaos
192
+ - **Color palette**:
193
+ - 60-30-10 rule: 60% neutral (background), 30% complementary, 10% accent (CTA)
194
+ - Max 1 brand color + 1 or 2 accents
195
+ - States (success/warn/error) are a separate palette
196
+ - **Alignment**: every element aligned to a grid - not "eyeball"
197
+
198
+ ### 9. i18n + l10n
199
+
200
+ - **Zero hardcoded string in markup**. Always a translation key
201
+ - JSX/TSX: don't write pt-BR text directly, use `t("key")` or equivalent
202
+ - Templates: use translate tag (`{% trans %}`, `<t>`, `@Localize`)
203
+ - HTML: separate content from markup
204
+ - **RTL ready** (Arabic, Hebrew):
205
+ - Logical properties: `margin-inline-start` instead of `margin-left`
206
+ - `padding-block` instead of `padding-top`
207
+ - `text-align: start/end` instead of `left/right`
208
+ - `dir="auto"` on fields accepting input in any language
209
+ - **Format by locale**:
210
+ - Dates: `Intl.DateTimeFormat` or backend equivalent
211
+ - Numbers: `Intl.NumberFormat`
212
+ - Currency: never hardcoded "$" - currency comes from locale + value
213
+ - **Pluralization**: ICU MessageFormat or equivalent. Languages have 1, 2, 3+ or more forms (Russian has 4)
214
+
215
+ ### 10. UI security - overlap with general rules
216
+
217
+ - **Tokens NEVER in localStorage/sessionStorage**:
218
+ - Vulnerable to XSS. Any malicious script reads everything
219
+ - Safe pattern: httpOnly cookie + SameSite=Strict
220
+ - Token in memory with refresh via cookie is OK for SPAs
221
+ - **Strict CSP**:
222
+ - `script-src 'self'` at minimum - no `unsafe-inline`, no `unsafe-eval`
223
+ - `frame-ancestors 'none'` or whitelist - prevents clickjacking
224
+ - **HTTPS only**:
225
+ - Redirect HTTP -> HTTPS on the server
226
+ - HSTS header with `includeSubDomains`
227
+ - No mixed content (HTTP on HTTPS page)
228
+ - **CSRF**:
229
+ - CSRF token on every form with authenticated side-effect
230
+ - SameSite=Strict cookie helps but isn't enough
231
+ - **External links**:
232
+ - `target="_blank"` ALWAYS with `rel="noopener noreferrer"` (prevents tabnabbing)
233
+ - **dangerouslySetInnerHTML / v-html / @Html.Raw**:
234
+ - Never with user input without sanitization (DOMPurify or backend sanitizer)
235
+ - Prefer semantic parsing (markdown -> AST -> render)
236
+ - **External form action**: never accept a user-controllable `action` URL
237
+
238
+ ## Anti-patterns - BLOCK list for reviewer
239
+
240
+ Each item below is automatic violation. Reviewer marks BLOCK + cites rule.
241
+
242
+ | Anti-pattern | Why it is BLOCK |
243
+ |---|---|
244
+ | Button that looks like a link / link that looks like a button | Confuses mental model, violates convention |
245
+ | `<div onclick>` instead of `<button>` | No keyboard, no ARIA, no semantics |
246
+ | `<a href="#">` or `<a href="javascript:">` for action | Becomes a destinationless link - use `<button>` |
247
+ | Modal without Esc close | Keyboard trap - WCAG 2.1.2 |
248
+ | Modal without visible close button | Same reason |
249
+ | Infinite spinner without timeout/fallback | User doesn't know if it's stuck |
250
+ | Auto-play media with sound | WCAG 1.4.2 |
251
+ | Toast as ONLY confirmation of destructive action | Toast disappears - destructive needs persistent |
252
+ | Disabled state without visible reason | "Why doesn't it work?" - UX bug |
253
+ | Generic error "Something went wrong" | Not actionable |
254
+ | Color as ONLY state indicator | Color blindness - WCAG 1.4.1 |
255
+ | Required marked ONLY by color (red border) | Same reason |
256
+ | Required shown ONLY after submit | User didn't know it was required |
257
+ | Form without `<label>` or `aria-label` | WCAG 3.3.2 |
258
+ | Placeholder replacing label | Disappears when user types - WCAG 3.3.2 |
259
+ | Heading skip (h1 -> h3 without h2) | WCAG 1.3.1 |
260
+ | `<img>` without `alt` | WCAG 1.1.1 |
261
+ | `<img alt="image">` or redundant alt "image of X" | Good alt describes content, not media |
262
+ | Text over image without overlay/guaranteed contrast | WCAG 1.4.3 |
263
+ | Animation > 400ms on direct interaction | Perceived as slow |
264
+ | `prefers-reduced-motion` ignored | WCAG 2.3.3 |
265
+ | Outline removed without replacement | WCAG 2.4.7 |
266
+ | Arbitrary positive `tabindex` (`tabindex="5"`) | Breaks natural order - only use 0 and -1 |
267
+ | `lang` absent on `<html>` | Screen reader pronounces wrong |
268
+ | Form action or href with direct user input | Risk of XSS/open redirect |
269
+ | `localStorage.setItem('token', ...)` or similar for credential | XSS risk - use httpOnly cookie |
270
+
271
+ ## Procedure (use by agent)
272
+
273
+ ### Doer (write/edit)
274
+
275
+ #### Step 1: Detect type of change
276
+ If task touches UI files, load checklist in mind before writing.
277
+
278
+ #### Step 2: For each new component/template
279
+ Apply the checklist of rules 1-10. In particular:
280
+ - Does it cover the 5 states (loading/empty/error/success/disabled)?
281
+ - Semantic HTML first?
282
+ - Visible focus maintained?
283
+ - Contrast OK in light/dark states?
284
+ - Strings via i18n key?
285
+
286
+ #### Step 3: When in architectural doubt
287
+ Consult references:
288
+ - Full WCAG: `references/wcag-checklist.md`
289
+ - States: `references/state-coverage.md`
290
+ - Forms: `references/forms-patterns.md`
291
+ - Anti-patterns explained: `references/anti-patterns.md`
292
+
293
+ ### Reviewer (gate 5)
294
+
295
+ #### Step 1: For each modified file in frontend
296
+ Run specific greps based on the type:
297
+
298
+ **JSX/TSX/Vue/Svelte:**
299
+ ```bash
300
+ # Button without aria-label and without inner text
301
+ grep -RnE '<button[^>]*>(\s*<[^>]+/?>\s*)+</button>' src/
302
+
303
+ # Input without label
304
+ grep -RnE '<input(?![^>]*aria-label)(?![^>]*id=)' src/
305
+
306
+ # href="#" for action
307
+ grep -RnE 'href="#"' src/
308
+
309
+ # localStorage with token
310
+ grep -RnE 'localStorage\.(set|get)Item.*[Tt]oken' src/
311
+
312
+ # Outline removed
313
+ grep -RnE 'outline\s*:\s*(none|0)' src/
314
+ ```
315
+
316
+ **Server-side templates (Razor/Twig/Blade/ERB/Jinja):**
317
+ Similar greps adapted to the syntax.
318
+
319
+ #### Step 2: Classify
320
+ - Match on violation listed in the table above -> BLOCK
321
+ - Suspicious pattern but not certain -> WARN
322
+ - No match -> PASS on gate 5
323
+
324
+ ## Expected inputs
325
+
326
+ - Path of the modified file
327
+ - Diff or complete content of the file
328
+
329
+ ## Outputs
330
+
331
+ Does NOT produce its own file. Modifies the parent agent's judgement:
332
+ - Doer chooses NOT to introduce a violation - writes correct code from the start
333
+ - Reviewer marks BLOCK/WARN with rule cited
334
+
335
+ ## References
336
+
337
+ - `references/wcag-checklist.md` - WCAG 2.2 AA expanded with code examples
338
+ - `references/state-coverage.md` - Patterns for loading/empty/error/success/disabled across engines
339
+ - `references/forms-patterns.md` - Universal patterns for form validation and UX
340
+ - `references/anti-patterns.md` - Gallery of anti-patterns with wrong example + fix
341
+
342
+ ## Anti-patterns of this skill
343
+
344
+ - Applying only to JS stacks - rules work for any template engine
345
+ - Making a rule framework-specific (e.g., "use React.useState") - skill is agnostic
346
+ - Replacing human design code review - skill covers the technically broken, not the aesthetically mediocre
347
+ - Blocking MVP for minor a11y - severity matters, minor is INFO/WARN
348
+
349
+ ## Examples
350
+
351
+ ### Example 1: Doer receives task "add delete button to ItemCard"
352
+
353
+ Applies skill before writing:
354
+ - Destructive action needs: explicit confirmation, focus returns to origin button after modal closes, descriptive label (`aria-label="Delete item Order #123"`), undo if possible
355
+ - Loading state during request
356
+ - Error state with retry
357
+ - Success state with undo (5s timer)
358
+ - Use `<button>`, not `<a>` or `<div>`
359
+ - Tab order: button -> modal opens -> modal buttons navigable -> Esc closes -> focus returns
360
+
361
+ Code written comes out compliant.
362
+
363
+ ### Example 2: Reviewer finds `<input>` without label
364
+
365
+ Marks gate 5 as BLOCK:
366
+ ```
367
+ [BLOCK] src/components/LoginForm.tsx:42
368
+ Rule: Forms - Form labels (WCAG 1.3.1, 3.3.2)
369
+ Violation: <input type="email" /> without <label>, aria-label, or aria-labelledby
370
+ Fix: <label htmlFor="email">Email</label><input id="email" type="email" />
371
+ ```
372
+
373
+ ### Example 3: Reviewer finds `localStorage.setItem('access_token', token)`
374
+
375
+ Marks gate 5 as BLOCK:
376
+ ```
377
+ [BLOCK] src/auth/store.ts:18
378
+ Rule: UI Security - Tokens in storage
379
+ Violation: localStorage.setItem with authentication token
380
+ Why: vulnerable to XSS - any malicious script on the page reads the token
381
+ Fix: backend sets httpOnly cookie SameSite=Strict; frontend doesn't touch token
382
+ ```
383
+
384
+ ### Example 4: Backend-only API (Python FastAPI)
385
+
386
+ Skill is not loaded. PROJECT.md has `frontend.has_frontend: false`. Nothing happens.