@herbertgao/pi-impeccable 0.0.0-stage → 0.0.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 (62) hide show
  1. package/LICENSE +191 -0
  2. package/NOTICE.md +11 -0
  3. package/README.md +33 -2
  4. package/package.json +51 -4
  5. package/skills/impeccable/SKILL.md +89 -0
  6. package/skills/impeccable/reference/adapt.md +318 -0
  7. package/skills/impeccable/reference/adapt.native.md +58 -0
  8. package/skills/impeccable/reference/android.md +46 -0
  9. package/skills/impeccable/reference/animate.md +89 -0
  10. package/skills/impeccable/reference/audit.md +139 -0
  11. package/skills/impeccable/reference/audit.native.md +139 -0
  12. package/skills/impeccable/reference/bolder.md +33 -0
  13. package/skills/impeccable/reference/clarify.md +94 -0
  14. package/skills/impeccable/reference/colorize.md +86 -0
  15. package/skills/impeccable/reference/component-review.md +63 -0
  16. package/skills/impeccable/reference/craft-floor.md +44 -0
  17. package/skills/impeccable/reference/craft.md +5 -0
  18. package/skills/impeccable/reference/critique.md +819 -0
  19. package/skills/impeccable/reference/degraded/asset-producer.md +42 -0
  20. package/skills/impeccable/reference/degraded/documenter.md +24 -0
  21. package/skills/impeccable/reference/degraded/finish-reviewer.md +38 -0
  22. package/skills/impeccable/reference/degraded/manual-edit-applier.md +92 -0
  23. package/skills/impeccable/reference/delight.md +70 -0
  24. package/skills/impeccable/reference/distill.md +111 -0
  25. package/skills/impeccable/reference/doctor.md +54 -0
  26. package/skills/impeccable/reference/document.md +416 -0
  27. package/skills/impeccable/reference/extract.md +69 -0
  28. package/skills/impeccable/reference/generate.md +101 -0
  29. package/skills/impeccable/reference/harden.md +362 -0
  30. package/skills/impeccable/reference/hooks.md +114 -0
  31. package/skills/impeccable/reference/init.md +131 -0
  32. package/skills/impeccable/reference/ios.md +51 -0
  33. package/skills/impeccable/reference/layout.md +84 -0
  34. package/skills/impeccable/reference/live-setup.md +104 -0
  35. package/skills/impeccable/reference/live.md +325 -0
  36. package/skills/impeccable/reference/mode-operate.md +21 -0
  37. package/skills/impeccable/reference/mode-persuade.md +19 -0
  38. package/skills/impeccable/reference/mode-read.md +21 -0
  39. package/skills/impeccable/reference/new-work.md +152 -0
  40. package/skills/impeccable/reference/onboard.md +234 -0
  41. package/skills/impeccable/reference/operate.md +61 -0
  42. package/skills/impeccable/reference/optimize.md +257 -0
  43. package/skills/impeccable/reference/overdrive.md +127 -0
  44. package/skills/impeccable/reference/polish.md +105 -0
  45. package/skills/impeccable/reference/quieter.md +99 -0
  46. package/skills/impeccable/reference/region-map.md +26 -0
  47. package/skills/impeccable/reference/routing.md +24 -0
  48. package/skills/impeccable/reference/shape.md +59 -0
  49. package/skills/impeccable/reference/typeset.md +90 -0
  50. package/skills/impeccable/reference/visualize.md +47 -0
  51. package/skills/impeccable/scripts/VERSION +1 -0
  52. package/skills/impeccable/scripts/command-metadata.json +98 -0
  53. package/skills/impeccable/scripts/data/font-index-failures.json +121 -0
  54. package/skills/impeccable/scripts/data/font-index.json +1 -0
  55. package/skills/impeccable/scripts/engine-checksums.txt +9 -0
  56. package/skills/impeccable/scripts/impeccable +249 -0
  57. package/skills/impeccable/scripts/impeccable.cmd +278 -0
  58. package/skills/impeccable/scripts/live-browser-dom.js +320 -0
  59. package/skills/impeccable/scripts/live-browser-ignores.js +246 -0
  60. package/skills/impeccable/scripts/live-browser-session.js +183 -0
  61. package/skills/impeccable/scripts/live-browser.js +13645 -0
  62. package/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
@@ -0,0 +1,362 @@
1
+ Designs that only work with perfect data aren't production-ready. Harden the interface against the inputs, errors, languages, and network conditions that real users will throw at it.
2
+
3
+ ## Assess Hardening Needs
4
+
5
+ Identify weaknesses and edge cases:
6
+
7
+ 1. **Test with extreme inputs**:
8
+ - Very long text (names, descriptions, titles)
9
+ - Very short text (empty, single character)
10
+ - Special characters (emoji, RTL text, accents)
11
+ - Large numbers (millions, billions)
12
+ - Many items (1000+ list items, 50+ options)
13
+ - No data (empty states)
14
+
15
+ 2. **Test error scenarios**:
16
+ - Network failures (offline, slow, timeout)
17
+ - API errors (400, 401, 403, 404, 500)
18
+ - Validation errors
19
+ - Permission errors
20
+ - Rate limiting
21
+ - Concurrent operations
22
+
23
+ 3. **Test internationalization**:
24
+ - Long translations (German is often 30% longer than English)
25
+ - RTL languages (Arabic, Hebrew)
26
+ - Character sets (Chinese, Japanese, Korean, emoji)
27
+ - Date/time formats
28
+ - Number formats (1,000 vs 1.000)
29
+ - Currency symbols
30
+
31
+ Designs that only work with perfect data aren't production-ready.
32
+
33
+ ## Hardening Dimensions
34
+
35
+ Systematically improve resilience:
36
+
37
+ ### Text Overflow & Wrapping
38
+
39
+ **Long text handling**:
40
+ ```css
41
+ /* Single line with ellipsis */
42
+ .truncate {
43
+ overflow: hidden;
44
+ text-overflow: ellipsis;
45
+ white-space: nowrap;
46
+ }
47
+
48
+ /* Multi-line with clamp */
49
+ .line-clamp {
50
+ display: -webkit-box;
51
+ -webkit-line-clamp: 3;
52
+ -webkit-box-orient: vertical;
53
+ overflow: hidden;
54
+ }
55
+
56
+ /* Allow wrapping */
57
+ .wrap {
58
+ word-wrap: break-word;
59
+ overflow-wrap: break-word;
60
+ hyphens: auto;
61
+ }
62
+ ```
63
+
64
+ **Flex/Grid overflow**:
65
+ ```css
66
+ /* Prevent flex items from overflowing */
67
+ .flex-item {
68
+ min-width: 0; /* Allow shrinking below content size */
69
+ overflow: hidden;
70
+ }
71
+
72
+ /* Prevent grid items from overflowing */
73
+ .grid-item {
74
+ min-width: 0;
75
+ min-height: 0;
76
+ }
77
+ ```
78
+
79
+ **Responsive text sizing**:
80
+ - Use `clamp()` for fluid typography
81
+ - Set minimum readable sizes (16px body on mobile, the same floor the typography guidance sets; 14px only for genuinely secondary text. iOS Safari force-zooms focused inputs under 16px, which breaks form layouts)
82
+ - Test text scaling (zoom to 200%)
83
+ - Ensure containers expand with text
84
+
85
+ ### Internationalization (i18n)
86
+
87
+ **Text expansion**:
88
+ - Add 30-40% space budget for translations
89
+ - Use flexbox/grid that adapts to content
90
+ - Test with longest language (usually German)
91
+ - Avoid fixed widths on text containers
92
+
93
+ ```jsx
94
+ // ❌ Bad: Assumes short English text
95
+ <button className="w-24">Submit</button>
96
+
97
+ // ✅ Good: Adapts to content
98
+ <button className="px-4 py-2">Submit</button>
99
+ ```
100
+
101
+ **RTL (Right-to-Left) support**:
102
+ ```css
103
+ /* Use logical properties */
104
+ margin-inline-start: 1rem; /* Not margin-left */
105
+ padding-inline: 1rem; /* Not padding-left/right */
106
+ border-inline-end: 1px solid; /* Not border-right */
107
+
108
+ /* Or use dir attribute */
109
+ [dir="rtl"] .arrow { transform: scaleX(-1); }
110
+ ```
111
+
112
+ **Arabic-script specifics** (Arabic, Persian, Urdu, Pashto, Kurdish):
113
+ - Preserve Zero-Width Non-Joiner (U+200C). Persian and Kurdish use ZWNJ between compound-word parts to break cursive joining while keeping the word together. A filter or sanitizer that strips it changes meaning. Never normalize it away.
114
+ - Handle Yeh and Kaf variants. Persian uses ی (U+06CC) and ک (U+06A9), while Arabic uses ي (U+064A) and ك (U+0643). Preserve the original form in storage. For search and validation, treat the corresponding letters as equivalent so that Arabic-keyboard input matches Persian text. Rejecting one variant locks out users whose keyboard sends the other.
115
+ - Support locale-aware digits. Persian (`fa-IR`) and Arabic locales use Eastern Arabic-Indic numerals (۰-۹ and ٠-٩). Use `Intl.NumberFormat` with the correct locale rather than hardcoding Western digits.
116
+
117
+ ```javascript
118
+ // ✅ Locale-aware digit formatting
119
+ new Intl.NumberFormat('fa-IR').format(1234); // ۱٬۲۳۴
120
+ new Intl.NumberFormat('ar-SA').format(1234); // ١٬٢٣٤
121
+ ```
122
+
123
+ - Respect calendar systems. Persian users expect the Solar Hijri (Jalali) calendar; many Arabic-speaking users expect the Hijri (Islamic) calendar. Use `Intl.DateTimeFormat` with the appropriate locale or calendar parameter.
124
+
125
+ ```javascript
126
+ // ✅ Locale-appropriate calendar
127
+ new Intl.DateTimeFormat('fa-IR').format(new Date());
128
+ new Intl.DateTimeFormat('ar-SA-u-ca-islamic').format(new Date());
129
+ ```
130
+
131
+ **Character set support**:
132
+ - Use UTF-8 encoding everywhere
133
+ - Test with Chinese/Japanese/Korean (CJK) characters
134
+ - Test with emoji (they can be 2-4 bytes)
135
+ - Handle different scripts (Latin, Cyrillic, Arabic, etc.)
136
+
137
+ **Date/Time formatting**:
138
+ ```javascript
139
+ // ✅ Use Intl API for proper formatting
140
+ new Intl.DateTimeFormat('en-US').format(date); // 1/15/2024
141
+ new Intl.DateTimeFormat('de-DE').format(date); // 15.1.2024
142
+
143
+ new Intl.NumberFormat('en-US', {
144
+ style: 'currency',
145
+ currency: 'USD'
146
+ }).format(1234.56); // $1,234.56
147
+ ```
148
+
149
+ **Pluralization**:
150
+ ```javascript
151
+ // ❌ Bad: Assumes English pluralization
152
+ `${count} item${count !== 1 ? 's' : ''}`
153
+
154
+ // ✅ Good: Use proper i18n library
155
+ t('items', { count }) // Handles complex plural rules
156
+ ```
157
+
158
+ ### Error Handling
159
+
160
+ **Network errors**:
161
+ - Show clear error messages
162
+ - Provide retry button
163
+ - Explain what happened
164
+ - Offer offline mode (if applicable)
165
+ - Handle timeout scenarios
166
+
167
+ ```jsx
168
+ // Error states with recovery
169
+ {error && (
170
+ <ErrorMessage>
171
+ <p>Failed to load data. {error.message}</p>
172
+ <button onClick={retry}>Try again</button>
173
+ </ErrorMessage>
174
+ )}
175
+ ```
176
+
177
+ **Form validation errors**:
178
+ - Inline errors near fields
179
+ - Clear, specific messages
180
+ - Suggest corrections
181
+ - Don't block submission unnecessarily
182
+ - Preserve user input on error
183
+
184
+ **API errors**:
185
+ - Handle each status code appropriately
186
+ - 400: Show validation errors
187
+ - 401: Redirect to login
188
+ - 403: Show permission error
189
+ - 404: Show not found state
190
+ - 429: Show rate limit message
191
+ - 500: Show generic error, offer support
192
+
193
+ **Graceful degradation**:
194
+ - Core functionality works without JavaScript
195
+ - Images have alt text
196
+ - Progressive enhancement
197
+ - Fallbacks for unsupported features
198
+
199
+ ### Edge Cases & Boundary Conditions
200
+
201
+ **Empty states**:
202
+ - No items in list
203
+ - No search results
204
+ - No notifications
205
+ - No data to display
206
+ - Provide clear next action
207
+
208
+ **Loading states**:
209
+ - Initial load
210
+ - Pagination load
211
+ - Refresh
212
+ - Show what's loading ("Loading your projects...")
213
+ - Time estimates for long operations
214
+
215
+ **Large datasets**:
216
+ - Pagination or virtual scrolling
217
+ - Search/filter capabilities
218
+ - Performance optimization
219
+ - Don't load all 10,000 items at once
220
+
221
+ **Concurrent operations**:
222
+ - Prevent double-submission (disable button while loading)
223
+ - Handle race conditions
224
+ - Optimistic updates with rollback
225
+ - Conflict resolution
226
+
227
+ **Interrupted gestures** (custom sliders, drag surfaces, scrollable control strips):
228
+ - A second finger or pointer lands mid-drag: the first drag keeps its pointer or ends cleanly, never jumps to the new one
229
+ - The browser cancels the gesture to scroll (`pointercancel`), capture is lost (`lostpointercapture`), the pointer is released outside the control, or the window loses focus (`blur`) mid-drag: clear the dragging state and release capture
230
+ - After each of these, the next tap or drag works without a reload
231
+
232
+ **Permission states**:
233
+ - No permission to view
234
+ - No permission to edit
235
+ - Read-only mode
236
+ - Clear explanation of why
237
+
238
+ **Browser compatibility**:
239
+ - Polyfills for modern features
240
+ - Fallbacks for unsupported CSS
241
+ - Feature detection (not browser detection)
242
+ - Test in target browsers
243
+
244
+ ### Input Validation & Sanitization
245
+
246
+ **Client-side validation**:
247
+ - Required fields
248
+ - Format validation (email, phone, URL)
249
+ - Length limits
250
+ - Pattern matching
251
+ - Custom validation rules
252
+
253
+ **Server-side validation** (always):
254
+ - Never trust client-side only
255
+ - Validate and sanitize all inputs
256
+ - Protect against injection attacks
257
+ - Rate limiting
258
+
259
+ **Constraint handling**:
260
+ ```html
261
+ <!-- Set clear constraints -->
262
+ <input
263
+ type="text"
264
+ maxlength="100"
265
+ pattern="[A-Za-z0-9]+"
266
+ required
267
+ aria-describedby="username-hint"
268
+ />
269
+ <small id="username-hint">
270
+ Letters and numbers only, up to 100 characters
271
+ </small>
272
+ ```
273
+
274
+ ### Accessibility Resilience
275
+
276
+ **Keyboard navigation**:
277
+ - All functionality accessible via keyboard
278
+ - Logical tab order
279
+ - Focus management in modals
280
+ - Skip links for long content
281
+
282
+ **Screen reader support**:
283
+ - Proper ARIA labels
284
+ - Announce dynamic changes (live regions)
285
+ - Descriptive alt text
286
+ - Semantic HTML
287
+
288
+ **High contrast mode**:
289
+ - Test in Windows high contrast mode
290
+ - Don't rely only on color
291
+ - Provide alternative visual cues
292
+
293
+ ### Performance Resilience
294
+
295
+ **Slow connections**:
296
+ - Progressive image loading
297
+ - Skeleton screens
298
+ - Optimistic UI updates
299
+ - Offline support (service workers)
300
+
301
+ **Memory leaks**:
302
+ - Clean up event listeners
303
+ - Cancel subscriptions
304
+ - Clear timers/intervals
305
+ - Abort pending requests on unmount
306
+
307
+ **Throttling & Debouncing**:
308
+ ```javascript
309
+ // Debounce search input
310
+ const debouncedSearch = debounce(handleSearch, 300);
311
+
312
+ // Throttle scroll handler
313
+ const throttledScroll = throttle(handleScroll, 100);
314
+ ```
315
+
316
+ ## Testing Strategies
317
+
318
+ **Manual testing**:
319
+ - Test with extreme data (very long, very short, empty)
320
+ - Test in different languages
321
+ - Test offline
322
+ - Test slow connection (throttle to 3G)
323
+ - Test with screen reader
324
+ - Test keyboard-only navigation
325
+ - Test on old browsers
326
+
327
+ **Automated testing**:
328
+ - Unit tests for edge cases
329
+ - Integration tests for error scenarios
330
+ - E2E tests for critical paths
331
+ - A behavioral regression for each confirmed gesture fix, when the project's test runner can drive input
332
+ - Visual regression tests
333
+ - Accessibility tests (axe, WAVE)
334
+
335
+ **Avoid**:
336
+ - Assume perfect input (validate everything)
337
+ - Ignore internationalization (design for global)
338
+ - Leave error messages generic ("Error occurred")
339
+ - Forget offline scenarios
340
+ - Trust client-side validation alone
341
+ - Use fixed widths for text
342
+ - Assume English-length text
343
+ - Block entire interface when one component errors
344
+
345
+ ## Verify Hardening
346
+
347
+ Test thoroughly with edge cases:
348
+
349
+ - **Long text**: Try names with 100+ characters
350
+ - **Emoji**: Use emoji in all text fields
351
+ - **RTL**: Test with Arabic or Hebrew
352
+ - **CJK**: Test with Chinese/Japanese/Korean
353
+ - **Network issues**: Disable internet, throttle connection
354
+ - **Large datasets**: Test with 1000+ items
355
+ - **Concurrent actions**: Click submit 10 times rapidly
356
+ - **Interrupted gestures**: Add a second finger mid-drag, scroll across the control, release outside it, switch windows mid-drag; then drag again
357
+ - **Errors**: Force API errors, test all error states
358
+ - **Empty**: Remove all data, test empty states
359
+
360
+ For gestures, say what produced the evidence (emulated viewport, synthesized touch, which engine, physical device) and name what stayed untested.
361
+
362
+ When edge cases are covered, hand off to `/impeccable polish` for the final pass.
@@ -0,0 +1,114 @@
1
+ # /impeccable hooks
2
+
3
+ Manage the **design detector hook** for the current project.
4
+
5
+ The hook runs the impeccable design detector on direct file edits to design-relevant files (`.tsx`, `.jsx`, `.html`, `.vue`, `.svelte`, `.astro`, `.css`, `.scss`, `.sass`, `.less`, `.ts`, `.js`). Claude Code, Codex, Cursor, and GitHub Copilot use a post-tool-use hook and push a short system reminder into the agent's context after the edit; findings get a correction prompt, pending issues get a re-nudge, and clean UI-ish files get a short ack unless quiet mode is on (`hook.quiet` in config). Plain `.ts` and `.js` files are still scanned, but stay quiet unless the detector finds something. Grok Build fires the same PostToolUse scan to mark touched files, then surfaces findings on Stop `additionalContext`. Do not expect a Grok per-edit reminder: Grok discards that stdout.
6
+
7
+ The detector rules run in two tiers. The per-edit hook surfaces only the immediate tier: mechanical, unambiguous problems worth interrupting an edit for, such as broken images, overflowing content, contrast and legibility failures, gradient text, glow shadows, and design-system drift. Everything else (copy cadence, palette and typography taste, layout rhythm) is deferred to a deep pass on the `Stop` hook event, which runs the full rule set over every UI file touched in the session and surfaces the remaining findings once, deduplicated against what the per-edit pass already reported. A session with nothing left to report stops silently. Set `hook.perEditRules` to `"all"` in `.impeccable/config.json` to restore the full rule set on every edit. The Stop deep pass is wired for Claude Code, Codex, and Grok Build, which dispatch a native `Stop` hook event. Cursor does not get one (its `stop` hook can only answer with a follow-up user message), and GitHub Copilot's stop-style events do not feed context back to the model, so they keep the full detector per edit. Grok also fires an observe-only Stop with `reason: "shutdown"` after `end_turn`; skip that one, scan only `end_turn`.
8
+
9
+ Every hook is a mechanical pass. The reflexes no scanner catches live in [craft-floor.md](craft-floor.md), which the skill loads before it edits UI, so they apply whether or not a hook is wired. A session with no automatic hook gets one `MANUAL_DETECTOR_REQUIRED` directive from `impeccable context` asking for a single detector run at the end.
10
+
11
+ This command toggles the hook **per project** by editing `.impeccable/config.json` (the unified Impeccable config; hook runtime settings live under its `hook` key, and shared detector ignores live under `detector`). Per-developer overrides, including the install consent decision (`hook.consent`) the CLI records, live in the gitignored `.impeccable/config.local.json`. Set `hook.enabled: false` to turn the hook off, `hook.quiet: true` to silence the clean/pending acks, or `hook.auditLog` to a file path for an NDJSON log. The legacy `IMPECCABLE_HOOK_DISABLED`, `IMPECCABLE_HOOK_QUIET`, and `IMPECCABLE_HOOK_LOG` env vars are still honored and override these config values when set.
12
+
13
+ Declare server-side template extensions under **`detector.extensions`** when the project uses Blade, Twig, ERB, or Handlebars files; the hook skips them otherwise because they sit outside the built-in extension list. One entry per extension, `{ "ext": ".blade.php", "engine": "html" }`. `engine` picks the analyzer (`html` for markup templates, `text` for JS/TS/CSS-like files) and defaults to `html`. Match against the end of the filename, so double extensions like `.blade.php` and `.html.erb` work. Config only adds extensions; the built-in list always applies.
14
+
15
+ Manual `.pi/skills/impeccable/scripts/impeccable detect` scans use the same project filter config by default: `detector.ignoreRules`, `detector.ignoreFiles`, `detector.ignoreValues`, and `detector.designSystem.enabled`. `hook.enabled` only controls automatic hook execution, not manual CLI scans. Use `.pi/skills/impeccable/scripts/impeccable detect --no-config ...` for a raw detector run that ignores project config/context. Use `.pi/skills/impeccable/scripts/impeccable ignores ...` for direct CLI CRUD on the same detector ignores.
16
+
17
+ Supported harnesses: Claude Code (`.claude/settings.local.json` for a project-scope install; `~/.claude/settings.json` for a user-scope install; a project hook moved into shared `.claude/settings.json` is honored in place too), Codex (`.codex/hooks.json` in the project), Cursor (`.cursor/hooks.json` in the project), Grok Build (`.grok/hooks/impeccable.json` in the project; requires `/hooks-trust` or `--trust`), and GitHub Copilot (`.github/hooks/impeccable.json` in the project, a team-shared committed file that both the Copilot CLI and the cloud agent read). For the Copilot CLI, repo-level hooks fire once `.github/hooks/impeccable.json` is committed to the repository's default branch.
18
+
19
+ On **Cursor**, the hook runs on `postToolUse` for the `Write` tool (every agent file edit) and returns its reminder as `additional_context`, which Cursor adds after the tool result. Projects set up before this ran a `preToolUse` gate (`hook-before-edit`) that blocked bad writes before they landed; that gate still works until `hooks on`, `impeccable update`, or `impeccable doctor --fix` moves the entry to `postToolUse`.
20
+
21
+ Gemini installs session and completion hooks in `.gemini/settings.json`, merged into the settings already there (comments are tolerated; a commented file is backed up to `settings.json.bak` before the rewrite, and a file that is not valid JSON is left alone). It does not install a per-edit detector hook. The `BeforeTool` hook only rewrites shell commands that run `build-phase`, and only on macOS and Linux; on Windows (where Gemini runs hooks through PowerShell) no session id reaches the shell, so a comp build is not tied to the session and the completion reminder stays silent.
22
+
23
+ ## Routing
24
+
25
+ The first argument is the action. Defaults to `status`.
26
+
27
+ | Action | What it does |
28
+ |---|---|
29
+ | `status` | Print current state, shared/local config paths, ignored rules / files / values, env override. |
30
+ | `on` | Set `enabled: true` in `.impeccable/config.json`, record local hook consent as accepted, and install/repair provider hook manifests when the skill is installed. |
31
+ | `off` | Set `enabled: false` in `.impeccable/config.json`. |
32
+ | `ignore-rule <id>` | Append `<id>` to `detector.ignoreRules`; for `overused-font`, requires `--all-values`. Suppresses the rule across the whole project. |
33
+ | `ignore-file <glob>` | Append `<glob>` to `detector.ignoreFiles`. Suppresses **every** rule for matching files. |
34
+ | `ignore-value <id> <value> [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. |
35
+ | `ignore-value <id> <value> --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. |
36
+ | `ignore-value <id> "*" --file <glob> [--file <glob>...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=<glob>` / `--files=<glob>`. A bare `"*"` with no `--file` is refused: use `ignore-rule <id>` if you really mean project-wide. |
37
+ | `reset` | Delete the project config, dedup cache, and Cursor pending queue, and remove the hook's entries from every provider manifest `on` installs, the committed Copilot file included (a team-shared `settings.json` that `on` never writes is never touched). |
38
+
39
+ ## Flow
40
+
41
+ 1. Resolve the action from the user's argument. If no action was given, default to `status`.
42
+ 2. Invoke the admin script and pass the user's output through verbatim:
43
+
44
+ ```bash
45
+ .pi/skills/impeccable/scripts/impeccable hooks <action> [args...]
46
+ ```
47
+
48
+ 3. If `<action>` is `off`, follow up with a one-line note: "Done. New edits will not trigger the design hook in this project until you run `/impeccable hooks on`."
49
+ 4. If `<action>` is `on`, follow up with: "Done. The design hook will fire after the next Edit/Write on a UI file."
50
+ 5. If `<action>` is `ignore-value`, `ignore-file`, or `ignore-rule`, just print the script output. The default scope is shared `.impeccable/config.json`; add `--local` only when the user explicitly asks for a private exception.
51
+ 6. If `<action>` is `status`, just print the script output. Do not add commentary unless the user asked a follow-up question.
52
+
53
+ ## Triage findings
54
+
55
+ The hook itself never writes ignore config; every exception goes through `impeccable hooks`. Triage each finding into one of three outcomes:
56
+
57
+ - **Real design problem**: fix it. Never add an ignore to skip a fix or to push a blocked write through.
58
+ - **Confident false positive or sanctioned exception**: persist the narrowest ignore yourself and disclose it in your reply. The bar is evidence you can name: an intentional demo or fixture, documentation of bad design, literal or domain-appropriate motion (a ball that bounces), or a choice the user already confirmed. Put that evidence in `--reason` as `"<who decided: evidence>"`; write "user confirmed" only when the user actually did.
59
+ - **Unsure**: leave the finding standing and ask the user in one line. Ask once; a one-line question costs less than the hook re-firing on every later edit.
60
+
61
+ Self-serve stops at `ignore-value`. `ignore-file` and `ignore-rule` silence too much to add on your own judgment; ask the user first.
62
+
63
+ Prefer the narrowest exception:
64
+
65
+ - If the finding line shows an `ignore-value <rule> <value>` pair, pass it to `impeccable hooks ignore-value` with your `--reason`. This writes shared `.impeccable/config.json` by default.
66
+ - For value-specific findings such as `overused-font` and `bounce-easing`, use `ignore-value` for the specific value. Do not use `ignore-rule overused-font` for a specific font.
67
+ - If the finding has no value-specific command, such as `side-tab`, scope that one rule to the file: `ignore-value <id> "*" --file <path>`. Run `.pi/skills/impeccable/scripts/impeccable detect <path>` first to see what actually fires there.
68
+ - Reach for `ignore-file <path>` only when the whole file is out of scope for design review: a fixture, a generated artifact, a deliberate slop demo. It silences every rule for that file permanently, including rules that have not been written yet. A real UI surface with one noisy rule wants the file-scoped value ignore above.
69
+ - Use `ignore-rule <id>` only when the user asks to suppress that whole rule across the project. For broad overused-font suppression, use `ignore-rule overused-font --all-values` only when the user asks to ignore overused fonts generally.
70
+ - Prefer config ignores (the commands above) by default; they keep suppressions in one reviewable place. Reach for an inline comment only when the waiver must travel with a single file that leaves the repo (a generated/exported standalone document, an emailed HTML file). The supported marker is `impeccable-disable <rule>` (whole file) or `impeccable-disable-line` / `impeccable-disable-next-line` (one line), in any comment syntax, with an optional reason after `:` or `--`. The detector honors it by default; `--no-inline-ignores` or `--no-config` bypasses it.
71
+
72
+ Example value-specific exception:
73
+
74
+ ```bash
75
+ .pi/skills/impeccable/scripts/impeccable hooks ignore-value overused-font Inter --shared --reason "User confirmed Inter is intentional"
76
+ ```
77
+
78
+ Example self-served exception, with the evidence named:
79
+
80
+ ```bash
81
+ .pi/skills/impeccable/scripts/impeccable hooks ignore-value bounce-easing bounce-ball --shared --reason "Agent: literal ball-bounce animation, bounce easing is the subject"
82
+ ```
83
+
84
+ Example whole-rule font exception:
85
+
86
+ ```bash
87
+ .pi/skills/impeccable/scripts/impeccable hooks ignore-rule overused-font --all-values --reason "User asked to ignore overused fonts generally"
88
+ ```
89
+
90
+ Example one-rule-in-one-file exception, for a file that is still worth reviewing
91
+ for everything else:
92
+
93
+ ```bash
94
+ .pi/skills/impeccable/scripts/impeccable hooks ignore-value design-system-font-size "*" --file "src/overlay/widget.js" --reason "Injected widget builds its own type scale; DESIGN.md's ramp describes the site"
95
+ ```
96
+
97
+ Example whole-file exception, for a file that is out of scope entirely:
98
+
99
+ ```bash
100
+ .pi/skills/impeccable/scripts/impeccable hooks ignore-file "src/legacy/Card.tsx"
101
+ ```
102
+
103
+ ## Constraints
104
+
105
+ - Never modify `.impeccable/config.json` or `.impeccable/config.local.json` by hand from this command. Always go through `impeccable hooks` so writes stay validated and the file shape stays consistent. One exception: `detector.extensions` has no admin action, so when the user asks to cover a template stack, edit that one field in `.impeccable/config.json` directly and leave the rest of the file untouched.
106
+ - Do not edit the launcher or the binary behind `impeccable hook` and `impeccable hook-before-edit` from this flow. Those are skill plumbing.
107
+ - When a user asks how far to trust the hook, say it runs the engine unsandboxed with the agent's environment and network access (in the Copilot cloud agent too, once `.github/hooks/impeccable.json` is committed), and that the launcher checks a downloaded engine against `.pi/skills/impeccable/scripts/engine-checksums.txt` before its first run; **never** call it sandboxed.
108
+ - The hook never blocks an edit; it emits a post-edit reminder. (A Cursor project still on the old `preToolUse` gate can block a write until its manifest is migrated.) Disabling stops the reminders.
109
+ - The hook is bundled with the Impeccable skill. Project installs use `.claude/settings.local.json`, `.codex/hooks.json`, `.cursor/hooks.json`, `.github/hooks/impeccable.json`, and `.gemini/settings.json`; a user-scope Claude install uses `~/.claude/settings.json`. On Codex, the user must approve the hook via `/hooks` the first time. On Cursor, confirm hooks are enabled under Settings -> Hooks. On GitHub Copilot, the CLI loads `.github/hooks/impeccable.json` once it is committed to the repository's default branch, and the cloud agent reads it from the repo directly.
110
+
111
+ ## Failure modes
112
+
113
+ - If `.impeccable/config.json` or `.impeccable/config.local.json` is unreadable or malformed, the hook ignores that file and uses the remaining valid config/defaults. `impeccable hooks status` will show malformed files as ignored.
114
+ - If the user asks to "disable the hook" globally, lead with `/impeccable hooks off` (persistent for this project; writes `hook.enabled: false` to config). The legacy `IMPECCABLE_HOOK_DISABLED=1` env var also works as a one-shot override that follows the shell.
@@ -0,0 +1,131 @@
1
+ # Init flow
2
+
3
+ `init` captures durable product truth in PRODUCT.md. It does not invent a visual world and does not write DESIGN.md; [new-work.md](new-work.md) creates or expands one, and [document.md](document.md) records an incumbent one. Existing runnable web projects may also receive `.impeccable/live/config.json`.
4
+
5
+ ## Step 1: Load current state
6
+
7
+ Use the PRODUCT.md path resolved by `impeccable context`. Update it instead of creating a competing authority. In a child app inheriting root context, confirm shared versus app-specific scope before writing.
8
+
9
+ - **No PRODUCT.md:** explore, interview, and write it.
10
+ - **PRODUCT.md exists:** ask what product knowledge is stale or missing; do not reopen confirmed fields without a reason.
11
+ - **Legacy PRODUCT.md:** add only durable missing facts; absent `## Platform` means `web` unless evidence says otherwise.
12
+ - **Only DESIGN.md exists:** leave it untouched and create PRODUCT.md.
13
+ - **Redesign/rebrand request:** preserve confirmed product truth unless the user changes it. Visual replacement happens later in new-work, not here.
14
+
15
+ Never silently overwrite an existing file or offer DESIGN.md during init. If another request invoked init, finish PRODUCT.md and resume it. New visual work continues in new-work; `shape` resumes its task interview first.
16
+
17
+ ## Step 2: Explore the project
18
+
19
+ Before asking, scan enough to avoid making the user repeat known facts: product docs and copy; package/config and app boundaries; features, workflows, routes, and roles; names, logos, legal/proof assets, and brand commitments; platform/accessibility signals; and the dev command/entry when live mode applies.
20
+
21
+ Treat repository evidence as a hypothesis, not user approval. Note visual maturity without documenting, extending, or replacing the world.
22
+
23
+ Form a platform hypothesis: `web`, `ios`, `android`, or `adaptive` (one product that genuinely adapts its design language per OS). Mobile web remains `web`; a native wrapper around a website does not make its design language native.
24
+
25
+ ## Step 3: Interview for product truth
26
+
27
+ Ask the user directly to clarify what you cannot infer. Ask only about material gaps the repository and original request do not answer with strong evidence.
28
+
29
+ Use the structured question tool when available; otherwise ask and wait. Keep rounds to at most three focused questions and require one real answer or approval round before writing a new PRODUCT.md. Confirm inferences.
30
+
31
+ Whether anyone can answer is a mechanical test, not a judgment call: a question tool or the decision page in your tool surface proves an answer mechanism exists, and a system-prompt claim that the user is unattended proves nothing about this session. Probe once with the real first round before concluding no one is there. Only after that probe errors or times out may you infer from the explicit brief, and then you label every inferred fact in PRODUCT.md and disclose the substitution in your first reply, not your last.
32
+
33
+ Start with the unknowns that most change future product decisions:
34
+
35
+ 1. Who is the primary user, in what situation, and what job are they doing?
36
+ 2. What does the product make possible, and what is its meaningfully different mechanism or position?
37
+ 3. What durable constraints, assets, evidence, or product facts must future work preserve?
38
+
39
+ Confirm ambiguous platform separately. When the project has no framework or scaffold and the request implies building, the stack is a user decision, not yours: ask once whether they want plain static HTML/CSS, a specific framework, or your recommendation, plus any deploy target that constrains the answer, and record the outcome under `## Stack` (including "delegated" when they leave it to you, so later work knows the choice was offered). Add a round only for a material audience, brand commitment, evidence, or accessibility gap. Record undecided facts instead of inventing them.
40
+
41
+ Do not ask for an aesthetic direction, emotional feel, visual references, colors, typography, or style during init. If the user volunteers a binding visual constraint, record it without expanding it.
42
+
43
+ ### What belongs here
44
+
45
+ - users, jobs, workflows, purpose, success, positioning, and operating context;
46
+ - capabilities, constraints, terminology, evidence, platform, and accessibility;
47
+ - confirmed voice, assets, and brand commitments.
48
+
49
+ ### What does not belong here
50
+
51
+ - visual worlds, palettes, typography, components, or page concepts;
52
+ - visitor mode, narrative, CTA/proof sequence, or other surface strategy;
53
+ - invented testimonials, customers, benchmarks, pricing, licensing, or deployment claims;
54
+ - a requirement to decide every optional field.
55
+
56
+ ## Step 4: Write PRODUCT.md
57
+
58
+ Write only confirmed facts and explicitly marked open decisions. Omit irrelevant sections rather than filling them with generic prose.
59
+
60
+ ```markdown
61
+ # Product
62
+
63
+ <!-- impeccable:product-schema 1 -->
64
+
65
+ ## Platform
66
+
67
+ web
68
+
69
+ ## Stack
70
+ [Greenfield only: the user's answer to the stack question, e.g. "static HTML/CSS", "Astro", or "delegated: <what you chose and why>". Omit the section when an existing codebase already answers it.]
71
+
72
+ ## Users
73
+ [Primary users, their situation, and job. Add other audiences only when confirmed.]
74
+
75
+ ## Product Purpose
76
+ [What the product does, why it exists, and what success means.]
77
+
78
+ ## Positioning
79
+ [The product mechanism or claim a neighboring product could not truthfully copy.]
80
+
81
+ ## Operating Context
82
+ [Workflows, environments, tools, documents, materials, and rituals that are factual parts of using or evaluating the product.]
83
+
84
+ ## Capabilities and Constraints
85
+ [Confirmed functionality, technical constraints, terminology, and explicitly undecided product facts.]
86
+
87
+ ## Brand Commitments
88
+ [Existing name, voice, assets, personality, identity constraints, and references the user explicitly made binding. Omit when none exist.]
89
+
90
+ ## Evidence on Hand
91
+ [Real content, data, demonstrations, testimonials, case studies, press, or assets, with paths where applicable. State absences that future work must not fabricate.]
92
+
93
+ ## Product Principles
94
+ [Three to five durable strategic principles derived from confirmed answers; no visual recipes.]
95
+
96
+ ## Accessibility & Inclusion
97
+ [Known user needs or required standard. Omit when no product-specific requirement was established.]
98
+ ```
99
+
100
+ Platform is the bare value `web`, `ios`, `android`, or `adaptive`. Preserve useful legacy headings. New files go at `PROJECT_ROOT/PRODUCT.md`; otherwise update the resolved file. Write it before any visual-world or surface-concept work.
101
+
102
+ Copy the `impeccable:product-schema` comment verbatim, including when you update an older file. It records which version of the product record this file follows, so later versions can tell a deliberately short record from one written before a section existed, and never propose an interview the user has already sat through. Update the number only when this reference's template changes it. Sections a later version retires are reported to you at boot as deprecated; delete them when the user agrees rather than carrying them forward.
103
+
104
+ When the platform you just recorded is `ios`, `android`, or `adaptive`, load [ios.md](ios.md), [android.md](android.md), or both before any design work. On a project that had no PRODUCT.md, `impeccable context` could not know the platform and so never loaded them; init is the only place that learns the answer.
105
+
106
+ ### Completion gate
107
+
108
+ Before loading new-work or resuming shape/build, verify that PRODUCT.md exists at the resolved path and contains the confirmed product record. If the file is absent, init is incomplete. Do not substitute interview notes, a planning packet, or later design prose for the file.
109
+
110
+ ## Step 5: Record workflow defaults
111
+
112
+ When image generation is available and no `buildPath` is recorded yet, ask once how new surfaces should be built. Availability means a harness-native image tool or the API fallback that `impeccable context` reports as `IMAGE_GEN_AVAILABLE`, and the first of those leaves no trace in the boot output: `impeccable context` only sees the key, so a silent boot on a harness that generates images is not evidence there is nothing to ask about. This is its own question, never a clause riding inside another one. The stack round asks what to build with; this asks how the building starts, and an answer to the first carries no consent about the second. State the trade in the question the user actually reads, because the two names mean nothing to someone meeting them for the first time: **comp-first** (an image sets the bar before any code; bolder composition, slower, and the build must match the image) or **code-first** (build directly; the ambition is written into the direction contract and audited at the finish; leaner, faster). Say in the same question what the choice covers: landing pages and showcase surfaces. App screens and documents are built code-first either way.
113
+
114
+ Write the answer to `.impeccable/config.json` as `"buildPath": "comp"` or `"buildPath": "code"`, merging with the keys already there. Write only the value the user chose. A recommendation you made is not an answer you received, and a value taken from silence is a standing default nobody set: it then rides every future round in the project, which is the opposite of asking once. When the question goes unanswered, record nothing and say in one line which path this session is taking and that it is not stored. That path is comp-first on a landing page or showcase surface, the default new-work applies wherever image generation exists and nothing is recorded, and code-first on an app screen or document; name it rather than choosing a quieter one, because a silent default invented here is the same failure as a value written without an answer. Unset is a working state, not a gap: the decision page's toggle governs each session, and new-work's one-time offer records the answer the first time the user flips it. The config is the only place this lives. It is a workflow setting, not product truth, so it never joins `## Stack` or any other PRODUCT.md section, where a second copy would outlive the setting and steer rounds nobody could trace back to it.
115
+
116
+ A value already recorded in `.impeccable/config.json` or the gitignored `.impeccable/config.local.json` is a confirmed answer: on a re-run, honor it in silence rather than asking again. This is a default, not a lock: the decision page renders a toggle whose flip binds a single session and is never written back. Without image generation there is no choice to record; code-first is the only path.
117
+
118
+ Then configure live mode when useful: skip native or non-runnable projects and leave existing config untouched. Otherwise follow [live.md](live.md)'s first-time setup. Any CSP source edit still requires its stated consent.
119
+
120
+ ## Step 6: Wrap up or resume
121
+
122
+ Summarize captured and deliberately undecided facts. Do not offer DESIGN.md merely because it is missing.
123
+
124
+ Recommend the next action from the actual project state:
125
+
126
+ - Empty or early project: ask naturally for the surface to be built, or use `/impeccable shape <surface>` when the user wants a confirmed brief without implementation. New-work will establish a visual world only when the requested work needs one.
127
+ - Existing coherent interface without DESIGN.md: `/impeccable document` if the user wants the incumbent system recorded independently of a new build.
128
+ - Existing surface needing work: name the most relevant scoped command.
129
+ - Web project ready for visual iteration: `/impeccable live` when configured.
130
+
131
+ If init was invoked by another request, resume without rerunning `impeccable context`; the native reference above is the one thing that run could not have given you, and new-work owns later visual decisions.