This commit is contained in:
Abdul Wahab
2026-09-01 10:08:03 +05:00
parent 89c842e5f4
commit 0aec856f45
4 changed files with 67 additions and 6 deletions
+2 -2
View File
@@ -458,7 +458,7 @@ This seed writes a minimal frontmatter with `name` and `description` only; no co
- `motion-energy-<mode>` 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 note that the unpicked cue images stay in `.impeccable/visual-cues/` for later art direction. `color-strategy` becomes the Named Rule. When surfaces differ (`color-strategy-<mode>` keys), state each surface's strategy and which surface leads (the bare key's owner).
- **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. `color-strategy` becomes the Named Rule. When surfaces differ (`color-strategy-<mode>` 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 `-<mode>` 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 `-<mode>` keys, so state it as a rule for the whole product rather than per surface.
@@ -466,7 +466,7 @@ This seed writes a minimal frontmatter with `name` and `description` only; no co
- **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.
- **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, defaults included, and a difference between surfaces is a decision the picker enforced, not an inconsistency to smooth over (the option lists differ per surface). Where all surfaces agree, 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.
+7 -3
View File
@@ -4,13 +4,15 @@ 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, and assets.
Read DESIGN.md, representative code, tokens, components, assets, and the interview record when Setup's `DESIGN_CONTEXT` directive reports one.
- **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
@@ -36,7 +38,7 @@ Keep the visual system fixed. Derive five to seven materially different structur
`node {{scripts_path}}/concept-seed.mjs --scope surface --mode <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. 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. 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. 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
@@ -62,6 +64,8 @@ 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 `{{command_prefix}}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. <!-- rule:skill-color-strategy -->
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. <!-- rule:skill-typo-reflex-faces -->
@@ -142,7 +146,7 @@ A capture is evidence only when it is valid, and you validate before you send. S
After the second inspection round the build thread's polishing is over: no further defect hunts, micro-edit scripts, or rebuilds here; whatever remains ships through the handoffs, where a fresh context does the finding better and cheaper. On the web, where this harness runs no design hook, run `node {{scripts_path}}/detect.mjs --json` on the changed targets once here, fix what is mechanical, and pass the remaining findings to the reviewer; a hookless web build that skips this ships every tell the hook exists to catch. A native platform skips the detector entirely: it reads HTML and CSS and has no verdict on native code, so the reviewer's floor check is the only slop gate and the input packet says so. Capture the screenshots into `.impeccable/review/`, one file per captured viewport (on the web, `desktop.png` and `mobile.png`, plus `user-<width>.png` whenever the user's viewport joined the inspected set; on native, one per device class, such as `phone.png` and `tablet.png`, suffixed per OS on adaptive), creating that directory when the harness does not; the paths you pass the reviewer are its spec, every viewport you inspected is named required in the packet, and that directory is where it looks when a passed path is missing.
Then spawn the shipped finish reviewer, `impeccable-finish-reviewer` (`impeccable_finish_reviewer` in codex; `/impeccable-finish-reviewer` in Cursor; on GitHub Copilot say "Use the impeccable-finish-reviewer agent"), with the original request, confirmed answers, the artifact path, the screenshot paths, the direction contract, existing hook findings, the QUALITY BAR card and approved comp paths (a code-led build has no approved comp; the chosen decision comp rides in that slot as the critique reference, named as such), on a comp-led build the build state (`.impeccable/build/state.json`), the spec, and the diff directories (`.impeccable/review/diff/hero/` and `.impeccable/review/diff/final/`, whose side-by-side, heatmap, region pairs, and `report.json` are the fidelity evidence), the craft-floor reference path, and on a native platform the platform reference path(s), [ios.md](ios.md) / [android.md](android.md), both on adaptive, plus one line saying no detector ran, so the reviewer judges in the platform's conventions rather than the web's. The reviewer has no browser; screenshots you fail to pass are checks it cannot run. Never read the shipped agents' definition files before spawning; the harness loads them at spawn, and you owe only the input packet. Wait on any agent with one long timeout rather than a loop of short polls, and spend the wait on the next independent step. Verify the return carries the five contract sections (a recapture return carries one, its recapture list); on an empty or thrashed return, respawn once with the same inputs. This review never runs inside the build thread and never inherits it: spawn the reviewer fresh, with no forked conversation history (`fork_turns: 0` in codex); a reviewer that inherits your transcript inherits your framing, your optimism, and your abstractions, and everything it needs travels in the inputs above. Only a harness with no subagent capability at all substitutes a fresh in-thread pass after stepping fully out of the build context, run from [degraded/finish-reviewer.md](degraded/finish-reviewer.md), and a substituted or failed-and-replaced review is disclosed in one line at finish, never silently. <!-- rule:skill-finish-separate-reviewer -->
Then spawn the shipped finish reviewer, `impeccable-finish-reviewer` (`impeccable_finish_reviewer` in codex; `/impeccable-finish-reviewer` in Cursor; on GitHub Copilot say "Use the impeccable-finish-reviewer agent"), with the original request, confirmed answers, the artifact path, the screenshot paths, the direction contract, existing hook findings, the QUALITY BAR card and approved comp paths (a code-led build has no approved comp; the chosen decision comp rides in that slot as the critique reference, named as such), on a comp-led build the build state (`.impeccable/build/state.json`), the spec, and the diff directories (`.impeccable/review/diff/hero/` and `.impeccable/review/diff/final/`, whose side-by-side, heatmap, region pairs, and `report.json` are the fidelity evidence), plus the chosen cue image (`.impeccable/design-context/cue.png`) on a questionnaire-seed world, named as the user's chosen cue, calibrating material and mood the way a QUALITY BAR card does, the craft-floor reference path, and on a native platform the platform reference path(s), [ios.md](ios.md) / [android.md](android.md), both on adaptive, plus one line saying no detector ran, so the reviewer judges in the platform's conventions rather than the web's. The reviewer has no browser; screenshots you fail to pass are checks it cannot run. Never read the shipped agents' definition files before spawning; the harness loads them at spawn, and you owe only the input packet. Wait on any agent with one long timeout rather than a loop of short polls, and spend the wait on the next independent step. Verify the return carries the five contract sections (a recapture return carries one, its recapture list); on an empty or thrashed return, respawn once with the same inputs. This review never runs inside the build thread and never inherits it: spawn the reviewer fresh, with no forked conversation history (`fork_turns: 0` in codex); a reviewer that inherits your transcript inherits your framing, your optimism, and your abstractions, and everything it needs travels in the inputs above. Only a harness with no subagent capability at all substitutes a fresh in-thread pass after stepping fully out of the build context, run from [degraded/finish-reviewer.md](degraded/finish-reviewer.md), and a substituted or failed-and-replaced review is disclosed in one line at finish, never silently. <!-- rule:skill-finish-separate-reviewer -->
Act on the disposition word; there are exactly four. **recapture**: the evidence failed, not the build. Recapture what the return names under the capture-validity rules, then run a full review over the new evidence. A review conducted on invalid evidence binds nothing, and a verdict pass may never follow it. **rebuild**: fidelity failed wholesale, not in patches. Skip the fix batch and execute the rebuild immediately: re-derive the named regions, produce the named assets, and send the result back for a fresh full review, never a verdict pass; a rebuild replaces regions wholesale, so the whole matrix runs again over the recaptures. Tell the user what is happening rather than asking permission to fix a failure. Consult the user only on a second rebuild directive, both verdicts on the table, or when rebuilding would discard content the user approved. **ship**: nothing is owed; report the verdict at its scope and continue to the documenter. **fix**: apply the material fixes in one batch, rebuild once, and recapture the same viewports over the same files. A recapture measures positions, loading, and overflow; it cannot measure whether a fix reached the quality the finding named, so send the recaptured screenshots back to the same reviewer for a verdict scoring every material fix resolved, partial, or unresolved (through the harness's agent continuation; without one, run the scoring fresh from [degraded/finish-reviewer.md](degraded/finish-reviewer.md)'s Verdict Pass). Fixes scored partial or unresolved get another batch, recapture, and verdict. Two rounds is the budget an unattended run ends at; an attended session's ceiling belongs to the user, so when the second verdict still lists open items, put the table in front of them and let them choose between shipping as it stands and funding another round; the table states in one line that the documenter has not run and, when DESIGN.md is still the pre-build seed, names that too, so the stop reads as what it is, a paused run with an unrecorded world. Whoever decides, stop the moment a round resolves nothing, and the reviewer's findings are the only list you work from, never your own re-opened hunt. Do not run a second detector. <!-- rule:skill-verdict-bounds-the-finish -->
+1 -1
View File
@@ -8,7 +8,7 @@ A probe tests composition, narrative, hierarchy, density, focal moment, signatur
The comp round runs inside the build's phase state: `build-phase.mjs start --direction <seed key> --kind <...>` has already run (the roll's output names the command) and its `comps` phase is open before the first comp is generated; a comp rendered before that sits outside the state, and a session resumed from that point has no phases to follow. `generate-image.mjs` refuses to write under `.impeccable/mocks/` until start has run; a harness-native image tool is bound by the same order.
Render three distinct high-fidelity north-star comps of the requested surface, saved under `.impeccable/mocks/` so they survive the session. Comp at the surface's own viewport: portrait at device size for a native app or mobile-first surface, desktop landscape otherwise; a phone screen comped landscape misstates the composition before anything is built against it. Comps are the build thread's own work, never delegated: the thread that writes the prompts holds the direction's full context and has seen every comp when the build starts. Open every image by its workspace-relative path; sandboxed viewers reject absolute paths, and everything under the project root has a relative one. Base the comps on real content and the surface concepts already developed with the user. On an established world, anchor every comp on the real identity: capture a screenshot of a representative existing page and pass it as a reference image (the harness image tool's input image, or `generate-image.mjs --ref`); the prompt leads with the new surface's structure while the reference carries palette, type, and component character, because DESIGN.md words alone drift where a pixel reference does not. Name what the reference contributes and what it must not: chrome, palette, type, and component character carry over; the reference page's own content does not, and a banner, hero, or card lifted verbatim is the reference leaking, not fidelity. Three is the number: one comp invites rubber-stamping; the spread between three surfaces the composition worth building. The chosen card's decision comp is the first of the three: it already renders this direction at full fidelity under this discipline, so generate two more that vary what the first held fixed, and send all three to the approval point together. Only a round arriving with no decision comp (a degraded roll, an identity-mode page, a direction pinned without the decision round) renders all three here.
Render three distinct high-fidelity north-star comps of the requested surface, saved under `.impeccable/mocks/` so they survive the session. Comp at the surface's own viewport: portrait at device size for a native app or mobile-first surface, desktop landscape otherwise; a phone screen comped landscape misstates the composition before anything is built against it. Comps are the build thread's own work, never delegated: the thread that writes the prompts holds the direction's full context and has seen every comp when the build starts. Open every image by its workspace-relative path; sandboxed viewers reject absolute paths, and everything under the project root has a relative one. Base the comps on real content and the surface concepts already developed with the user. On an established world, anchor every comp on the real identity: capture a screenshot of a representative existing page and pass it as a reference image (the harness image tool's input image, or `generate-image.mjs --ref`); the prompt leads with the new surface's structure while the reference carries palette, type, and component character, because DESIGN.md words alone drift where a pixel reference does not. On a seed world with no built page to screenshot, the chosen cue (`.impeccable/design-context/cue.png`) is that reference, the staged logo alongside when one exists; the same carry-over rule holds: material, palette, and type character transfer, the cue's own composition does not. Name what the reference contributes and what it must not: chrome, palette, type, and component character carry over; the reference page's own content does not, and a banner, hero, or card lifted verbatim is the reference leaking, not fidelity. Three is the number: one comp invites rubber-stamping; the spread between three surfaces the composition worth building. The chosen card's decision comp is the first of the three: it already renders this direction at full fidelity under this discipline, so generate two more that vary what the first held fixed, and send all three to the approval point together. Only a round arriving with no decision comp (a degraded roll, an identity-mode page, a direction pinned without the decision round) renders all three here.
- A comp is a designed surface, not a picture of the subject. Lead the prompt with the surface's own structure: the regions this design has, named in order with their scale relationships; a page with no navigation says so instead of inventing one, and an unconventional surface states its unconventional skeleton. A prompt that leads with atmosphere gets a vignette back: the model paints the fish market instead of the fish market's website. Self-check every render: if it could hang as a poster, or reads as a photograph with some text on it, it is not a comp; regenerate with the layout scaffold stated more literally.
- The inverse is also a failure: a surface with none of its subject in it. The subject appears as the content the regions hold; the world dresses the frame and never displaces what the frame shows. The deletion usually rides in on the prompt's exclusion list, so exclusions bind invented claims, and a medium ban belongs to the committed imagery stance, never to caution. Before accepting a render, point at the subject; a render that depicts everything about the world and nothing of the subject fails however faithful its atmosphere. Regenerate with the subject's content named region by region.
+57
View File
@@ -1171,6 +1171,7 @@ async function cli() {
parts.push(buildResolvedContextDirective(ctx, cliOptions, { targetExists }));
appendDetectorFallback(parts, ctx);
appendImageGenDirective(parts);
appendDesignContextDirective(parts, ctx);
appendBuildPathDirective(parts, ctx);
await appendCompRoundOpenDirective(parts, ctx);
appendAutonomyCounterDirective(parts);
@@ -1191,6 +1192,7 @@ async function cli() {
parts.push(buildResolvedContextDirective(ctx, cliOptions, { targetExists }));
appendDetectorFallback(parts, ctx);
appendImageGenDirective(parts);
appendDesignContextDirective(parts, ctx);
appendBuildPathDirective(parts, ctx);
await appendCompRoundOpenDirective(parts, ctx);
appendAutonomyCounterDirective(parts);
@@ -1367,6 +1369,61 @@ function appendBuildPathDirective(parts, ctx) {
}
}
// The design interview's durable record: when the user chose the visual world
// in the browser questionnaire, the choice survives as files (the cue image
// the palette was picked from, staged brand assets, every per-surface answer),
// not only as DESIGN.md prose. A later session must learn those files exist
// to open them; an older seed DESIGN.md may not name them at all. Bounded
// stats on fixed store paths only (Tier 1: no walks, no git).
//
// The names are spelled here rather than imported from
// design-context/store.mjs, which owns them: this script boots every session
// and imports only node builtins and ./lib, so a sibling directory missing
// from a harness's copy cannot take the whole session down with a resolve
// error. Same reason `.impeccable/config.json` is spelled out below. If the
// store ever moves, this list moves with it.
const DESIGN_CONTEXT_DIR = '.impeccable/design-context';
function appendDesignContextDirective(parts, ctx) {
const roots = [...new Set(
[process.cwd(), ctx.projectRoot, ctx.contextDir]
.filter(Boolean)
.map((dir) => path.resolve(dir)),
)];
for (const root of roots) {
const store = {
cuePng: path.join(root, DESIGN_CONTEXT_DIR, 'cue.png'),
answersJson: path.join(root, DESIGN_CONTEXT_DIR, 'answers.json'),
contextJson: path.join(root, DESIGN_CONTEXT_DIR, 'context.json'),
assetsDir: path.join(root, DESIGN_CONTEXT_DIR, 'assets'),
};
let cueExists = false;
let answersExist = false;
let contextExists = false;
let assetNames = [];
try { cueExists = fs.existsSync(store.cuePng); } catch {}
try { answersExist = fs.existsSync(store.answersJson); } catch {}
try { contextExists = fs.existsSync(store.contextJson); } catch {}
try {
assetNames = fs.readdirSync(store.assetsDir).filter((name) => !name.startsWith('.'));
} catch {}
if (!cueExists && !answersExist && assetNames.length === 0) continue;
const rel = (target) => path.relative(process.cwd(), target) || target;
const pieces = [];
if (cueExists) pieces.push(`${rel(store.cuePng)} (the image the user picked the palette from)`);
if (assetNames.length > 0) pieces.push(`${rel(store.assetsDir)}/ (staged brand material: ${assetNames.join(', ')})`);
if (answersExist) pieces.push(`${rel(store.answersJson)} (every questionnaire decision, per surface)`);
if (contextExists) pieces.push(`${rel(store.contextJson)} (the interview's chat half, with each staged file's kind and note under context.assets)`);
parts.push([
'DESIGN_CONTEXT: the visual world on record was chosen by the user in the design interview, and the interview record is files, not only prose: ' + pieces.join('; ') + '.',
"Before building or comping any surface on this world, open the cue image and every staged asset; they are the world's pixel truth, and a staged logo is the project's real mark.",
'reference/new-work.md names where each rides (comp reference, build material, reviewer calibration).',
].join(' '));
return;
}
}
// Image generation availability: harness-native tools always win, but when the
// environment carries an OpenAI key the API fallback works everywhere. The
// flag only reports capability, positively: absence stays silent, because a