diff --git a/.agent/skills/impeccable/SKILL.md b/.agent/skills/impeccable/SKILL.md index e4d2e8e03..f5da1671f 100644 --- a/.agent/skills/impeccable/SKILL.md +++ b/.agent/skills/impeccable/SKILL.md @@ -8,7 +8,7 @@ allowed-tools: - Bash(node .agent/skills/impeccable/scripts/*) --- -This skill gives you the tools and permission to create design that earns to be called out-of-distribution craft: Whereas before, your design work would have been safe, timid and measured, you now approach every design task as an award-winning design director with impeccable understanding for what makes exceptional design work: production-grade code, peak creativity, a clear POV, deep understanding of the needs of the client and users, and exceptional craft. +This skill gives you the tools and permission to create design that earns to be called out-of-distribution craft: Whereas before, your design work would have been safe, timid and measured, you now approach every design task as a award-winning design director with impeccable understanding for what makes exceptional design work: production-grade code, peak creativity, a clear POV, deep understanding of the needs of the client and users, and exceptional craft. Core principles: - Go all out. No hedging, no shortcuts. The deliverable must be complete (except assets the user must provide). @@ -18,7 +18,7 @@ Core principles: ## Setup 1. Run `node /scripts/context.mjs` once per session, where `` is the loaded base directory the runtime reports for this skill; keep cwd at the user's project. That base directory resolves every `node .agent/skills/impeccable/scripts/...` command in this skill and its references, and `.agent/skills/impeccable/scripts` is the fallback only when the runtime reports no base directory. Pass a named source file or route as `--target `. It loads PRODUCT.md, DESIGN.md, the matching surface brief, and native-platform guidance when applicable; follow its directives and do not rerun it. -2. Load the request's playbook: its Commands-table reference for an explicit/implied sub-command, or [reference/new-work.md](reference/new-work.md) for a new surface or replacement visual world. Inspect target and incumbent visual truth before editing. When the app cannot run, start with committed visual-regression goldens or screenshot fixtures; verify target and freshness against current tokens, CSS, components, or assets, resolve conflicts, and compare theme/variant captures. +2. Before acting, load the one playbook that owns the request: the Commands table's reference for an explicit or clearly implied sub-command, or [reference/new-work.md](reference/new-work.md) for a new surface or replacement visual world. Then inspect the target and at least one representative source of incumbent visual truth (tokens, theme, CSS, component, or asset) before editing. 3. After analysis and direction are resolved, load [reference/craft-floor.md](reference/craft-floor.md) immediately before editing UI. It carries the quality floor, the absolute bans, and the reflexes no detector catches. Do not load it for planning-only work. ## How to design @@ -47,7 +47,6 @@ Choose the mode from the requested surface, not the product, and persist it only | `init` | Build | Capture durable product context in PRODUCT.md | [reference/init.md](reference/init.md) | | `document` | Build | Generate DESIGN.md from existing project code | [reference/document.md](reference/document.md) | | `extract [target]` | Build | Pull reusable tokens and components into design system | [reference/extract.md](reference/extract.md) | -| `design-context [open/edit/export/import]` | Build | Reopen, revise, export, or import the design interview and its document | [reference/design-context.md](reference/design-context.md) | | `critique [target]` | Evaluate | UX design review with heuristic scoring | [reference/critique.md](reference/critique.md) | | `audit [target]` | Evaluate | Technical quality checks (a11y, perf, responsive) | [reference/audit.md](reference/audit.md) · native: [reference/audit.native.md](reference/audit.native.md) | | `polish [target]` | Refine | Final quality pass before shipping | [reference/polish.md](reference/polish.md) | diff --git a/.agent/skills/impeccable/reference/audit.md b/.agent/skills/impeccable/reference/audit.md index 3c93c8ce1..474af4154 100644 --- a/.agent/skills/impeccable/reference/audit.md +++ b/.agent/skills/impeccable/reference/audit.md @@ -99,7 +99,7 @@ For each issue, document: - **Impact**: How it affects users - **WCAG/Standard**: Which standard it violates (if applicable) - **Recommendation**: How to fix it -- **Suggested command**: Which command to use (prefer: /impeccable adapt, /impeccable animate, /impeccable audit, /impeccable bolder, /impeccable clarify, /impeccable colorize, /impeccable critique, /impeccable delight, /impeccable design-context, /impeccable distill, /impeccable document, /impeccable harden, /impeccable layout, /impeccable onboard, /impeccable optimize, /impeccable overdrive, /impeccable polish, /impeccable quieter, /impeccable shape, /impeccable typeset) +- **Suggested command**: Which command to use (prefer: /impeccable adapt, /impeccable animate, /impeccable audit, /impeccable bolder, /impeccable clarify, /impeccable colorize, /impeccable critique, /impeccable delight, /impeccable distill, /impeccable document, /impeccable harden, /impeccable layout, /impeccable onboard, /impeccable optimize, /impeccable overdrive, /impeccable polish, /impeccable quieter, /impeccable shape, /impeccable typeset) ### Patterns & Systemic Issues @@ -118,7 +118,7 @@ List recommended commands in priority order (P0 first, then P1, then P2): 1. **[P?] `/command-name`**: Brief description (specific context from audit findings) 2. **[P?] `/command-name`**: Brief description (specific context) -**Rules**: Only recommend commands from: /impeccable adapt, /impeccable animate, /impeccable audit, /impeccable bolder, /impeccable clarify, /impeccable colorize, /impeccable critique, /impeccable delight, /impeccable design-context, /impeccable distill, /impeccable document, /impeccable harden, /impeccable layout, /impeccable onboard, /impeccable optimize, /impeccable overdrive, /impeccable polish, /impeccable quieter, /impeccable shape, /impeccable typeset. Map findings to the most appropriate command. End with `/impeccable polish` as the final step if any fixes were recommended. +**Rules**: Only recommend commands from: /impeccable adapt, /impeccable animate, /impeccable audit, /impeccable bolder, /impeccable clarify, /impeccable colorize, /impeccable critique, /impeccable delight, /impeccable distill, /impeccable document, /impeccable harden, /impeccable layout, /impeccable onboard, /impeccable optimize, /impeccable overdrive, /impeccable polish, /impeccable quieter, /impeccable shape, /impeccable typeset. Map findings to the most appropriate command. End with `/impeccable polish` as the final step if any fixes were recommended. After presenting the summary, tell the user: diff --git a/.agent/skills/impeccable/reference/audit.native.md b/.agent/skills/impeccable/reference/audit.native.md index fd266cbf1..0126fa157 100644 --- a/.agent/skills/impeccable/reference/audit.native.md +++ b/.agent/skills/impeccable/reference/audit.native.md @@ -102,7 +102,7 @@ For each issue, document: - **Impact**: How it affects users - **Guideline**: The HIG / Material rule it violates (if applicable) - **Recommendation**: How to fix it -- **Suggested command**: Which command to use (prefer: /impeccable adapt, /impeccable animate, /impeccable audit, /impeccable bolder, /impeccable clarify, /impeccable colorize, /impeccable critique, /impeccable delight, /impeccable design-context, /impeccable distill, /impeccable document, /impeccable harden, /impeccable layout, /impeccable onboard, /impeccable optimize, /impeccable overdrive, /impeccable polish, /impeccable quieter, /impeccable shape, /impeccable typeset) +- **Suggested command**: Which command to use (prefer: /impeccable adapt, /impeccable animate, /impeccable audit, /impeccable bolder, /impeccable clarify, /impeccable colorize, /impeccable critique, /impeccable delight, /impeccable distill, /impeccable document, /impeccable harden, /impeccable layout, /impeccable onboard, /impeccable optimize, /impeccable overdrive, /impeccable polish, /impeccable quieter, /impeccable shape, /impeccable typeset) ### Patterns & Systemic Issues @@ -121,7 +121,7 @@ List recommended commands in priority order (P0 first, then P1, then P2): 1. **[P?] `/command-name`**: Brief description (specific context from audit findings) 2. **[P?] `/command-name`**: Brief description (specific context) -**Rules**: Only recommend commands from: /impeccable adapt, /impeccable animate, /impeccable audit, /impeccable bolder, /impeccable clarify, /impeccable colorize, /impeccable critique, /impeccable delight, /impeccable design-context, /impeccable distill, /impeccable document, /impeccable harden, /impeccable layout, /impeccable onboard, /impeccable optimize, /impeccable overdrive, /impeccable polish, /impeccable quieter, /impeccable shape, /impeccable typeset. Map findings to the most appropriate command. End with `/impeccable polish` as the final step if any fixes were recommended. +**Rules**: Only recommend commands from: /impeccable adapt, /impeccable animate, /impeccable audit, /impeccable bolder, /impeccable clarify, /impeccable colorize, /impeccable critique, /impeccable delight, /impeccable distill, /impeccable document, /impeccable harden, /impeccable layout, /impeccable onboard, /impeccable optimize, /impeccable overdrive, /impeccable polish, /impeccable quieter, /impeccable shape, /impeccable typeset. Map findings to the most appropriate command. End with `/impeccable polish` as the final step if any fixes were recommended. After presenting the summary, tell the user: diff --git a/.agent/skills/impeccable/reference/craft-floor.md b/.agent/skills/impeccable/reference/craft-floor.md index f6ca25d6a..9653b9808 100644 --- a/.agent/skills/impeccable/reference/craft-floor.md +++ b/.agent/skills/impeccable/reference/craft-floor.md @@ -2,8 +2,6 @@ Load this after the direction is settled, and build without announcing the checklist. A pinned brief or the committed visual world overrides anything here; your own habit does not. When the design hook is active it already enforces the mechanical checks below as you edit: act on its findings instead of re-auditing each rule. -A wholesale file rewrite, after a hook block or an error recovery, starts by re-opening DESIGN.md and the token sheet, so the new file restates the recorded system rather than your memory of it; memory is where a display token becomes a hand-tuned clamp. The ranking lives in [new-work.md](new-work.md): the comp rules composition; the world rules material, and a rewrite changes neither. - ## Verify Each of these is a check on the built result, not an intention. Run them together in the batched inspection rounds, not as separate screenshot trips; the checks share one render. @@ -13,7 +11,6 @@ Each of these is a check on the built result, not an intention. Run them togethe - **Spacing:** tight groups, generous separation, more space above a heading than below it. Read the computed values. - **Type:** body measure 65–75ch, display max 6rem, tracking floor -0.04em, balanced headings, obvious scale and weight steps. Run the real copy at every breakpoint and fix what overflows. - **Motion:** one authored moment, not scattered effects and not one identical entrance on every section. Exponential ease-out from an already-visible default. Reach past transform and opacity: blur, backdrop-filter, clip-path, mask, and shadow belong to the palette when they stay smooth. -- **Tokens:** a size or color a step from a defined token takes the token: `0.82rem` beside a `0.8rem` token is the token, not a new size, and inline SVG or JS-drawn strokes take `var(--role)` or `currentColor`. Wire or remove what nothing consumes before finish; done means every defined custom property is consumed by at least one rule. - **States:** hover, disabled, loading, error, empty. Plus real content, working controls, responsive composition, keyboard focus. - **Browser surfaces:** the parts you did not draw still carry the design. Text selection, the caret, custom scrollbars, focus rings, underline offset, and the numerals in tabular data all ship with browser defaults that belong to no design system. Theme them from the palette. This is the cheapest signal that a page was built rather than assembled, and the one models skip most reliably. - **Copy:** the product's own language. Controls name their action; errors name the problem and the recovery. @@ -40,7 +37,7 @@ Surface habits: - Sparklines, progress rings, and soft-shadowed rounded rectangles standing in for content. - Monospace as a costume for "technical" rather than for code, data, or measurement. - A system display face (Impact, Arial Black, the platform sans) as the display voice of an own-world page. Source and self-host a face whose character matches the approved lettering; the closest installed font is a failure, not a fallback. -- Unicode glyphs or emoji standing in for an icon system. Icons are drawn, from a real library or authored SVG, in one consistent stroke and weight. When a pack icon fails to fetch, take the nearest icon from the same pack, jsDelivr as the fallback CDN; drawing a replacement from scratch is an exception the user signs off on, so the one-pack promise survives a failed fetch. +- Unicode glyphs or emoji standing in for an icon system. Icons are drawn, from a real library or authored SVG, in one consistent stroke and weight. - Geometric masks standing in for organic contours. A circle, polygon, or radial-gradient cutout approximating a photographic subject's edge is the cheap version of the effect and reads worse than omitting it. Derive an alpha matte from the actual image, or produce a cut-out asset. - Light or dark picked by category. Pick it from the use scene: who, where, under what ambient light. diff --git a/.agent/skills/impeccable/reference/critique.md b/.agent/skills/impeccable/reference/critique.md index d1a8abdaf..187a8680c 100644 --- a/.agent/skills/impeccable/reference/critique.md +++ b/.agent/skills/impeccable/reference/critique.md @@ -1,6 +1,6 @@ ### Purpose -Resolve one stable target, run two independent assessments, synthesize a design critique, persist a snapshot, and ask the user what to improve next. The chat response is the primary deliverable; the snapshot is an archive of that run. +Resolve one stable target, run two independent assessments, synthesize a design critique, persist a snapshot, and ask the user what to improve next. The chat response is the primary deliverable; the snapshot is an archive/backlog for future commands. ### Hard Invariants @@ -84,7 +84,7 @@ After Assessment B returns usable CLI findings, reuse them. Do not rerun `detect Synthesize both assessments into a single report. Do NOT simply concatenate. Weave the findings together, noting where the LLM review and detector agree, where the detector caught issues the LLM missed, and where detector findings are false positives. -The chat response is the primary user-facing deliverable. Present the full structured critique below in chat; do not replace it with a summary and a link. The persisted snapshot is an archive of that run. +The chat response is the primary user-facing deliverable. Present the full structured critique below in chat; do not replace it with a summary and a link. The persisted snapshot is only an archive/backlog for later commands. Structure your feedback as a design director would: @@ -142,7 +142,7 @@ For each issue, tag with **P0-P3 severity** (see [Issue Severity below](#issue-s - **[P?] What**: Name the problem clearly - **Why it matters**: How this hurts users or undermines goals - **Fix**: What to do about it (be concrete) -- **Suggested command**: Which command could address this (from: /impeccable adapt, /impeccable animate, /impeccable audit, /impeccable bolder, /impeccable clarify, /impeccable colorize, /impeccable critique, /impeccable delight, /impeccable design-context, /impeccable distill, /impeccable document, /impeccable harden, /impeccable layout, /impeccable onboard, /impeccable optimize, /impeccable overdrive, /impeccable polish, /impeccable quieter, /impeccable shape, /impeccable typeset) +- **Suggested command**: Which command could address this (from: /impeccable adapt, /impeccable animate, /impeccable audit, /impeccable bolder, /impeccable clarify, /impeccable colorize, /impeccable critique, /impeccable delight, /impeccable distill, /impeccable document, /impeccable harden, /impeccable layout, /impeccable onboard, /impeccable optimize, /impeccable overdrive, /impeccable polish, /impeccable quieter, /impeccable shape, /impeccable typeset) #### Persona Red Flags > *Consult the [Personas reference](#persona-based-design-testing) below.* @@ -197,7 +197,7 @@ Skip this step if the Setup slug was null (vague or root-level target). IMPECCABLE_CRITIQUE_META='{"target":"","total_score":,"max_score":,"na_heuristics":"","p0_count":,"p1_count":}' \ node .agent/skills/impeccable/scripts/critique-storage.mjs write "" ``` - `max_score` is the applicable maximum from the heuristic table (40 when every heuristic applied), so a later run can tell a renormalized total from a full one. For a local file target, the helper also records an exact content fingerprint so polish can distinguish the assessed bytes from later edits without relying on Git state or timestamps. The helper prints the absolute path it wrote. Leave that file on disk. Polish closes it; this run does not. + `max_score` is the applicable maximum from the heuristic table (40 when every heuristic applied), so a later run can tell a renormalized total from a full one. The helper prints the absolute path it wrote. 3. **Delete the temp body file** after the write attempt completes, whether the write succeeded or failed. If deletion fails, mention `temp-file cleanup failed: ` briefly in the final output, but do not block the critique. @@ -257,7 +257,7 @@ List recommended commands in priority order, based on the user's answers: ... **Rules for recommendations**: -- Only recommend commands from: /impeccable adapt, /impeccable animate, /impeccable audit, /impeccable bolder, /impeccable clarify, /impeccable colorize, /impeccable critique, /impeccable delight, /impeccable design-context, /impeccable distill, /impeccable document, /impeccable harden, /impeccable layout, /impeccable onboard, /impeccable optimize, /impeccable overdrive, /impeccable polish, /impeccable quieter, /impeccable shape, /impeccable typeset +- Only recommend commands from: /impeccable adapt, /impeccable animate, /impeccable audit, /impeccable bolder, /impeccable clarify, /impeccable colorize, /impeccable critique, /impeccable delight, /impeccable distill, /impeccable document, /impeccable harden, /impeccable layout, /impeccable onboard, /impeccable optimize, /impeccable overdrive, /impeccable polish, /impeccable quieter, /impeccable shape, /impeccable typeset - Order by the user's stated priorities first, then by impact - Each item's description should carry enough context that the command knows what to focus on - Map each Priority Issue to the appropriate command diff --git a/.agent/skills/impeccable/reference/degraded/asset-producer.md b/.agent/skills/impeccable/reference/degraded/asset-producer.md index ac453680e..652d8d999 100644 --- a/.agent/skills/impeccable/reference/degraded/asset-producer.md +++ b/.agent/skills/impeccable/reference/degraded/asset-producer.md @@ -11,27 +11,78 @@ Do not redesign. Preserve the reference's visual role, silhouette, palette, ligh ## Decision Comps -When the parent hands you a decision card packet instead of an approved mock, the job is one comp: one card, one file, written to the card's declared `comp` path the moment it renders. The parent runs several of you in parallel, one per card, so this card is your entire contract; generate first, plan never, because the file on disk is the deliverable and the decision page is waiting on it. Work from the card's structured fields, PRODUCT.md, and on a questionnaire-seed world the packet's cue image with its **Cue, in words:** passage, nothing else; report a card too thin to brief a comp, never pad it from imagination. When the packet carries the cue, attach it to the generation call as a reference image and restate the passage's materials and light in the prompt in your own words; an attached image with no restated words leaves the model guessing what to take from it, and the cue's still-life composition never transfers, only its materials, palette, and light. A staged logo in the packet rides the same way: attach it and name it as the exact mark to reproduce, never a shape to reinterpret. Render the card's direction as a north-star comp at full fidelity: the requested surface's first viewport, prompt led by the surface's own structure (regions named in order with their scale relationships, never the world's atmosphere), fully committed in the card's own palette, type character, and material world. A native app or mobile-first surface is a portrait frame at its device viewport, never a landscape default. Every sibling renders at the same full fidelity in its own grammar, one surface, one aspect; equal commitment keeps the comparison honest. Real product name and real content only; never invent commercial claims, prices, benchmarks, or dates PRODUCT.md does not carry. Exclusions bind those claims, never a medium the card's own world has not excluded: a subject that lives in photographs keeps its photographs. Write the prompt sidecar beside the file. Return one line naming the path and any deviation, nothing more. Everything below this section is the asset-production job; none of it applies to a decision-comp run. +When the parent hands you a decision card packet instead of an approved mock, the job is one comp: one card, one file, written to the card's declared `comp` path the moment it renders. The parent runs several of you in parallel, one per card, so this card is your entire contract; generate first, plan never, because the file on disk is the deliverable and the decision page is waiting on it. Work from the card's structured fields and PRODUCT.md alone; report a card too thin to brief a comp, never pad it from imagination. Render the card's direction as a north-star comp at full fidelity: the requested surface's first viewport, prompt led by the surface's own structure (regions named in order with their scale relationships, never the world's atmosphere), fully committed in the card's own palette, type character, and material world. A native app or mobile-first surface is a portrait frame at its device viewport, never a landscape default. Every sibling renders at the same full fidelity in its own grammar, one surface, one aspect; equal commitment keeps the comparison honest. Real product name and real content only; never invent commercial claims, prices, benchmarks, or dates PRODUCT.md does not carry. Exclusions bind those claims, never a medium the card's own world has not excluded: a subject that lives in photographs keeps its photographs. Write the prompt sidecar beside the file. Return one line naming the path and any deviation, nothing more. Everything below this section is the asset-production job; none of it applies to a decision-comp run. ## Input Contract -Expect the measured spec (`.impeccable/build/spec.json`, written by `comp-spec.mjs` from the approved comp), the approved comp path, and the skill scripts path. Optionally: a subset of region ids to produce, extra prompt notes per region, and format or transparency needs. Everything else you need is in the spec: each raster region's id, kind (plate, image, texture), pixel box, sampled palette, aspect, note, and the plate path it must land on. +Expect: -If there is no spec, stop and return one line asking the parent to run `comp-spec.mjs` first. You do not inventory the comp yourself; the spec is the inventory, and a second inventory disagrees with the first. +- Approved mock path or screenshot reference. +- Crop paths or a contact sheet with crop ids. +- Output directory. +- Required dimensions, format, transparency needs, and avoid list. +- Notes on what should remain semantic HTML/CSS/SVG instead of raster. -## The job +If the source mock is attached but has no filesystem path, use it for visual planning; ask for a path only before cropping or writing assets. -Every region with `medium: raster` in the spec ships as a plate at its `plate` path. A plate is the region regenerated at asset resolution from the comp crop as reference: same subject, same composition, same palette, same lighting and material, with the UI text and page chrome removed, at 1.5x the comp region's pixel size or more. The page draws text, controls, radius, shadow, and layout in code; the plate carries what code cannot draw. Crops from the comp are references, never shipping pixels: a comp is reference grade and a shipped crop is how a beautiful comp becomes a blurry site. +Defaults unless contradicted: -Per region, in the spec's order: +- `.webp` for opaque photos, backgrounds, and textures. +- `.png` for transparent cutouts, seals, tickets, and illustrations. +- Target production size, or at least 2x display size when dimensions are known. Never default to the small size of a full-page mock crop. +- Remove UI text, navigation, buttons, labels, and body copy. +- Keep physical marks only when the parent says they are part of the asset. +- Remove letterboxing, empty padding, baked card corners, borders, shadows, caption bands, and layout background unless the parent says those pixels are intrinsic. +- Keep the final assets directory clean: only files the build will consume. Source crops, reference crops, masks, and contact sheets go in a sibling `_sources`, `sources`, or review folder. -1. `node .agent/skills/impeccable/scripts/comp-spec.mjs --crop ` writes the reference crop under `.impeccable/build/crops/`. -2. Produce the plate. With the API fallback: `node .agent/skills/impeccable/scripts/generate-image.mjs --plate --quality high` does the whole step (crop as reference, the spec's plate prompt, output size chosen from the region's aspect, the file written to its plate path, prompt embedded, and the plate scored against the crop). With a harness-native image tool: use the crop as the input image and `node .agent/skills/impeccable/scripts/comp-spec.mjs --plate-prompt ` as the prompt, write the result to the plate path, then run `node .agent/skills/impeccable/scripts/embed-prompt.mjs --prompt ""`. -3. Read the score line. `PLATE-SCORE` under 50%, or a `PLATE-WARN`, means the plate does not read as the region: open the plate beside the crop, name what drifted (subject, framing, palette, style), tighten the prompt with that, and regenerate once. Two misses on one region: keep the better plate, mark it `needs_parent_review`, and say why in one line. -4. Transparent cutouts (a figure or object on the page ground): generate on a flat chroma color absent from the subject and key it to alpha before writing the PNG; never ship the keyed background. +Ask blockers once, globally. Missing source path/crops or output directory blocks production. Exact dimensions, compression targets, retina variants, and format preferences do not; choose defaults and report them. -Do not redesign. Do not add objects, restyle, or reinterpret; the comp was approved as it is. Do not touch the page code, the spec, or the comp. Do not produce anything the spec does not list; a region the parent forgot goes back as a one-line note, not a plate. +## Workflow + +1. Inventory the full approved mock or every assigned crop. +2. Put each visual role in exactly one bucket: + - `produce`: needs generation, image editing, cleanup, cutout work, or a clean plate before it can ship. + - `direct`: ships after format conversion, compression, or renaming because the parent supplied a real standalone source: a project file, stock, or prior production art. A crop from the approved mock is never `direct`, whatever its apparent size. + - `semantic`: build in HTML/CSS/SVG/canvas, no raster output. +3. Crops from the mock are binding visual references, never shipping pixels: a full-page mock's effective resolution is reference grade, and a shipped crop, however close it looks, is how a beautiful comp becomes a blurry site. Every mock-derived asset goes through `produce` as a clean regeneration. +4. Give the parent an execution order for the `produce` bucket. +5. For produced assets, choose the least inventive strategy: image-to-image clean plate, faithful regeneration from crop reference, transparent cutout, texture/pattern reconstruction, stock/project source, or a semantic HTML/CSS/SVG recommendation when raster is wrong. +6. Use the harness's native image tool by default when generation or editing is needed; otherwise use the skill's generate-image.mjs. + +7. Remove baked-in UI text, navigation, buttons, body copy, and mock chrome unless the text is part of the asset. +8. Think through the final DOM/CSS representation before generating. If CSS will own radius, clipping, shadows, borders, perspective, responsive cropping, captions, or card frames, do not bake those into the bitmap. +9. Save outputs non-destructively in the requested project directory, and leave the intent with the file: after every generation, run `node .agent/skills/impeccable/scripts/embed-prompt.mjs --prompt ""` so the prompt lives inside the image itself. The build thread composes what you made and needs to know what it is looking at, and the embedding survives copies where sidecars get lost. +10. Compare each output against its source crop, opening every image by its workspace-relative path; sandboxed viewers reject absolute paths. If a review/QA tool is available, run it before the final manifest, then retry each major/fatal finding once before finalizing. + +Use `texture/pattern extraction` only when the source region is already clean enough to sample as texture. If UI, cards, labels, headings, body copy, or footer chrome must be removed first, classify it as crop-derived cleanup or clean-plate work. + +Use `semantic` for dashboards, charts, controls, screenshots of whole UI sections, data widgets, card chrome, app frames, icon toolbars, logos, wordmarks, and anything the final implementation can render crisply in HTML/CSS/SVG/canvas. Ship a screenshot raster only when the parent explicitly says the screenshot itself is the final asset. + +Semantic does not mean ignored. For every semantic role, write a concrete implementation handoff for the parent craft agent: the DOM/component layers, CSS-owned visual treatment, SVG/canvas/icon-library pieces, responsive behavior, and which nearby produced raster assets it composes with. For logos and icons, prefer inline SVG/vector or icon-library implementation unless the parent provides a production logo raster. + +## Prompt Pattern + +Use this shape for image-to-image work: + +```text +Use the provided crop as the approved visual reference. +Recreate the same asset as a clean reusable production image at the target component aspect ratio and at least 2x display resolution. +Preserve silhouette, object/scene perspective, camera angle, palette, lighting, material, texture, and visual role. +Remove baked-in UI copy, navigation, buttons, labels, body text, watermarks, and mock chrome unless explicitly part of the asset. +Remove letterboxing, padding, card borders, rounded clipping, CSS shadows, perspective transforms, caption bands, and layout backgrounds that the implementation should create in code. +Do not add new objects. Do not change the concept. Do not redesign the composition. +``` + +For transparent cutouts: use true alpha when the tool supports it; otherwise generate on a flat chroma-key color that cannot appear in the subject and post-process that color to alpha before shipping the PNG/WebP. Never ship the keyed background as the final asset. ## Output Contract -Return one line per raster region: ` % `. Then `blockers` (missing spec, missing comp, no image capability, exhausted key) and `assumptions`, each global and minimal. Nothing else: no summary, no praise, no implementation advice. The parent runs `build-phase.mjs advance` to verify the plates against the same spec; your line and its line must agree. \ No newline at end of file +Return a complete manifest, grouped by `produce`, `direct`, and `semantic`. For each asset include: `id`, `source_crop`, `output_path` when applicable, `strategy`, `prompt_used` when applicable, `dimensions`, `format`, `transparency`, `deviations`, and `qa_status`. + +For each semantic row include `id`, `implementation`, `notes`, and `qa_status`. The `implementation` is a concrete build handoff, not a note that no asset was produced: name the likely HTML/CSS/SVG/canvas/icon/component pieces and the visual responsibilities code owns. + +`qa_status` is `accepted`, `needs_parent_review`, or `blocked`. `accepted` only after visual comparison passes. `needs_parent_review` for cut-off subjects, unwanted borders or rounded-card chrome, letterboxing, baked semantic text, low-resolution output, perspective that should have been CSS, missing transparency, or drift from the crop. `blocked` when inputs, permissions, image capability, or asset source quality prevent a credible result. + +End with `execution_order`, `blockers`, and `assumptions` sections. Keep blockers global and minimal; per-asset rows carry only asset-specific risks or decisions. + +Do not modify implementation code. Do not edit the approved mock. Do not produce final page copy. The parent craft agent owns implementation and final mock fidelity. \ No newline at end of file diff --git a/.agent/skills/impeccable/reference/degraded/finish-reviewer.md b/.agent/skills/impeccable/reference/degraded/finish-reviewer.md index 433cc72b9..e2a4fd130 100644 --- a/.agent/skills/impeccable/reference/degraded/finish-reviewer.md +++ b/.agent/skills/impeccable/reference/degraded/finish-reviewer.md @@ -11,16 +11,16 @@ A hard turn ceiling ends the run without warning; a run that ends before its con ## Input Contract -Expect: the original request; the confirmed user answers; the artifact path(s); the screenshots the parent captured, in `.impeccable/review/` (web: `desktop.png` and `mobile.png`; native: device-class names such as `phone.png` and `tablet.png`, suffixed per OS on adaptive). A screenshot path the calling brief names is authoritative when the file exists; `.impeccable/review/` is where to look when the brief names none or a named path is missing, never a filename you invent. Also expect: the direction contract (THESIS, OWN-WORLD, STORY, FIRST VIEWPORT, FORM); the PRODUCT.md path; existing hook or detector findings; the chosen world's QUALITY BAR card paths; on a comp-led build the approved comp path (a code-led build has none; it passes the chosen decision comp as a separate critique-reference input, labeled as such, and nothing here that binds "the approved comp" binds it); on a comp-led build the build state (`.impeccable/build/state.json`), the measured spec (`.impeccable/build/spec.json`), and the diff directories `.impeccable/review/diff/hero/` and `.impeccable/review/diff/final/` (each holds `side-by-side.png`, `heatmap.png`, `regions/.png` paired crops, and `report.json` with per-region scores and verdicts from `comp-diff.mjs`); and the skill's `reference/craft-floor.md` path. On a native (`ios` / `android` / `adaptive`) build the packet adds the platform reference path(s) (`reference/ios.md` / `reference/android.md`) and a line saying no detector ran: read the platform reference alongside the craft floor, judge every check in the platform's own conventions, treat the screenshots as device captures, and know your floor check is the build's only slop gate. When the harness can view images, open the screenshots, the comp, and the card first, and inventory the comp's salient elements in your own words before reading the direction contract or any builder-authored summary: a review anchored on the contract inherits whatever the builder's abstraction dropped. +Expect: the original request; the confirmed user answers; the artifact path(s); the screenshots the parent captured, in `.impeccable/review/` (web: `desktop.png` and `mobile.png`; native: device-class names such as `phone.png` and `tablet.png`, suffixed per OS on adaptive). A screenshot path the calling brief names is authoritative when the file exists; `.impeccable/review/` is where to look when the brief names none or a named path is missing, never a filename you invent. Also expect: the direction contract (THESIS, OWN-WORLD, STORY, FIRST VIEWPORT, FORM); the PRODUCT.md path; existing hook or detector findings; the chosen world's QUALITY BAR card paths; on a comp-led build the approved comp path (a code-led build has none; it passes the chosen decision comp as a separate critique-reference input, labeled as such, and nothing here that binds "the approved comp" binds it); and the skill's `reference/craft-floor.md` path. On a native (`ios` / `android` / `adaptive`) build the packet adds the platform reference path(s) (`reference/ios.md` / `reference/android.md`) and a line saying no detector ran: read the platform reference alongside the craft floor, judge every check in the platform's own conventions, treat the screenshots as device captures, and know your floor check is the build's only slop gate. When the harness can view images, open the screenshots, the comp, and the card first, and inventory the comp's salient elements in your own words before reading the direction contract or any builder-authored summary: a review anchored on the contract inherits whatever the builder's abstraction dropped. ## Checks, in order 0. **Evidence.** Before any other check, verify the required captures exist and every capture is valid. Required: the platform's full viewport set (web: `desktop.png` and `mobile.png`; native: one capture per shipped device class), plus every capture the calling brief names as required, a reported user viewport (`user-.png`) included. Valid: no black or blank regions, content matching what the filename claims (a visit capture showing the About section is invalid), the document top visible where the file claims a full page, dimensions that make sense for the named viewport. A required capture that is absent fails exactly like one that is malformed: a viewport nobody captured is a viewport nobody inspected, and it cannot ship. When any capture fails, the whole review changes shape: return `disposition: recapture` as the first line, then one section, `recapture`, listing each missing or invalid file and what a valid capture of it shows, and stop. Never build a matrix on malformed evidence; a verdict derived from a broken capture launders the breakage into an approval, and the parent owes you a full re-review on valid captures, not a scoring round. -1. **Persistence.** PRODUCT.md exists. On a comp-led build, `.impeccable/build/state.json` exists and its `comps` (or `skipped` when a surface round locked the comp), `spec`, `plates`, and `hero` phases are `closed`; a comp-led config with no state file, or a state whose `comps` phase never closed, means the comp round was skipped and the build ran from a world description alone, a material finding that outranks craft; a phase closed with a `forced` record is disclosed as a material finding unless the user downgraded the comp in words the packet quotes; a state file whose `hero.gate.score` sits under 0.72, or a missing state file, means the reproduction ran unproven, a material finding, and `.impeccable/review/hero-repro.png` must exist either way. When a seed or prior DESIGN.md predates this build, it matches the built world, and "matches" is evidence you grep, not an impression: custom properties DESIGN.md defines that no rule consumes, literals sitting a step from a defined token, geometry a named rule bans (a 999px pill against a Slightly Soft rule). Each hit is a material finding under the craft floor's token rule, and an approved comp excuses none of them: the comp rules composition; the world rules material. On a new world with no seed, DESIGN.md is written after this review by the documenter, so its absence here is not a finding. When comp-round comps exist under `.impeccable/mocks/`, an approval record exists too: the surface brief naming the approved comp, or an `approved` flag in its sidecar. Comp-round comps with no recorded pick mean the approval point was skipped, a material finding. Files under `.impeccable/mocks/decision/` are exempt: they are the direction round's dealt hand, produced before any comp round, and imply no approval whatever the build path; a code-led build has no comp round at all. -2. **Fidelity.** Start from the measurement, then judge what it cannot: read `.impeccable/review/diff/final/report.json` (and hero) first; every region scored `missing` or `contradicted` is a matrix row in that state unless the paired crop under `regions/` shows the score is wrong, and you say why; a region scored `match` still gets your eye for lettering character and material, which the numbers do not measure. Then, against your own element inventory of the approved comp, never against the contract's summary of it: topology, reading order, focal scale, overlaps and z-order, density, signature geometry, the primary action's treatment (a CTA the comp physically works, dissolves, or stamps is a signature element; its plain-rectangle rendition is contradicted), navigation items and icons, headline levels and scale relationships. Classify every salient element: match, acceptable adaptation, missing, contradicted, or added without approval. Three rows are mandatory in every matrix. TYPE: the display lettering's character, compression, width, weight, contrast, terminals, against the comp's; a face of a different character is contradicted however the layout matches. MATERIAL: an element rendered as flat CSS or clean vector where the comp shows painted, textured, dimensional, or photographic material is contradicted regardless of placement; medium is part of the promise. GROUND: the page field's value and temperature against the comp's, sampled from pixels on both sides when tooling allows rather than judged from memory, and read as the net on-screen result where a texture or tile paints over the base color; a ground warmer or cooler than the comp's is contradicted however faithfully the layout matches, and drift toward the rendition prior (warm cream on light grounds, blue-black slate on dark) is the direction to hunt. With no approved comp, TYPE and MATERIAL do not lapse: judge them against the contract's OWN-WORLD and the world's real materials, and treat faked physicality (CSS bevels, embossing, stamped-metal or chalk effects imitating a material the page never renders) as contradicted on its face; imitation material is the single most reliable mark of machine-made design. GROUND narrows rather than lapses: with no comp to sample, a color OWN-WORLD names is the target and the same warmer-or-cooler judgment applies; when OWN-WORLD names none, there is no GROUND authority, and the review says so in place of a verdict, because a target the reviewer invents turns the check into taste. A critique-reference comp on such a build is provocation, not spec: no element matrix, no adaptation citations, no asset obligations; its one contribution is what the image dared that the build did not, and dares worth adopting enter material_fixes as ordinary ordered fixes. An adaptation counts as intentional only when it cites the user answer, surface brief, accessibility need, or product truth that forced it; an uncited deviation is a defect. A missing signature element, a changed topology, or content added without approval fails fidelity and outranks every craft point in material_fixes. When MATERIAL is contradicted on the focal element, or contradiction is the page rather than the exception, stop ordering repairs: make the first material fix a rebuild directive naming the comp regions to re-derive and the assets to produce; a list of patches against a rejected page launders the rejection into an approval. A fix that requires producing an asset says so explicitly ("produce: as a raster asset"), never phrased as a style adjustment the parent will answer with CSS. The comp is the spec for composition, topology, element inventory, density, lettering character, and material; it is not a pixel spec for semantics, accessibility, or responsive reflow, and that allowance covers translation, never replacement. -3. **Ceiling.** Against the QUALITY BAR card: name the world's native devices the build left unused, frame, depth, lettering treatment, ornament density, motion. A committed motion energy shows up as eased state changes in the shipped code; a recorded energy with zero transitions is a finding. The card governs commitment and finish, never composition. +1. **Persistence.** PRODUCT.md exists. On a comp-led build, `.impeccable/review/hero-repro.png` exists: the hero reproduction checkpoint's capture at the comp's own dimensions; its absence means the reproduction phase ran unproven, a material finding. When DESIGN.md predates this build (an extension or redesign), it matches the built world; on a new world it is written after this review by the documenter, so its absence here is not a finding. When comp-round comps exist under `.impeccable/mocks/`, an approval record exists too: the surface brief naming the approved comp, or an `approved` flag in its sidecar. Comp-round comps with no recorded pick mean the approval point was skipped, a material finding. Files under `.impeccable/mocks/decision/` are exempt: they are the direction round's dealt hand, produced before any comp round, and imply no approval whatever the build path; a code-led build has no comp round at all. +2. **Fidelity.** Against your own element inventory of the approved comp, never against the contract's summary of it: topology, reading order, focal scale, overlaps and z-order, density, signature geometry, the primary action's treatment (a CTA the comp physically works, dissolves, or stamps is a signature element; its plain-rectangle rendition is contradicted), navigation items and icons, headline levels and scale relationships. Classify every salient element: match, acceptable adaptation, missing, contradicted, or added without approval. Three rows are mandatory in every matrix. TYPE: the display lettering's character, compression, width, weight, contrast, terminals, against the comp's; a face of a different character is contradicted however the layout matches. MATERIAL: an element rendered as flat CSS or clean vector where the comp shows painted, textured, dimensional, or photographic material is contradicted regardless of placement; medium is part of the promise. GROUND: the page field's value and temperature against the comp's, sampled from pixels on both sides when tooling allows rather than judged from memory, and read as the net on-screen result where a texture or tile paints over the base color; a ground warmer or cooler than the comp's is contradicted however faithfully the layout matches, and drift toward the rendition prior (warm cream on light grounds, blue-black slate on dark) is the direction to hunt. With no approved comp, TYPE and MATERIAL do not lapse: judge them against the contract's OWN-WORLD and the world's real materials, and treat faked physicality (CSS bevels, embossing, stamped-metal or chalk effects imitating a material the page never renders) as contradicted on its face; imitation material is the single most reliable mark of machine-made design. GROUND narrows rather than lapses: with no comp to sample, a color OWN-WORLD names is the target and the same warmer-or-cooler judgment applies; when OWN-WORLD names none, there is no GROUND authority, and the review says so in place of a verdict, because a target the reviewer invents turns the check into taste. A critique-reference comp on such a build is provocation, not spec: no element matrix, no adaptation citations, no asset obligations; its one contribution is what the image dared that the build did not, and dares worth adopting enter material_fixes as ordinary ordered fixes. An adaptation counts as intentional only when it cites the user answer, surface brief, accessibility need, or product truth that forced it; an uncited deviation is a defect. A missing signature element, a changed topology, or content added without approval fails fidelity and outranks every craft point in material_fixes. When MATERIAL is contradicted on the focal element, or contradiction is the page rather than the exception, stop ordering repairs: make the first material fix a rebuild directive naming the comp regions to re-derive and the assets to produce; a list of patches against a rejected page launders the rejection into an approval. A fix that requires producing an asset says so explicitly ("produce: as a raster asset"), never phrased as a style adjustment the parent will answer with CSS. The comp is the spec for composition, topology, element inventory, density, lettering character, and material; it is not a pixel spec for semantics, accessibility, or responsive reflow, and that allowance covers translation, never replacement. +3. **Ceiling.** Against the QUALITY BAR card: name the world's native devices the build left unused, frame, depth, lettering treatment, ornament density, motion. The card governs commitment and finish, never composition. 4. **Contract, promise by promise.** First verify FORM carries the seed key the concept roll printed; a contract with no seed key, or one the parent cannot corroborate, means the roll was skipped, a material fix ahead of any craft point. Then, for each of the five blocks: does the render keep the promise? Apply the memory test to the first viewport. -5. **Truth.** Demonstration data authored and labeled synthetic; no invented commercial claims; unanswered claims present as marked placeholders, not omissions. Every raster region of the spec shipped as its plate (the spec names the file; the page references it; the region's diff row is not `missing`), not a gradient, an inline SVG, or a many-vertex `clip-path` standing in for it, and every produced asset visibly present in the screenshots; an asset applied at near-zero opacity or buried behind a wash is a compliance token, not a shipped material, and the detector's `buried-raster` and `organic-clip-path` findings in the packet are material fixes. +5. **Truth.** Demonstration data authored and labeled synthetic; no invented commercial claims; unanswered claims present as marked placeholders, not omissions. Every image-native region of the approved comp shipped as a real asset, not a gradient standing in for one, and every produced asset visibly present in the screenshots; an asset applied at near-zero opacity or buried behind other paint is a compliance token, not a shipped material. 6. **Floor.** Read the craft floor's Refuse list and hold the screenshots against it: kickers and eyebrows, hard offset shadows outside a neobrutalist world, glyph icons, system display faces, gradient text, side stripes, and the rest. A banned element is a material fix even when it matches nothing in the comp: the builder loaded the same ban before writing it, and fidelity to a comp cannot authorize what the floor refuses. The parent's hook findings cover this mechanically where hooks run; this check exists because hookless harnesses reach you with none, and the last two live sessions shipped five kickers past a reviewer that never looked. Do not run a second detector pass; mechanical findings belong to the parent's hooks. diff --git a/.agent/skills/impeccable/reference/design-context.md b/.agent/skills/impeccable/reference/design-context.md deleted file mode 100644 index 06068b190..000000000 --- a/.agent/skills/impeccable/reference/design-context.md +++ /dev/null @@ -1,93 +0,0 @@ -# Design Context - -Loaded by `/impeccable design-context`. Owns the design interview record, the document built from it, and its portable form. The interview itself is created by `/impeccable document` seed mode; this command is everything afterwards. - -## Where it lives - -One store, under the project root: - -```text -.impeccable/design-context/ - context.json the chat half of the interview: product, audience, brand, interview - answers.json the questionnaire's decisions - assets/ brand files the user supplied - fonts/ font faces the user uploaded - cue.png the chosen cue image, copied at submit - runtime/ session.json, journal.jsonl, draft.json (local, gitignored) - exports/ the written-out forms (local, gitignored) -``` - -`.impeccable/visual-cues/` is separate on purpose: it is the generation workspace, regenerable and gitignored, and the document no longer depends on it. The store is the user's own record and is theirs to commit. - -## No argument - -Report status in two lines, then act: - -- Whether `answers.json` exists, and when it was last written. -- Whether a draft is waiting (`runtime/draft.json`), whether DESIGN.md is seeded, and whether a session is live (`runtime/session.json` naming a running process). - -With answers on disk, do `open`. Without them, say the design context is created by the questionnaire and offer `/impeccable document`. Never start the questionnaire unasked. - -## open - -Reopen the document, live for edits. - -Run `node .agent/skills/impeccable/scripts/picker-server.mjs --doc` from the project root as a foreground command and parse its `PICKER_URL` line. Open it and wait exactly as [visual-cues.md](visual-cues.md)'s launch paragraph does: its harness-browser ladder (in-IDE browser first, then another browser tool, then the system opener, then telling the user the URL) and its wait-on-the-foreground-process rule. Skip everything earlier in its Step 7: the cue announcement and the `modes` and `context` writes belong to a run that is generating cues, and this one is not. - -Then enter the document edit loop below. The process exiting is the signal: - -- `DOC_SESSION_ENDED` and exit 0: the document was closed. Say so in one line; the loop is over. -- Exit 2: it timed out or was never opened. Say it can be reopened with the same command, and never relaunch unprompted. -- Exit 1: no interview exists. Route to `/impeccable document`. - -## edit - -Re-run the questionnaire over the previous answers. - -Say in one line what it will do before launching, and settle DESIGN.md in the same breath, because a new run replaces the seed the last one produced: *"This re-runs the questionnaire with your previous answers filled in. When you finish, I will refresh DESIGN.md from the new answers. Refresh it, overwrite it, or merge by hand?"* That is the whole consent for this run; do not ask again afterwards. - -Then run `node .agent/skills/impeccable/scripts/picker-server.mjs`, using the same launch ladder and wait rule as `open`. Prefill happens on its own: an unfinished run resumes from its draft, a finished one loads its answers, and `--fresh` starts blank. Cues and `context.json` already exist from the previous run, so do not regenerate cues and do not repeat Step 7's pre-launch writes. - -On exit 0, go to [document.md](document.md) Steps 5-6 and write the seed from the new `answers.json`, honoring the choice made before launch. On exit 2, nothing was answered and nothing changed. - -If `.impeccable/visual-cues/cues.json` is missing, the questionnaire cannot run: its palette screen loads the dealt cues and the built-in seeds together and neither arrives without that file. Say so and offer a full `/impeccable document --seed` run instead. - -## export - -```text -node .agent/skills/impeccable/scripts/design-context-export.mjs [--out DIR] [--no-assets] -``` - -Writes two files and prints an `EXPORTED` line for each. Tell the user what each is for, in one line each: - -- `design-context.md` is the design context as one readable document. It is what to hand another tool, another agent, or a collaborator who needs to follow this design. -- `design-context.bundle.json` is the same context in a form `/impeccable design-context import` reads, including the files the user supplied. - -Do not read the export back into the conversation; the user asked for a file, not a recitation. - -## import - -```text -node .agent/skills/impeccable/scripts/design-context-import.mjs [--design skip|write] [--force] -``` - -It refuses a project that already has a design context unless `--force`, and refuses while a document is open either way. Report what it prints: - -- `DESIGN_MD carried` with a DESIGN.md already here: ask whether to refresh it from the imported context, overwrite it, or merge by hand, then act. -- `DESIGN_MD carried` with none here: offer to write it (`--design write`) or to re-seed from the imported answers through [document.md](document.md) Steps 5-6. -- `DESIGN_MD absent`: say the bundle carried decisions but no design document, and offer to seed one. - -Then offer `open`. - -## The document edit loop - -The document is a working surface. Follow [visual-cues.md](visual-cues.md)'s "The document edit loop" section; it is the canonical contract for polling, the event kinds, and the reply commands. Two things to hold on to while you are in it: - -- **The session is the only writer of the store.** Never edit `answers.json` or `context.json` yourself while a session runs. Values you settle travel on your reply, through `--answers` or `--context`. DESIGN.md and PRODUCT.md are yours to write directly. -- **A `save_batch` is already applied.** The user's values are in the store before you hear about them. Your work is the prose those values leave stale, in whichever document the event's `downstream` names. - -## Pitfalls - -- Never poll `answers.json` while a server runs. The process exiting is the signal. -- Never drive the questionnaire yourself. The answers are the user's, and a run you filled in is a run they did not make. -- Editing in the document changes values that are already there. A field the interview never captured is added by asking in chat, not by this command. diff --git a/.agent/skills/impeccable/reference/document.md b/.agent/skills/impeccable/reference/document.md index 99493a258..9da0bc743 100644 --- a/.agent/skills/impeccable/reference/document.md +++ b/.agent/skills/impeccable/reference/document.md @@ -64,7 +64,6 @@ Omit irrelevant sections rather than filling them with invented rules. Put respo ## When to run - New-work found a coherent incumbent visual system but no `DESIGN.md`. -- New-work paused before its direction roll on a project with no `DESIGN.md` and the user accepted the seed questionnaire recommendation; run seed mode. - The first implementation of a new world is complete and its provisional decisions need to be carbonized. - An existing `DESIGN.md` is stale (the design has drifted). - Before a large redesign, to capture the current state as a reference. @@ -74,9 +73,9 @@ If a `DESIGN.md` already exists, **do not silently overwrite it**. Show the user ## Two paths - **Scan mode** (default): the project has design tokens, components, or rendered output. Extract, then confirm descriptive language. Use when there's code to analyze. -- **Seed mode**: the project is pre-implementation (fresh init, nothing built yet). Decide first whether the browser questionnaire can run, gather any existing brand assets, interview in chat (three named references and one anti-reference when the questionnaire will run; five high-level answers when it will not), then write a seed DESIGN.md marked `` that carries every decision the interview and the questionnaire made. Re-run in scan mode once there's code. +- **Seed mode**: the project is pre-implementation. Ensure PRODUCT.md exists, then reuse new-work's visual-world workshop and write its directional DESIGN.md seed. Re-run in scan mode once there's code. -Decide by scanning first (Scan mode Step 1). If the scan finds no tokens, no component files, and no rendered site, offer seed mode; don't silently switch. `/impeccable document --seed` forces seed mode on a pre-implementation project, but it does not authorize replacing coherent code: when an incumbent system exists, offer scan mode or route an explicit identity-replacement request through new-work. +Decide by scanning first (Scan mode Step 1). If the scan finds no tokens, no component files, and no rendered site, offer seed mode; don't silently switch. `/impeccable document --seed` requests new-work's world workshop, but it does not authorize replacing coherent code: when an incumbent system exists, offer scan mode or route an explicit identity-replacement request through new-work. ## Scan mode (approach C: auto-extract, then confirm descriptive language) @@ -309,7 +308,7 @@ The `html` and `css` fields must be **self-contained, drop-in snippets** that re 1. **Tailwind expansion.** If the source uses Tailwind (className="bg-primary text-white rounded-lg px-6 py-3"), expand every utility to literal CSS properties in the `css` string. Do **not** reference Tailwind classes; do **not** assume a Tailwind CSS bundle is loaded. Each component is self-contained. 2. **Token resolution.** If the project exposes tokens as CSS custom properties on `:root` (e.g. `--color-primary`, `--radius-md`), reference them via `var(--color-primary)`; they inherit through the shadow DOM and stay live-bound. If tokens live only in JS theme objects (styled-components, CSS-in-JS), resolve to literal values at generation time. -3. **Icons.** Inline as SVG. Do not reference Lucide/Heroicons packages, icon fonts, or ``. A typical icon is 16-24px; copy the SVG path data directly. This is about how a snippet ships, not about which family the project draws from: when the design names an icon set, keep using that set's glyphs and paste their path data in. +3. **Icons.** Inline as SVG. Do not reference Lucide/Heroicons packages, icon fonts, or ``. A typical icon is 16-24px; copy the SVG path data directly. 4. **States.** Include `:hover`, `:focus-visible`, and (if meaningful) `:active` rules inline. A static default-only snapshot makes the panel feel dead. Hover + focus rules in the CSS make it feel alive. 5. **Reset bloat.** Extract only the component's *distinctive* CSS (background, color, padding, border-radius, typography, transition). Skip universal resets (`box-sizing: border-box`, `line-height: inherit`, `-webkit-font-smoothing`). The panel already has a neutral canvas; don't re-ship resets. 6. **Scoped class names.** Prefix every class with `ds-` (e.g. `ds-btn-primary`, `ds-input-search`) so component CSS doesn't collide with other components' CSS in the same shadow DOM. @@ -350,138 +349,46 @@ Your own write is the freshest source; subsequent commands in this session don't ## Seed mode -For projects with no visual system to extract yet. Produces a minimal, user-chosen scaffold, not a fabricated token spec. +For projects with no visual system to extract yet. Produces a user-chosen visual-world scaffold, not a fabricated token spec. + +### Step 1: Route through new-work's workshop PRODUCT.md is the prerequisite. If it is missing, load [init.md](init.md) and complete its product interview first. Do not create a visual identity without durable product context. -### Step 1: Decide the path, confirm seed mode, and ask for assets +If PRODUCT.md exists, load [new-work.md](new-work.md) and resolve visual authority. Seed mode requires a concrete first surface: use the target the user named, or ask what they want to make first. Run new-work's **Create or replace the visual world** flow, then **Commit the world**, so the visual world and its first expression are chosen together. Stop after the directional DESIGN.md seed and surface brief; do not implement. A structured simulated user counts as the user and must get the same choice. -The browser questionnaire asks color strategy and motion per surface and picks concrete typefaces and a type scale by eye, so whether it will run decides what the chat interview may ask. Decide the path **before the first question**, never after the interview: +If new-work already completed the workshop in this session, use its chosen direction directly. Do not ask again. -- **The harness has native image generation** (Codex's `image_gen`, an equivalent MCP tool, or similar): the questionnaire path; the cues are generated directly at Step 4, no setup needed. This branch wins even when `.impeccable/.env` already holds an `IMAGE_GEN_API_KEY` or an earlier run in another harness left a wrapper script behind; those are fallbacks for keyless harnesses, not the preferred path. A native tool that **cannot generate** (zero credits, failed auth) counts as absent: fall through to the next branch without asking, and mention the swap in the final report. -- **No usable native path, key already in `.impeccable/.env`**: the questionnaire path, with no pause and no questions. Load [image-api.md](image-api.md) and use its shipped wrapper; it pre-answers everything this path has ever stopped to ask, including which provider the key belongs to. -- **No usable native path, no key**: pause. Ask the user directly to clarify what you cannot infer. Ask whether the user wants generated visual cues to pick a palette by eye. *"I can generate a few small palette-and-mood images so you choose a direction visually instead of from descriptions. That needs an image-generation API key (FLUX and Google Nano Banana are supported out of the box; other providers work too), stored as `IMAGE_GEN_API_KEY` in `.impeccable/.env`. Add one, or skip straight to the chat interview?"* If a key arrives, write it to `.impeccable/.env` together with `IMAGE_GEN_PROVIDER` (`bfl` for FLUX, `gemini` for Nano Banana, the provider's own name for anything else; when the user does not say, let the wrapper infer it from the key). Confirm that file is listed in the project's `.gitignore` (add it if missing; a committed key is a leak), then load [image-api.md](image-api.md). Its shipped wrapper is the whole integration for the built-in providers; only a provider it does not know earns the project-local wrapper that file specifies. A key arriving makes this the questionnaire path. -- **The user opts out, or no key arrives**: the interview-only path. The assets ask below, the five questions in Step 3, then Steps 5-6 from the interview alone. +### Step 2: Write seed DESIGN.md -Then confirm seed mode and ask for assets, framed for the path: +Use the canonical section order from Scan mode. Populate the selected workshop direction and leave unresolved implementation facts as honest placeholders. The seed commits a world and its invariants; it does not pretend implementation tokens already exist. -- **Questionnaire path**: *"There's no existing visual system to scan. You'll pick the visual direction by eye in a browser questionnaire; before I generate its options, three quick things. First: if you have any visual assets (a logo, reference or product images, moodboards), drop them in or point me at the files. They're extra context that makes the first DESIGN.md seed more accurate. You can re-run `/impeccable document` once there's code, to capture the real tokens and components. OK?"* -- **Interview-only path**: *"There's no existing visual system to scan. I'll ask five quick questions to seed a starter DESIGN.md. First: if you have any visual assets (a logo, reference or product images, moodboards), drop them in or point me at the files. They'll ground the questions in what you already have. You can re-run `/impeccable document` once there's code, to capture the real tokens and components. OK?"* - -Also glance for assets already in the project (`assets/`, `public/`, `brand/`, image files at the root); name anything found so the user can confirm it's relevant. Assets are optional: one ask, then proceed with whatever arrived. - -If the user prefers to skip entirely, stop. No file. - -### Step 2: Read the assets - -Look at every asset provided (attached in chat or a file path) and record what it tells you, before writing the questions: - -- **Logo**: sample the exact colors, note letterform character (geometric / humanist / serif) and temperature. -- **Reference / product images**: density, palette, type feel; what the user is drawn to. -- **Moodboards**: recurring hues, textures, era, register cues. - -On the questionnaire path, the files themselves also feed the design context document the picker shows after the last question. When the user provided actual files (a logo, a mood board, a reference image), copy each one into `.impeccable/design-context/assets/`, keeping its filename. Record every staged file for Step 4's context write: it becomes an object entry in `context.json` `context.assets`, `{ "file": "", "kind": "logo" | "moodboard" | "reference", "note": "" }`, where the note is what this step read off it. An observation with no file behind it stays a plain string entry, as before. On the interview-only path, stage nothing; the observations feed the questions and the seed alone. - -These observations exist to sharpen Step 3. **No assets: skip straight to Step 3** with generic options. - -### Step 3: The interview - -Group each path's questions into one `AskUserQuestion` interaction. Options must be concrete. Keep skill vocabulary (seed, register, anti-reference) out of question text; ask for the thing in words the user would use. Ask like a magazine editor profiling the brand: curious and narrative, drawing out the feel the surface should carry. - -**Questionnaire path: two questions, nothing more.** With Step 1's assets ask these are the whole chat interview; the questionnaire asks everything else by eye. - -1. **Three named references.** Brands, products, printed objects. Not adjectives. When Step 2 produced observations, ground candidate names in them (references drawn from the moodboard's era). -2. **One anti-reference.** What the product should NOT feel like. Also named. - -**Do not ask about color, typography, or motion here; the questionnaire owns them.** It asks color strategy and motion per surface and picks concrete typefaces and a type scale, so a chat answer would be asked again by eye and one of the two would be thrown away. Both answered, go straight to Step 4. - -**Interview-only path: five questions.** When Step 2 produced observations, ground the options in them: offer the logo's sampled color as a hue anchor in Q1, a type direction that matches the letterforms in Q2, candidate named references drawn from the moodboard's era in Q4. The user should recognize their own material in the choices. - -1. **Color strategy.** Pick one: - - Restrained: tinted neutrals + one accent ≤10% - - Committed: one saturated color carries 30–60% of the surface - - Full palette: 3–4 named color roles, each deliberate - - Drenched: the surface IS the color - - Then: one hue family or anchor reference ("deep teal", "mustard", "Klim #ff4500 orange"). - -2. **Typography direction.** Pick one (specific fonts come later): - - Serif display + sans body - - Single sans (warm / technical / geometric / humanist; pick a feel) - - Display + mono - - Mono-forward - - Editorial script + sans - -3. **Motion energy.** Pick one: - - Restrained: state changes only - - Responsive: feedback + transitions, no choreography - - Choreographed: orchestrated entrances, scroll-driven sequences - -4. **Three named references.** Brands, products, printed objects. Not adjectives. - -5. **One anti-reference.** What it should NOT feel like. Also named. - -### Step 4: Launch the questionnaire (questionnaire path only) - -**Interview-only path: skip this step.** Go to Step 5 and seed from the answers alone. Step 1 already settled the capability question; do not re-open it here. - -On the questionnaire path, **stop and load [visual-cues.md](visual-cues.md)** and follow its pipeline; it owns everything from the one-line user announcement and the persona palette studio through generation, `cues.json`, and the picker pause. Do not restate its mechanics here or in chat. The picker's exit is the handoff: when the server exits 0 and `.impeccable/design-context/answers.json` lands, come back here and run Steps 5-6 with that file in hand. - -### Step 5: Write seed DESIGN.md - -Use the canonical section order from Scan mode. Populate what the interview, the assets, and the questionnaire answer; leave the rest as honest placeholders. The seed is a scaffold, not a fabricated spec, but a decision the user actually made in the picker is real and belongs in the file at full strength. - -Mark the file as a seed with this comment as the first line of the markdown body, immediately after the frontmatter's closing `---` (the frontmatter must open the file or token parsers will not see it): +Lead the file with: ```markdown ``` -**Two seeds exist**, and which one you write depends on whether Step 4's picker ran: +Per-section guidance in seed mode: -**Interview-only seed** (the user opted out of generation, or no key arrived). Per-section guidance: - -- **Overview**: Creative North Star and philosophy phrased from the answers (color strategy + motion energy + references). Reference the user's anti-reference directly. -- **Colors**: Color strategy as a Named Rule (e.g. *"The Drenched Rule. The surface IS the color."*). Hue family or anchor reference. Colors sampled from a provided logo are real; include them with exact values and note the source. Everything else stays `[to be resolved during implementation]`; those sampled anchors are the only hex this seed may carry. -- **Typography**: the direction the user picked (e.g. "Serif display + sans body"). No font names yet: `[font pairing to be chosen at implementation]`. -- **Layout** and **Shapes**: omit unless an asset or answer established a spatial or form preference; do not invent grids or corner language pre-implementation. -- **Elevation & Depth**: inferred from motion energy. Restrained/Responsive → flat by default; Choreographed → layered. One sentence. +- **Overview**: the chosen design thesis, layout behavior, material character, imagery stance, motion grammar, and reusable signature. Keep the selected first-surface expression in its surface brief; do not promote its composition into the global world. +- **Colors**: the selected palette strategy and roles. Include values only when the user, an existing asset, or new-work's exploration established them; otherwise mark them `[to be resolved during implementation]`. +- **Typography**: the selected type character and role relationship. Include font names only when established; otherwise mark the pairing `[to be resolved during implementation]`. +- **Layout**: the selected spatial grammar and responsive behavior, without pretending exact measurements are settled. +- **Elevation & Depth**: the selected material and depth behavior, stated as an invariant rather than inferred from a generic preset. +- **Shapes**: the selected form and corner language. - **Components**: omit entirely; no components exist yet. -- **Do's and Don'ts**: carry PRODUCT.md's anti-references directly plus the anti-reference named in Q5. +- **Do's and Don'ts**: record the durable guardrails confirmed during the world choice, not task-local refusals. -This seed writes a minimal frontmatter with `name` and `description` only; no colors, typography, rounded, spacing, or components yet. +Seed mode writes a minimal frontmatter with `name` and `description` only; no colors, typography, rounded, spacing, or components yet. Real tokens land on the next Scan-mode run. Skip the `.impeccable/design.json` sidecar in seed mode for the same reason: nothing to render. -**Questionnaire seed** (`.impeccable/design-context/answers.json` exists from this run). The user answered every screen by eye, so the seed carries their answers as decisions, not directions. **`_chosen` names the fields they actually set**: it holds a JSON-encoded array of per-surface keys, and a `-` field missing from that array is a **preset** the picker minted when the surface was switched on, not an answer. Read the answers file plus the picked cue's palette entry in `.impeccable/visual-cues/cues.json` (`palette-source` names it), and map: - -- **Frontmatter**: `name` and `description`, plus real `colors` (the four `palette-*` hex values under descriptive slugs; these are picked, not sampled) and real `typography` (`font-heading` and `font-body` are exact family names; give each role its family and weight intent, leave sizes for implementation). Derive the two text inks and record them under `colors` too: one near-black and one near-white, the pair the picker's previews already set their text in over these exact surfaces, each holding 4.5:1 against the grounds it will carry copy on, so a builder needing body-text contrast finds ink in the system instead of inventing a fifth color. Still no `rounded`, `spacing`, or `components`: the corner and spacing answers are qualitative, and nothing is built. -- **Overview**: Creative North Star and philosophy phrased from the questionnaire's color-strategy and motion answers plus the chat references; reference the user's anti-reference directly. Name the chosen surfaces (`surface-modes`) and what each is for. Movement stays here, after the North Star, but the questionnaire asks it of a landing page and a portfolio only, so write what the keys support: - - `motion-energy-` keys present, all agreeing: one philosophy sentence for the product, as before. - - Keys present and disagreeing: one sentence per surface, named (*"The landing page moves on state change only; the portfolio stages entrances and drives sequences on scroll."*). The bare `motion-energy` is the leading one of the two. - - **No `motion-energy` key at all**: the run has neither of those surfaces, so movement was never asked. Say nothing about it, and do not fill the gap from the register; this path's chat interview never asked about motion, so there is nothing to borrow. The next Scan-mode run reads the real transitions out of the code. -- **Colors**: the four roles with their picked hex, noting the cue they came from. Name the chosen cue by its slug and name its kept image at `.impeccable/design-context/cue.png`, so a later build opens the picture the palette came from instead of imagining it; note that the unpicked cue images stay in `.impeccable/visual-cues/` for later art direction. Then open the kept image and describe it into the same section, three or four sentences under a **Cue, in words:** lead: the physical material each palette role lives on in the picture (cloth, glass, enamel, paper), the light and its temperature, the surface finish and grain, and the one material move that makes the image itself. Name each color as it appears on its material; `#C92823` as soft matte wrapping cloth instructs an image model where the bare hex only tints. Generation prompts on this world restate this passage (new-work.md and visualize.md say where), so a seed that records only the cue's file path leaves the material world to the model's imagination. The **chosen** strategy becomes the Named Rule. When surfaces differ (`color-strategy-` keys), state each surface's strategy and which surface leads (the bare key's owner). -- **Typography**: the real pair by name, the pairing's character, and the type scale as a rule: `type-scale` names it, `type-scale-ratio` is the ratio (e.g. *"Major third: each heading step is 1.25x the last"*). Base size and exact steps stay `[resolved at implementation]`. A `font-heading-source` / `font-body-source` value means a user-provided font file; record where it lives. -- **Layout**: `boundary-style` (how sections separate) per surface when the `-` keys differ, plus `layout-structure` (how pages are composed), which the questionnaire asks of a landing page and a portfolio only. No invented grids beyond what the answers state. - - `layout-structure` present: one bare key and no `-` keys, so state it as a rule for the whole product rather than per surface. - - **No `layout-structure` key at all**: the run has neither of those surfaces, so composition was never asked. Say nothing about how strict the grid is, and let `boundary-style` carry the section. -- **Elevation & Depth**: `depth-style` per surface, stated directly; the questionnaire answered this, so do not re-infer it from motion energy. -- **Shapes**: `corner-style` per surface. -- **Components**: still omit; nothing exists yet. -- **Do's and Don'ts**: the interview-only guidance, plus a Do fixing the icon source: every icon comes from the chosen pack (`icon-pack-name`, license, URL), no mixed sets. When the interview staged brand files (`context.assets` object entries in `.impeccable/design-context/context.json`), add one Do per file naming its path under `.impeccable/design-context/assets/`, its kind, and its note; a staged logo is the product's real mark and the build uses the file itself. - -Per-surface answers come back for every chosen surface, presets included, and a difference between surfaces is a decision the picker enforced, not an inconsistency to smooth over (the option lists differ per surface, so a pick one surface allows can be unavailable on another and that surface falls to its preset). **Write a preset as provisional**, on the surface's own line: name the value, say it is that surface's default because the surface was never configured, and keep it out of the Named Rules and out of every product-wide sentence. Naming an untouched preset as a rule invents a law the user never chose. Where all surfaces agree **and `_chosen` shows the agreement was picked**, state the answer once for the product. `motion-energy` and `layout-structure` are the two keys that can be missing entirely, since movement and composition are asked of a landing page and a portfolio only; [visual-cues.md](visual-cues.md) has the full contract. - -Both seeds skip the `.impeccable/design.json` sidecar: nothing to render yet. Real tokens for sizes, spacing, and components land on the next Scan-mode run. - -### Step 6: Confirm +### Step 3: Confirm 1. Show the seed DESIGN.md. Call out that it is a seed (the marker is the literal commitment). 2. Tell the user: "Re-run `/impeccable document` once you have some code. That pass will extract real tokens and generate the sidecar." -3. On the questionnaire path, add one line: the interview is kept, and `/impeccable design-context` reopens the document, re-runs the questionnaire over these answers, or writes the context out for another tool. See [design-context.md](design-context.md). Your own write is the freshest source; no reload needed. -When the questionnaire ran, the confirm is not the end of the turn: the design context document in the user's tab is live for edits through the session the picker forked. Follow the document edit loop in [visual-cues.md](visual-cues.md): poll, apply `edit_request`s to this same DESIGN.md, reply. A color the user changed in the tab before your seed write is already in `answers.json`; one changed after arrives as a `save_batch` event, its value already in the store and its description in DESIGN.md yours to bring in line. - ## Style guidelines - **Frontmatter first, prose second.** Tokens go in the YAML frontmatter; prose contextualizes them. Don't redefine a token value in two places; the frontmatter is normative. diff --git a/.agent/skills/impeccable/reference/hooks.md b/.agent/skills/impeccable/reference/hooks.md index a4496dcf9..188215495 100644 --- a/.agent/skills/impeccable/reference/hooks.md +++ b/.agent/skills/impeccable/reference/hooks.md @@ -32,7 +32,7 @@ The first argument is the action. Defaults to `status`. | `ignore-value [--shared] [--reason "..."]` | Append a rule/value suppression to shared `.impeccable/config.json`. | | `ignore-value --local [--reason "..."]` | Append a private rule/value suppression to `.impeccable/config.local.json`. | | `ignore-value "*" --file [--file ...]` | Turn one rule off in matching files only, leaving it active everywhere else. Repeat `--file`, or use `--file=` / `--files=`. A bare `"*"` with no `--file` is refused: use `ignore-rule ` if you really mean project-wide. | -| `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). | +| `reset` | Delete the project config, dedup cache, and Cursor pending queue. | ## Flow @@ -102,7 +102,6 @@ node .agent/skills/impeccable/scripts/hook-admin.mjs ignore-file "src/legacy/Car - Never modify `.impeccable/config.json` or `.impeccable/config.local.json` by hand from this command. Always go through `hook-admin.mjs` 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. - Do not edit the hook scripts themselves (`hook.mjs`, `hook-lib.mjs`, `hook-before-edit.mjs`) from this flow. Those are skill plumbing. -- The design context document's Hooks page reads and writes this same config through `hook-admin.mjs` (`state` and `apply`, its machine channel, called by the doc session); those two verbs are not part of this command's routing. Entries it wrote are user decisions: the person pressed Apply in the page, so treat them like any user-made config. - Cursor can block a proposed write when the detector finds a real issue. Claude Code, Codex, and GitHub Copilot do not block the edit; they emit a post-edit reminder instead. Disabling stops both blocking and reminders. - The hook is bundled with the Impeccable skill and installed through project-local manifests: `.claude/settings.local.json`, `.codex/hooks.json`, `.cursor/hooks.json`, and `.github/hooks/impeccable.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. diff --git a/.agent/skills/impeccable/reference/image-api.md b/.agent/skills/impeccable/reference/image-api.md deleted file mode 100644 index 728a92fca..000000000 --- a/.agent/skills/impeccable/reference/image-api.md +++ /dev/null @@ -1,54 +0,0 @@ -# Image API Path (keyless harnesses) - -Loaded when a pipeline needs image generation and the harness has **no usable native tool**. It answers, upfront, every question an agent has historically stopped to ask on this path; with a funded key in place, a run through this file asks the user nothing and debugs nothing. - -**This file never overrides a working native tool.** A harness with native image generation skips this path entirely; the precedence rule lives where the path is picked ([visual-cues.md](visual-cues.md) Step 3, [document.md](document.md) seed Step 1), not here. One refinement to that rule: a native tool that **cannot generate** (zero credits, failed auth, disabled account) counts as absent. Fall through to this path silently and mention the swap in the final report; do not stop to ask which path to use. A stopped question costs hours when the user is away; the swap costs nothing. - -## The setup, already answered - -- **Key**: `IMAGE_GEN_API_KEY` in `.impeccable/.env` at the project root. The wrapper reads that file itself; never `source` it, never export the key by hand, never rename the variable. Never delete or truncate that file either, cleanup included: it is the user's stored credential, not run output, and a wiped key turns the next run's silent keyless path into a stalled question. -- **Provider**: `IMAGE_GEN_PROVIDER` in the same file: `bfl` (FLUX / Black Forest Labs) or `gemini` (Google Nano Banana), both built into the wrapper; any other value routes to a custom wrapper (below). Loose spellings from earlier runs (`flux`, `google`, `nano-banana`) normalize to the built-ins, and a missing provider line is inferred from the key's shape (Google keys start with `AIza` or `AQ.`; anything else runs as `bfl`), so a misworded or absent line is never a reason to stop and ask. -- **Wrapper**: `.agent/skills/impeccable/scripts/image-gen.mjs`, shipped with the skill. Do **not** write a new wrapper for a built-in provider, edit this one, or fall back to raw `curl`/`fetch` calls; every known failure mode below is already handled inside it. Wrappers left by earlier runs under other names (`flux-gen.mjs`, project-local copies) are superseded by the shipped one. -- **No smoke test.** A funded key plus the shipped wrapper is a working path; the first real generation is the test, and the wrapper turns transient failures into internal retries rather than failed calls. - -## The command - -One command regardless of provider; the provider switch happens inside the wrapper, so calling pipelines never branch on it: - -```text -node .agent/skills/impeccable/scripts/image-gen.mjs --prompt "..." --out /abs/path.png \ - [--ref /abs/reference.png] [--width 1408] [--height 1408] -``` - -Run it from the project root (that is where it finds `.impeccable/.env`). It prints the absolute output path on success and exits non-zero with the error on stderr. `--ref` switches text-to-image to image-to-image where the provider supports it. - -## Provider facts, so no one re-derives them - -**bfl** (FLUX): - -- **Models**: `flux-pro-1.1` text-to-image; with `--ref`, `flux-kontext-max` image-to-image (reference sent as base64, aspect ratio pinned 1:1). -- **Size**: BFL accepts 256-1440 px in multiples of 32. The default `1408x1408` is the largest clean square; passing `--width 1500` fails validation locally, before any credit is spent. Output is always square unless you pass unequal values. -- **Concurrency**: BFL allows 24 active tasks (`flux-kontext-max`: 6). A six-spawn wave fits both caps; do not throttle it. -- **Protocol**: submit returns a `polling_url`; the wrapper polls exactly that URL (the global endpoint requires it) and downloads the signed result URL immediately, inside its 10-minute expiry. None of this is the caller's concern. - -**gemini** (Nano Banana): - -- **Model**: `gemini-3.1-flash-image` by default; a `IMAGE_GEN_MODEL` line in `.impeccable/.env` overrides it, and the wrapper retries the `-preview` sibling once when Google's model naming drifts. -- **Size**: the wrapper pins aspect ratio 1:1, so output is always square; Gemini picks the pixel size for its tier (1024 by default) and ignores `--width`/`--height`. A 1024 square passes the pipelines' square gate as a "nearest supported square"; do not upscale it. -- **Format**: Gemini frequently returns JPEG bytes regardless of the `--out` filename; the wrapper converts them, so the written file is always a real PNG. Do not re-check or re-convert it. -- **Protocol**: synchronous; one call returns the image inline, no polling. Moderation arrives as an imageless response, which the wrapper turns into a clear error, not as an HTTP failure. -- **Text rendering**: Gemini paints text well and eagerly, so a prompt that mentions codes, numbers, or labels tends to get them rendered onto the image (hex codes come back as a printed swatch strip). The calling pipeline's prompt rules ([visual-cues.md](visual-cues.md)'s HERO PROMPT skeleton) keep those out of prompts; follow them, not looser habits from other models. - -**Any other provider**: the user names it, so the integration cannot be pre-shipped. Write `.impeccable/image-gen.mjs` implementing the same CLI (same flags, print the absolute output path on success, non-zero exit with the error on stderr, transient retries handled inside), set `IMAGE_GEN_PROVIDER` to the provider's name, and the shipped wrapper delegates to it automatically; calling pipelines keep using the shipped command unchanged. Build it from the provider's API docs, and give it square output; do **not** modify the shipped wrapper to add the provider inline. - -## Failures and what they mean - -The wrapper retries transient failures internally (DNS, network blips, 429 back-pressure, poll hiccups, expired-download re-fetches), so an error that reaches the caller is real and carries its own explanation: - -- **"out of credits"** (bfl, HTTP 402): a human must top up at dashboard.bfl.ai. Report it and stop this path; retrying is pointless, and so is asking the user to choose an alternative that does not exist. -- **"quota or rate limit exhausted"** (gemini, HTTP 429 after the wrapper's own retries): the key's plan is out of headroom. Report it and stop this path; the fix is billing, not retries. -- **"rejected the key"** (either provider): the key in `.impeccable/.env` is wrong or revoked. Report it; do not mint debugging sessions around a dead key. -- **Moderation** ("Content Moderated" / "Request Moderated" / "Prompt was moderated"): the prompt tripped the provider's filter; rewording the prompt is the fix, within the caller's normal generation budget. -- **"cannot resolve"**: the wrapper already tried the system resolver, `dig`, Google, and Cloudflare. **Never debug DNS beyond this**: no `/etc/hosts` edits, no new resolvers, no rewriting the wrapper to use `fetch()` (sandboxed harnesses block the default resolver for these hosts; the wrapper pins IPs via `curl --resolve` for exactly that reason). Report the failure and let the parent decide. - -Subagents on this path inherit the generation-failure budget from their own pipeline ([visual-cues.md](visual-cues.md)'s three-call budget, or the calling pipeline's equivalent); the wrapper's internal retries do not count against it, only whole failed invocations do. diff --git a/.agent/skills/impeccable/reference/new-work.md b/.agent/skills/impeccable/reference/new-work.md index 84da9299d..8647c52c7 100644 --- a/.agent/skills/impeccable/reference/new-work.md +++ b/.agent/skills/impeccable/reference/new-work.md @@ -4,15 +4,13 @@ Use this flow for a new surface or a replacement visual identity. PRODUCT.md own ## 1. Decide what is already true -Read DESIGN.md, representative code, tokens, components, assets, and the interview record when Setup's `DESIGN_CONTEXT` directive reports one. +Read DESIGN.md, representative code, tokens, components, and assets. - **Redesign:** preserve product truth, content, function, constraints, and explicit brand commitments; replace the old visual world rather than polishing it. The old look is evidence of what the subject is, not authority over what it becomes. - **Established world:** inherit it. A missing DESIGN.md does not erase a coherent identity already in code; document that identity instead of inventing a replacement. - **Incomplete brand:** preserve confirmed assets and recognizable traits, then expand the system with the user for this surface. - **No visual authority:** create a new world with the user. -**A questionnaire seed is an established world with its evidence on disk.** When DESIGN.md carries the SEED marker and the interview record exists (`.impeccable/design-context/`), inherit the world and open the record before deciding anything: `cue.png` is the image the user picked the palette from, and each file under `assets/` is real brand material, its kind and note recorded in `context.json`. The record also settles most of section 2; ask only what it left open. Building on this world from DESIGN.md's words alone, with the cue unopened, is building from a paraphrase of a decision the user made in pixels. - A section, component, feature, or state inside an established surface inherits that surface. Never turn a local addition into a new identity exercise. ## 2. Ask what will change the work @@ -38,21 +36,19 @@ Keep the visual system fixed. Derive five to seven materially different structur `node .agent/skills/impeccable/scripts/concept-seed.mjs --scope surface --mode ` -The script deals three of your structures; the dice pick which three reach the user, breaking the ranking rut while the user keeps a real choice. Present them on the decision page as full cards of equal salience, the dealt lead under kicker THE ROLL, with steer and re-roll; the user locks one. No canon card and no pick card at surface scope: the world is settled, so every card visualizes composition, not identity. With image generation and a comp-led default (`.impeccable/config.json`; the build-path paragraph below), each card declares a `comp` under `.impeccable/mocks/decision/`, generated after serving, in reading order, under [visualize.md](visualize.md)'s comp discipline. Anchor each comp on the established identity: pass a screenshot of a representative existing page as a reference image (the harness image tool's input image, or `generate-image.mjs --ref`) with a prompt that leads with the new surface's structure and names DESIGN.md's palette, type, and component character; prose paraphrases of a design system drift, pixel references do not. On a seed world with no built page to screenshot, the chosen cue is that pixel reference: pass `.impeccable/design-context/cue.png` (and the staged logo when one exists) the same way. Pixels are half the anchor: restate the seed DESIGN.md's **Cue, in words:** passage in the prompt, the material each color lives on, the light, the finish, because the attached image sets a standard while the restated words tell the model which parts of the standard are the point. A seed DESIGN.md with no such passage (seeded before it was recorded) gets one written now: open the cue, write the passage into the Colors section under [document.md](document.md)'s shape, then prompt from it. The same cue rides the cards: on the comp-led roll every grounded card also declares the cue as its `hero`, the slot a catalog world's card art fills, so the page shows the world these compositions come from beside each comp and the lock's ANSWER names the image to open before code; challengers keep their own catalog inspirations. Without image generation, or under a code-led default, each card carries a `wireframe` schematic (`serve-question.mjs --schema`) the page draws itself. Locking a card is the approval and sets the build path: a locked comp builds comp-led with that comp as the approved comp, discharging [visualize.md](visualize.md)'s three-option round with no second approval point; a locked wireframe builds code-led, its ambition carried by the direction contract. Never run the script for a local extension or a precisely specified narrow request; shape those directly. +The script deals three of your structures; the dice pick which three reach the user, breaking the ranking rut while the user keeps a real choice. Present them on the decision page as full cards of equal salience, the dealt lead under kicker THE ROLL, with steer and re-roll; the user locks one. No canon card and no pick card at surface scope: the world is settled, so every card visualizes composition, not identity. With image generation and a comp-led default (`.impeccable/config.json`; the build-path paragraph below), each card declares a `comp` under `.impeccable/mocks/decision/`, generated after serving, in reading order, under [visualize.md](visualize.md)'s comp discipline. Anchor each comp on the established identity: pass a screenshot of a representative existing page as a reference image (the harness image tool's input image, or `generate-image.mjs --ref`) with a prompt that leads with the new surface's structure and names DESIGN.md's palette, type, and component character; prose paraphrases of a design system drift, pixel references do not. Without image generation, or under a code-led default, each card carries a `wireframe` schematic (`serve-question.mjs --schema`) the page draws itself. Locking a card is the approval and sets the build path: a locked comp builds comp-led with that comp as the approved comp, discharging [visualize.md](visualize.md)'s three-option round with no second approval point; a locked wireframe builds code-led, its ambition carried by the direction contract. Never run the script for a local extension or a precisely specified narrow request; shape those directly. ### Create or replace the visual world -**When DESIGN.md is missing**, pause before any of the work below. Ask the user directly to clarify what you cannot infer. Ask once: recommend `/impeccable document --seed`, the guided interview plus browser questionnaire, because a world established from the user's own choices beats one assigned to them; offer the skip in the same breath. *"There's no design system on record yet. Before I invent directions for [the requested surface], I can run a short interview and browser questionnaire so the visual world is built from your choices; I recommend it. Or skip it and I'll roll a direction now."* The pause is enforced by the script, not by your discipline: with no DESIGN.md on record, the step 4 roll refuses to deal and prints this same offer until the questionnaire has been put to the user. Do not roll first and offer the questionnaire after, the assignment anchors the conversation; do not run document on the user's behalf without their yes. **Accepted:** seed mode in [document.md](document.md) owns the interview and the picker; follow it. When the seed DESIGN.md is written, resume at section 1: the seed world now reads as an established world, so inherit it; the direction roll below no longer applies, and the optional surface roll remains. Through every phase that follows, comp-led included, the comp rules composition; the world rules material, and this seed is that world. **Skipped:** re-run the step 4 command with `--seed-declined=""`; the flag carries the user's own words as evidence of the skip, and the roll deals with nothing in step 4 softened. The build request itself is never a skip answer, a bare flag refuses again, and fabricating or paraphrasing the quote is a contract violation; only words the user typed after being asked qualify. When DESIGN.md exists, there is no pause and no flag. - -1. Name the product's unique mechanism in one sentence, the audience's real scene, its cultural home, and what this first surface must prove. Note the page this category always ships and its predictable opposite; name both as the rut and keep them out of the seven-candidate list. A brief that paints its own picture, a product name, a titled artifact, a governing metaphor, adds its literal reading to the rut: spend at most one candidate on it and derive the rest from elsewhere in the audience's world. -2. From that cultural world, list seven concrete visual systems, artifacts, places, or rituals the audience knows by heart, each with one line on why it resonates and can carry the mechanism, ordered by resonance. The audience's world includes its graphic and screen traditions, not only its physical objects: the notation, publications, identity programs, data graphics, and interfaces it reads daily; a nameable abstract system (a school of poster, a documentation standard) is as concrete a candidate as any artifact. What would this thing look like as a physical object; what did its world look like before the web? Near-duplicates count once. When more than three of the seven share one material family, the derivation stopped at the subject's most obvious artifact; dig until the list spans at least three families. +1. Name the product's unique mechanism in one sentence, the audience's real scene, its cultural home, and what this first surface must prove. Note the page this category always ships and its predictable opposite; both are the rut, kept out of the seven-candidate list. A brief that paints its own picture, a product name, a titled artifact, a governing metaphor, adds its literal reading to the rut: spend at most one candidate on it and derive the rest from elsewhere in the audience's world. +2. From that cultural world, list seven concrete visual systems, artifacts, places, or rituals the audience knows by heart, each with one line on why it resonates and can carry the mechanism, ordered by resonance. The audience's world includes its graphic and screen traditions, not only its physical objects: the notation, publications, identity programs, data graphics, and interfaces it reads daily. A nameable abstract system (a school of poster, a documentation standard) is as concrete a candidate as any artifact. What would this thing look like as a physical object; what did its world look like before the web? Near-duplicates count once. When more than three of the seven share one material family, the derivation stopped at the subject's most obvious artifact; dig until the list spans at least three families. 3. Turn that material into complete directions: each joins a reusable visual world to a concrete first-surface experience. -4. Run `node .agent/skills/impeccable/scripts/concept-seed.mjs --scope direction --mode ` and follow what it prints. With no DESIGN.md the script refuses to deal until the seed pause above has run; after the user's explicit skip, and only then, re-run it with `--seed-declined=""` carrying the user's own words. This step has no substitute and no skip condition (the seed pause above exits this subsection before any direction work starts; it is not a skip of the roll): on a new or replacement world, writing artifact code before this script has run and its assignment is acknowledged is a contract violation, whatever the harness, the model, or the time pressure, because the roll is the mechanism that keeps every run from converging on the category default. The script assigns which direction gets built and deals catalog challengers. Fuse each challenger before judging it: the challenger supplies the form and its system grammar, the product supplies every fact, and clarity wins conflicts. Weigh fused challengers against the assigned direction on exactly two axes, audience identification and product clarity; losing to strong grounded material is a valid outcome, and beating a thin or tool-monoculture list is the point. The weighing closes with a verdict per challenger, decided before any borrowing is considered: wins (beats the assigned direction on both axes; it becomes the build candidate), competitive (holds one axis; it stays a full alternate), or declined (loses both). A declined challenger is not spent: name the one discipline of its system the assigned direction lacks, and raise the assigned direction to match before presenting it. A donation transfers ambition and system discipline (a palette's total commitment, a grid's density courage, a form's structural honesty), never the challenger's clothes; a motif lifted from a declined world is a costume note, not a raise, and one world owns the page. Write each raise into the presented direction as its own line, named for its donor; a raise nobody can read did not happen. -5. Present one direction, fully committed and already raised by the hand it beat, its raises visible as named lines: its world, first viewport, visitor path, signature interaction, cross-surface reach, and honest risk. Alongside it, route each dealt challenger by its verdict: winning and competitive challengers are full alternates carrying their QUALITY BAR cards and one-line case, while declined challengers render demoted, compact and quiet, each carrying its verdict plus what the direction kept from it, never full-size and never silently dropped, each still adoptable on request. The verdict informs the user's choice, it never pre-empts it; the demoted row is the hand's proof of judgment, showing why the dealt worlds made the presented direction better. A hand holds at most three full-card challengers: when the roll deals more, the three strongest join the hand and the rest wait in the re-roll pool, noted in one line; dropping a challenger from the hand itself takes a named product-truth failure, disclosed. Add one card for your own top-ranked grounded candidate when it is not the assigned direction, kicker IMPECCABLE’S PICK, same anatomy as every card, with an honest risk line naming its familiarity when true: the strongest grounded direction is often the one most runs in this category land on, and the user deciding that trade is the point of showing it. Familiar and effective is a legitimate destination, not a failure of nerve; the pick card and the standing exit serve it at two depths. One pick card, never two, never a ranked list: the rest of your grounded candidates stay yours, because a lineup of them hands selection back to a taste function and invites the safest card. The pick never takes the lead position, and when the dice assign your top candidate there is no pick card; the assigned card notes it also topped your list. Add re-roll with an optional one-line steer, offered in three registers: plain (a fresh hand, same spread), safer (the familiar register: your remaining conventional grounded candidates plus the canon against named competitors), and bolder (foreign forms only, at full commitment). A register is the user's steering on the familiar-to-bold axis, never yours to pre-select; when the answer carries one, re-run the seed with `--register ` and the next `--reroll` round, and follow what it prints. A user saying "bolder" or "safer" while a direction round is open means these registers, never the bolder or harden commands. The two channels share this structure and differ only in richness: cards and boards on the decision page, names and one-liners through the structured tool; the structured tool's option list carries the assigned direction, the pick, the winning and competitive challengers, and the standing exit as its last option, while declined challengers fold into the assigned option's description as their kept lines, so the raise survives the text channel too. +4. Run `node .agent/skills/impeccable/scripts/concept-seed.mjs --scope direction --mode ` and follow what it prints. No substitute, no skip: on a new or replacement world, writing artifact code before this script has run and its assignment is acknowledged is a contract violation, whatever the harness, the model, or the time pressure; the roll is what keeps every run from converging on the category default. The script assigns the direction to build and deals catalog challengers. Fuse each challenger before judging it: the challenger supplies the form and its system grammar, the product supplies every fact, clarity wins conflicts. Weigh fused challengers against the assigned direction on exactly two axes, audience identification and product clarity. Losing to strong grounded material is a valid outcome; beating a thin or tool-monoculture list is the point. Close with a verdict per challenger, decided before any borrowing: wins (beats the assigned direction on both axes; becomes the build candidate), competitive (holds one axis; stays a full alternate), or declined (loses both). A declined challenger is not spent: name the one discipline of its system the assigned direction lacks, and raise the assigned direction to match before presenting it. A donation transfers ambition and system discipline (a palette's total commitment, a grid's density courage, a form's structural honesty), never the challenger's clothes; a lifted motif is a costume note, not a raise, and one world owns the page. Write each raise into the presented direction as its own line, named for its donor; a raise nobody can read did not happen. +5. Present one direction, fully committed and already raised by the hand it beat, raises visible as named lines: world, first viewport, visitor path, signature interaction, cross-surface reach, honest risk. Route each challenger by verdict: winning and competitive challengers are full alternates with their QUALITY BAR cards and one-line case; declined challengers render demoted, compact and quiet, each carrying its verdict and what the direction kept from it, never full-size, never silently dropped, still adoptable on request. The verdict informs the user's choice, never pre-empts it; the demoted row is the hand's proof of judgment. A hand holds at most three full-card challengers: when the roll deals more, the three strongest join and the rest wait in the re-roll pool, noted in one line; dropping a challenger from the hand itself takes a named product-truth failure, disclosed. Add one card for your own top-ranked grounded candidate when it is not the assigned direction, kicker IMPECCABLE’S PICK, same anatomy as every card, with an honest risk line naming its familiarity when true: the strongest grounded direction is often where most runs in this category land, and the user deciding that trade is the point of showing it. Familiar and effective is a legitimate destination, not a failure of nerve; the pick card and the standing exit serve it at two depths. One pick card, never two, never a ranked list: a lineup of your candidates hands selection back to a taste function and invites the safest card. The pick never takes the lead position; when the dice assign your top candidate there is no pick card, and the assigned card notes it topped your list. Add re-roll with an optional one-line steer, in three registers: plain (a fresh hand, same spread), safer (your remaining conventional grounded candidates plus the canon against named competitors), bolder (foreign forms only, at full commitment). The register is the user's steering on the familiar-to-bold axis, never yours to pre-select; when the answer carries one, re-run the seed with `--register ` and the next `--reroll` round, and follow what it prints. A user saying "bolder" or "safer" while a direction round is open means these registers, never the bolder or harden commands. The two channels share this structure and differ only in richness: cards and boards on the decision page, names and one-liners through the structured tool, whose option list carries the assigned direction, the pick, the winning and competitive challengers, and the standing exit last; declined challengers fold into the assigned option's description as their kept lines, so the raise survives the text channel. -The standing exit: every direction round offers one quiet, permanent alternative, the category standard, played straight. It is the user's door, never yours: never recommend it, never weigh it against the roll, never let it soften the dealt directions; the counterweights bind the unchosen default, not the chosen one. When the user takes it (the canon action, a safer-steer, or plain words asking for the familiar or competitor-like path), convention becomes the commitment: ask once for two or three products this should sit alongside, make their craft level the bar, and execute the canon at full fidelity, without irony or smuggled quirk. Record a standing preference as a brand commitment in PRODUCT.md. Re-roll eliminates every direction already shown, grounded and challenger alike; after two consecutive re-rolls, ask what quality is missing. Re-roll on your own only on named factual grounds, when the assigned direction cannot carry the product's truth or task; taste is never grounds. The user may re-roll freely, and a user- or brief-pinned direction beats the roll, always. Resolve collisions field by field: preserve every user- or brief-pinned constraint. In dimensions the brief leaves open, the assignment still binds through its topology, controls, state vocabulary, and ritual; when only its materials conflict with a pinned visual direction or PRODUCT.md brand commitment, translate that material expression and name the translation in the presented direction. A look mismatch is not grounds to re-roll. Present the decision visually: write an options payload with the assigned direction leading, its raised lines included; the pick card when one exists; the dealt challengers as alternates with their QUALITY BAR cards, verdicts, and kept lines; re-roll with its safer and bolder registers; steer; canon enabled; and `buildPath` carrying the recorded default with `toggle: true` whenever image generation exists (details in the build-path paragraph below). A degraded roll with no challengers still uses the page, as a single text-only card with re-roll. Give every card the same anatomy: thesis, palette, materials, first viewport, honest risk, and the challengers' case lines (`--schema` prints the exact shape); the page renders identity from these fields, demotes declined challengers to their row on its own, and a challenger's catalog image rides as labeled inspiration, never the promise of the build. Author `canonCard` too: the category standard as one honest card, same anatomy; the page keeps it subordinate, and the counterweights still bind you. Run `node .agent/skills/impeccable/scripts/serve-question.mjs --start --payload ` (`--schema` first for the payload shape). It daemonizes, prints the page URL and a key, and exits; open that URL for the user, in-app browser first, then the system opener, then showing the URL. Collect the choice with `--wait --key `, repeating while it exits 3; the ANSWER prints as JSON. An ANSWER of `{"optionId":"reroll"}` keeps the server alive and the page open on a loading hand: rerun concept-seed with the same `--scope` and `--mode` plus `--from --reroll ` (1 on the first re-roll, counting up), build the next payload, deliver it with `--update --key --payload `, then return to `--wait` on that key. Never `--start` a second server or fall back to chat here: either strands the open tab on a hand that never arrives. Exit 4 means the page closed unanswered: re-present once through the structured question tool, and with no answer there either, proceed unattended with the assigned direction and state the assumptions. A harness that can leave a shell blocked in the background may run the script without `--start` and let it auto-open and block. Never predict the fallback: run the script, and only exit code 2 from starting it routes the decision to the structured tool; that exit is the fallback, never an error to retry. +The standing exit: every direction round offers one quiet, permanent alternative, the category standard, played straight. It is the user's door, never yours: never recommend it, never weigh it against the roll, never let it soften the dealt directions; the counterweights bind the unchosen default, not the chosen one. When the user takes it (the canon action, a safer-steer, or plain words asking for the familiar or competitor-like path), convention becomes the commitment: ask once for two or three products this should sit alongside, make their craft level the bar, and execute the canon at full fidelity, without irony or smuggled quirk. Record a standing preference as a brand commitment in PRODUCT.md. Re-roll eliminates every direction already shown, grounded and challenger alike; after two consecutive re-rolls, ask what quality is missing. Re-roll on your own only on named factual grounds, when the assigned direction cannot carry the product's truth or task; taste is never grounds. The user may re-roll freely, and a user- or brief-pinned direction beats the roll, always. Present the decision visually: write an options payload with the assigned direction leading, its raised lines included; the pick card when one exists; the dealt challengers as alternates with their QUALITY BAR cards, verdicts, and kept lines; re-roll with its safer and bolder registers; steer; canon enabled; and `buildPath` carrying the recorded default with `toggle: true` whenever image generation exists (details in the build-path paragraph below). A degraded roll with no challengers still uses the page, as a single text-only card with re-roll. Give every card the same anatomy: thesis, palette, materials, first viewport, honest risk, and the challengers' case lines (`--schema` prints the exact shape); the page renders identity from these fields, demotes declined challengers to their row on its own, and a challenger's catalog image rides as labeled inspiration, never the promise of the build. Author `canonCard` too: the category standard as one honest card, same anatomy; the page keeps it subordinate, and the counterweights still bind you. Run `node .agent/skills/impeccable/scripts/serve-question.mjs --start --payload ` (`--schema` first for the payload shape). It daemonizes, prints the page URL and a key, and exits; open that URL for the user, in-app browser first, then the system opener, then showing the URL. Collect the choice with `--wait --key `, repeating while it exits 3; the ANSWER prints as JSON. An ANSWER of `{"optionId":"reroll"}` keeps the server alive and the page open on a loading hand: rerun concept-seed with the same `--scope` and `--mode` plus `--from --reroll ` (1 on the first re-roll, counting up), build the next payload, deliver it with `--update --key --payload `, then return to `--wait` on that key. Never `--start` a second server or fall back to chat here: either strands the open tab on a hand that never arrives. Exit 4 means the page closed unanswered: re-present once through the structured question tool, and with no answer there either, proceed unattended with the assigned direction and state the assumptions. A harness that can leave a shell blocked in the background may run the script without `--start` and let it auto-open and block. Never predict the fallback: run the script, and only exit code 2 from starting it routes the decision to the structured tool; that exit is the fallback, never an error to retry. -When image generation exists, every card also declares a `comp` path under `.impeccable/mocks/decision/`, the canon card included. Where the harness sandboxes its shell, start the page through the least-sandboxed command path it offers: a sandboxed shell cannot bind the board's port, and the first-attempt failure costs a retry every session. Serve the page first, then produce the comps; the page shimmer-waits per slot and the user may answer before they land. Each card's image is that direction's north-star comp at full fidelity under [visualize.md](visualize.md)'s comp discipline: the requested surface's first viewport, structure-led prompt, real product name and real content, no invented commercial claims, in that card's own palette, type character, and material world, committed all the way. Generation takes the same time at any fidelity, so an unfinished draft pays comp cost for draft quality; fairness between cards is equal fidelity in each card's own grammar, one surface, one aspect, never shared unfinishedness. The frame's aspect is the surface's own: portrait at device viewport for a native app or mobile-first surface, landscape for desktop web; the decision page adapts to either, and a phone screen comped landscape is a broken frame, not a neutral default. Produce in reading order, the assigned card, then the pick, then the full-card hand, then canon, each file written with its prompt sidecar the moment it is done, so a re-roll's spend front-loads onto the cards read first; declined challengers get no comp, their catalog thumb is their face. With parallel subagents, fan out one agent per card: each spawn is the shipped asset producer with a single-comp packet, that card's fields, PRODUCT.md, the shared frame, the card's declared path, and on a questionnaire-seed world the cue image, the staged logo, and the seed DESIGN.md's **Cue, in words:** passage, up to four in flight. Regenerate inline any slot still empty when its agent returns; drop without ceremony any slot still empty when the user answers. No other supervision is owed. Without parallel subagents, generate in the main thread after serving, same order, and let the harness's own generation display carry the progress; the wait for the answer follows the last file. The chosen card's comp is not spent by the choice: comp-led, it enters the comp round as compositional option one; code-led, it returns at the finish review as the critique reference, what the image dared that the build did not. Unchosen comps stay in `.impeccable/mocks/decision/` as the round's spent hand; they carry no approval and imply none. With no image generation, cards carry their identity in palette chips and facts, and that page is complete, not a lesser version; the page then also demotes every challenger's catalog art to a labeled thumbnail on its own, because salience must encode the verdict, never the accident of which cards have images. +When image generation exists, every card also declares a `comp` path under `.impeccable/mocks/decision/`, the canon card included. Where the harness sandboxes its shell, start the page through the least-sandboxed command path it offers: a sandboxed shell cannot bind the board's port, and the first-attempt failure costs a retry every session. Serve the page first, then produce the comps; the page shimmer-waits per slot and the user may answer before they land. Each card's image is that direction's north-star comp at full fidelity under [visualize.md](visualize.md)'s comp discipline: the requested surface's first viewport, structure-led prompt, real product name and real content, no invented commercial claims, in that card's own palette, type character, and material world, committed all the way. Generation takes the same time at any fidelity, so an unfinished draft pays comp cost for draft quality; fairness between cards is equal fidelity in each card's own grammar, one surface, one aspect, never shared unfinishedness. The frame's aspect is the surface's own: portrait at device viewport for a native app or mobile-first surface, landscape for desktop web; the decision page adapts to either, and a phone screen comped landscape is a broken frame, not a neutral default. Produce in reading order, the assigned card, then the pick, then the full-card hand, then canon, each file written with its prompt sidecar the moment it is done, so a re-roll's spend front-loads onto the cards read first; declined challengers get no comp, their catalog thumb is their face. With parallel subagents, fan out one agent per card: each spawn is the shipped asset producer with a single-comp packet, that card's fields, PRODUCT.md, the shared frame, and the card's declared path, up to four in flight. Regenerate inline any slot still empty when its agent returns; drop without ceremony any slot still empty when the user answers. No other supervision is owed. Without parallel subagents, generate in the main thread after serving, same order, and let the harness's own generation display carry the progress; the wait for the answer follows the last file. The chosen card's comp is not spent by the choice: comp-led, it enters the comp round as compositional option one; code-led, it returns at the finish review as the critique reference, what the image dared that the build did not. Unchosen comps stay in `.impeccable/mocks/decision/` as the round's spent hand; they carry no approval and imply none. With no image generation, cards carry their identity in palette chips and facts, and that page is complete, not a lesser version; the page then also demotes every challenger's catalog art to a labeled thumbnail on its own, because salience must encode the verdict, never the accident of which cards have images. The execution contract, comp-led or code-led, is a workflow preference, not a per-surface decision; no round asks it. The recorded default rides every round and the page's toggle handles the exception. Read the default from `.impeccable/config.json` (`buildPath`), the gitignored `.impeccable/config.local.json` winning where one machine differs from the team's committed value; with neither, comp-led is the default whenever image generation exists. Author every direction and surface payload with `buildPath: { "value": , "toggle": true }`; the page renders a footer toggle with the trade stated beside it, and the ANSWER returns `buildPath` plus `buildPathFlipped`. A flipped value binds that session only and is never written back, with one exception, the only question this preference ever earns inside a round (init records it up front on projects that get the chance): when `buildPathFlipped` comes back true on a project that records no `buildPath` at all, ask once after the round closes whether to keep it as the standing default. Either answer writes `.impeccable/config.json`; the answer picks the value, never whether to record one. Yes writes the flipped value; "no, just this once" writes the value they flipped away from, the standing default they just confirmed by declining. Ask on the flip, never on the untouched default: a user who left the toggle alone told you nothing. A declined offer nothing writes down is an offer the next session makes again. When the user asks in words to change the standing default, update the file without asking. **Comp-led**: the chosen card's comp is law, generated before building when it does not yet exist, and the finish review audits the build against it; boldest composition on the table, fix rounds expected, and the comp is non-optional, no silent skipping. **Code-led**: no comp of this page and no apology for it; the QUALITY BAR boards still calibrate finish, and the ambition moves into the written contract, the FIRST VIEWPORT block plus a named signature interaction and motion grammar, which the finish reviewer audits in behavior; code-led is not a discount on commitment. A code-led round still declares each card's comp path as a flip reserve: when the user flips the toggle to comp mid-round, `--wait` returns once with BUILD PATH FLIPPED while the page shimmers the slots; generate each open card's comp into its declared path then, lead first, and wait again. The flip back is free, and a comp that already rendered rides at the finish review as the critique reference. Without image generation there is no toggle and no choice: code-led is the only path, stated in one line rather than asked. The old two-card execution-contract round is retired; `followup: true` remains the general mechanism for delivering any later round over the same table via `--update`. @@ -64,8 +60,6 @@ For **Persuade**, the opening must make the offer intelligible and desirable, ex ## 4. Commit the world -**A recorded world has already committed.** When DESIGN.md records these decisions, and a questionnaire seed always does, read them instead of choosing again: its strategy, faces, scale, and icon pack are the user's own picks and outrank this section's defaults. Per-surface records bind per surface: build the requested surface under its own mode's recorded strategy, boundaries, corners, depth, and motion; another surface's answer never substitutes, and the leading surface's bare answer is not a product-wide rule where the record splits. A surface whose mode the record never answered takes the world's product-wide rules plus the mode guidance, and you may offer `/impeccable design-context edit` once to re-run the questionnaire with that surface added; never block on it. The rest of this section is for worlds not yet recorded. - Pick a color strategy before picking colors: Restrained (neutrals plus one accent; the default when the visitor came to operate or read), Committed (one saturated color carries 30-60% of the surface), Full palette (3-4 named roles), or Drenched (the surface IS the color). Persuade and Experience surfaces have permission for the bolder strategies; take them when the brief allows. Color commits at page scale: fields that own whole regions, not accents scattered over a neutral ground. Dark or light is never a default: write one sentence of physical scene (who uses this, where, under what light) and let it force the answer. Choose faces like objects from the subject's world, in the mode's register. Operate and Read surfaces are well served by system stacks and workhorse UI faces; Persuade and Experience surfaces want faces with a point of view, and these training-data defaults mean you stopped looking: Fraunces, Playfair Display, Cormorant, Lora, Crimson, Newsreader, Syne, Space Grotesk, Space Mono, IBM Plex, Inter-as-display, DM Sans, DM Serif, Outfit, Plus Jakarta Sans, Instrument Sans. Naming one of these faces anyway requires a reason no other face could satisfy, and a subject association is never that reason: books wanting a serif, bookshops wanting hand-lettering, and tech wanting a mono are the associations the list exists to break. @@ -74,20 +68,16 @@ Calibration: AI-generated interfaces cluster around a few looks regardless of su ## 5. Record the decision -Before code, record the chosen direction as a development-only contract under `## Direction contract` in the relevant surface brief. A direction contract is durable route or artifact strategy, so create or update the brief even when no other surface strategy needs persistence. Keep the contract to six short blocks and 150 words at most. THESIS: the one idea this surface owns and the category-default arrangement it refuses. OWN-WORLD: the palette, the faces with the recorded type scale when DESIGN.md names one, and the component language, specific enough to be recognizable with all content removed. STORY: what the visitor understands, believes, and does. FIRST VIEWPORT: the exact composition, what is where and at what scale, and where the primary action sits. FORM: the chosen form, its position on your ordered list, and the seed key the script printed. Close with one more line, FINISH: the run's exit condition, verbatim "unreviewed and undocumented is unfinished; this build ends with the finish review, the verdict, DESIGN.md, and every shipping raster carrying its provenance". The surface brief is the reminder later agents reload across edits and sessions: a page that looks complete with the FINISH line undischarged is not done, it is abandoned at the finish line. If a block reads like a mood, the direction is not decided yet; the finishing review audits the render against this contract. - -Never copy the direction contract into implementation source or any browser-delivered artifact. This includes HTML or framework comments, hidden DOM, `