Generated banner for Impeccable
Generated logo for Impeccable

Impeccable

Paul BakausCommunityCreated by Paul Bakaus

  • Skill
  • Workflow
  • Design and creative
  • Apache-2.0
  • Low risk
  • Has scripts

From the author

Use to design, redesign, critique, audit, polish or animate a frontend: websites, landing pages, dashboards, app UI, components, native iOS/Android screens, or a design system (DESIGN.md).
— the description by Paul Bakaus

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

Impeccable provides a structured approach to designing, auditing, and refining frontend interfaces including websites, dashboards, and mobile applications. It operates by establishing product context through documentation and applying specific design modes—Persuade, Operate, Read, and Experience—to guide the visual and functional direction of a project. The skill supports a wide range of tasks from initial planning and documentation to technical audits, visual refinements, and animation, ensuring that design changes remain consistent with the established visual world.

What it does

  • Audits UI for accessibility, performance, and responsive behavior.
  • Generates design documentation from existing project code.
  • Refines visual elements through commands like colorize, typeset, and layout.
  • Provides tools to plan UX and UI before implementation.
  • Manages design system tokens and component extraction.
  • Supports iterative design through live variant generation and testing.

When to use it

  • When you need to perform a UX critique or technical audit of an existing interface.
  • When starting a new design surface or defining a new visual world.
  • When you need to polish or refine UI components before a release.
  • When you need to adapt an interface for different screen sizes or platforms.
  • When you need to add purposeful animations or improve typography hierarchy.

Advantages

  • Provides a consistent framework for design decisions across different project types.
  • Integrates technical audits directly into the design workflow.
  • Supports specific modes to align design output with user intent.
  • Enables structured documentation of product and design context.
  • Offers granular control over UI refinements through specialized commands.

Usage examples

“impeccable audit src/components/Dashboard.tsx”
The agent performs a technical quality check on the dashboard component, reporting on accessibility, performance, and responsiveness.
“impeccable polish src/landing-page.css”
The agent executes a final quality pass on the landing page styles to ensure visual consistency and adherence to the design system.
“impeccable animate hero-section”
The agent applies purposeful motion and animation to the specified hero section based on the project's design mode.
“impeccable init”
The agent captures the current project context and creates a PRODUCT.md file to serve as the foundation for future design work.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/pbakaus/impeccable/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip impeccable.zip -d .agents/skills

Documentation by Paul Bakaus

This skill gives you the tools and permission to make design that earns the name out-of-distribution craft. Work as an award-winning design director would: production-grade code, a clear POV, a deep grasp of what the client and its users need, and exceptional craft.

Core principles:

  • Finish the job. No hedging, no shortcuts: the deliverable is complete, except assets the user must provide.

  • Scale ambition to the surface's mode (see Modes). Persuade and Experience get full commitment: bold, distinct work with a point of view. On Operate and Read, ambition shows as precision and restraint, and patterns the visitor already knows earn their place.

  • Verify by looking at the rendered result at the sizes it ships at, and batch the checks: fix what one look shows before looking again, rather than screenshotting after every tweak.

Setup

  1. Run "${CLAUDE_SKILL_DIR}/scripts/impeccable" context once per session, where ${CLAUDE_SKILL_DIR} is the directory that contains this SKILL.md (the skill folder, not a plugin root two levels above it); keep cwd at the user's project. Every "${CLAUDE_SKILL_DIR}/scripts/impeccable" <verb> command in this skill and its references resolves against that base directory. In reference files, replace the skill-base-dir placeholder with this directory before running commands; it is not a shell variable. On a Windows shell without sh, call & "${CLAUDE_SKILL_DIR}/scripts/impeccable.cmd" instead. The launcher runs a self-contained binary that ships next to it or is downloaded once on first run; no Node or other runtime is required. Pass a named source file or route as --target <path>. 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 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.

  3. After resolving analysis and direction, read reference/craft-floor.md immediately before any UI edit, including small refinements. It carries the quality floor, the absolute bans, and the reflexes no detector catches. Do not load it for planning-only work.

Launcher unavailable: On refusal or failure, send a separate message before the next tool call: “Context loading did not run; I’ll read the existing project context directly.” Then read existing PRODUCT.md and DESIGN.md without inventing missing context, follow applicable steps 2–3, including reading reference/craft-floor.md immediately before any UI edit, and continue through permitted tools. This applies to planning and editing; launcher failure alone does not block either.

How to design

  • The brief wins. Honor pinned aesthetics, eras, materials, fonts, and palettes even when they conflict with a saturated-pattern warning. Redirecting a clear brief toward your taste is failure.

  • Refinement preserves; redesign replaces. Refinement keeps the incumbent identity, behavior, copy, and everything outside scope. Ask before replacing factual copy or adding claims. Redesign keeps product truth, content, function, native affordances, and constraints, but treats the old look as evidence and anti-reference; choose a replacement world in new-work and replace DESIGN.md. Never split the difference into polish on the discarded look.

  • Loaded symbols stay out of the decoration. A subject's world does not license emblems tied to militarism, supremacy, or hate movements as motifs, badges, or ornament, such as the Rising Sun flag's rays, the Confederate battle flag, or Nazi-era insignia and their stylised variants; reach for that world's neutral forms instead. Content that documents such a symbol as fact stays as it is.

  • Visual authority is evidence, not a filename. Missing DESIGN.md alone does not make a project greenfield; new-work decides whether to preserve, expand, or replace the incumbent world.

Modes

The mode names what the visitor's success looks like on this surface.

  • Persuade: the visitor decides and acts; design is the product. Landing pages, marketing, campaigns, pricing. Earn attention and action. Ship real imagery when the brief needs it; follow the committed world, not category habit.

  • Operate: the visitor completes a task. App UI, dashboards, editors, admin, settings, tools. Scanability, consistency, native expectations, and the real usage scene outrank expression. Brand lives in precise details.

  • Read: the visitor understands something. Docs, articles, guides, help, changelogs. Structure for comprehension, then make the reading experience worth staying in.

  • Experience: the visitor is inside the work itself. Portfolios, galleries, showcases. Let the artifact lead from the first viewport; the interface recedes.

Choose the mode from the requested surface, not the product, and persist it only in that surface brief. A tool's landing page is still Persuade; a fashion house's documentation is still Read; a docs index is Read, not Persuade. See new-work.md for new surfaces and operate.md for deeper Operate/Read guidance.

Commands

CommandCategoryDescriptionReference
craft [feature]BuildDeprecated alias for an ordinary new-work requestreference/craft.md
shape [feature]BuildPlan UX/UI before writing codereference/shape.md
initBuildCapture durable product context in PRODUCT.mdreference/init.md
documentBuildGenerate DESIGN.md from existing project codereference/document.md
extract [target]BuildPull reusable tokens and components into design systemreference/extract.md
critique [target]EvaluateUX design review with heuristic scoringreference/critique.md
audit [target]EvaluateTechnical quality checks (a11y, perf, responsive)reference/audit.md · native: reference/audit.native.md
polish [target]RefineFinal quality pass before shippingreference/polish.md
bolder [target]RefineAmplify safe or bland designsreference/bolder.md
quieter [target]RefineTone down aggressive or overstimulating designsreference/quieter.md
distill [target]RefineStrip to essence, remove complexityreference/distill.md
harden [target]RefineProduction-ready: errors, i18n, edge casesreference/harden.md
onboard [target]RefineDesign first-run flows, empty states, activationreference/onboard.md
animate [target]EnhanceAdd purposeful animations and motionreference/animate.md
colorize [target]EnhanceAdd strategic color to monochromatic UIsreference/colorize.md
typeset [target]EnhanceImprove typography hierarchy and fontsreference/typeset.md
layout [target]EnhanceFix spacing, rhythm, and visual hierarchyreference/layout.md
delight [target]EnhanceAdd personality and memorable touchesreference/delight.md
overdrive [target]EnhancePush past conventional limitsreference/overdrive.md
clarify [target]FixImprove UX copy, labels, and error messagesreference/clarify.md
adapt [target]FixAdapt for different devices and screen sizesreference/adapt.md · native: reference/adapt.native.md
optimize [target]FixDiagnose and fix UI performancereference/optimize.md
liveIterateVisual variant mode: pick elements in the browser, iterate on alternativesreference/live.md
generate [n] [action] [element]IterateVariants, versions, or alternatives of a named element to choose from in the live browser; no manual pickingreference/generate.md

Routing:

  • No argument: read routing.md and present its context-aware menu; never auto-run a command.

  • Explicit or clearly implied request to run a command: load its reference (native variant on native platforms) and follow it. Ask once if two commands fit.

  • Workflow or command-selection question: read Workflow questions.

  • Otherwise: treat the request as general design work. Missing PRODUCT.md routes a new surface or replacement world through init, then new-work; a narrow refinement of existing code proceeds on the incumbent implementation as impeccable context directs, offering init afterward rather than blocking on it.

  • teach aliases init. craft is a deprecated alias for ordinary new-work and adds nothing. shape owns task discovery, then enters new-work only for visual-world and surface-concept decisions.

After init writes PRODUCT.md, resume without rerunning impeccable context; init loads the native platform reference itself when the platform it recorded is ios, android, or adaptive.

Pin / Unpin: "${CLAUDE_SKILL_DIR}/scripts/impeccable" pin <pin|unpin> <command> creates or removes a standalone /<command> shortcut. Report the script's result concisely; relay stderr verbatim on error.

Hooks: /impeccable hooks <on|off|status|ignore-rule|ignore-file|ignore-value|reset> manages the design detector hook for this project (auto-runs the detector after UI file edits and surfaces findings). Load reference/hooks.md when the user invokes it with any argument.

Doctor: /impeccable doctor reports and repairs drift between this project's Impeccable artifacts (PRODUCT.md, DESIGN.md and its sidecar, config, surface briefs, the hook) and what this version reads. Load reference/doctor.md when the user invokes it, or when they ask what is out of date, stale, or needs refreshing. A CONTEXT_STALE directive in Setup's output is the cheap subset of the same report; act on it there per its own instructions rather than running doctor unasked.

Never repair drift as a side effect of a design task. A CONTEXT_STALE finding is reported, not acted on, unless the user asks. The one exception is a finding marked auto, which the next write to that file performs anyway.

Files

reference/live.md

Interactive live variant mode: select elements in the browser, pick a design action, and get AI-generated HTML+CSS variants hot-swapped via the dev server's HMR.

Prerequisites

A running dev server with HMR (Vite, Next.js, Bun, etc.), OR a static HTML file open in the browser. If the dev server's default port is busy, the app is very likely ALREADY running; probe the default URL before spawning a second server.

Live editing requires a local checkout; injection into deployed production sites (including HTTPS) is unsupported. For production inspection, use "<skill-base-dir>/scripts/impeccable" detect <url> or the browser extension, not the live helper. Do not disable browser security or weaken production CSP to enable live mode.

The contract (read once)

Execute in order. No step skipped, no step reordered. Every tool output in live mode may carry an _instructions field: it is the authoritative next step for that exact situation, with real ids and paths substituted; when it conflicts with your recollection of this document, _instructions wins.

  1. impeccable live: boot. If the request names or implies a file, route, or app inside a monorepo, infer the concrete path and run "<skill-base-dir>/scripts/impeccable" live --target <path> instead; then run the rest of this live session from the returned projectRoot. The boot resolves the app root from dev-server config files and persists it in .impeccable/live/roots.json; every helper re-anchors to that manifest at startup (a wrong cwd cannot fork session state), PRODUCT.md / DESIGN.md are discovered upward to the git root, and relative helper args like --file resolve against the app root.

  2. Open the app URL that serves pageFile (infer from package.json, docs, terminal output, or an open tab). Never use serverPort; it's the helper, not the app. Cursor: browser_navigate to that URL before polling; do not skip. Other harnesses: use the available browser tool; if the URL is uncertain, ask the user once.

  3. Poll loop with the default long timeout (600000 ms). Run impeccable live-poll again immediately after every event or --reply; Codex runs this one-shot poll in the foreground. Never pass a short --timeout=. The global bar's Impeccable mark dims with a pulsing amber dot when nothing is polling /poll; restart impeccable live-poll to reconnect.

  4. On generate: reuse event.scaffold when present; read the screenshot if present; load the action's reference; deliver variants; --reply done; poll again. Generate in this thread: you already hold the project's tokens and layout. The overlay preview IS the verification channel; do not screenshot, re-render, or QA variants between generate and accept. Apply craft-floor's contrast, spacing, and type floors by construction as you write; full verification runs once at accept on the chosen variant.

  5. On steer: read the message and pageUrl; do the work; --reply steer_done; poll again. No pickup ack.

  6. On accept / discard: the poll script runs impeccable live-accept, acknowledges delivery, and prints _completionAck. Plain accepts/discards are terminal immediately; carbonize accepts stay recoverable until impeccable live-complete --id EVENT_ID runs. Finish that cleanup before polling again.

  7. If interrupted, run impeccable live-status or impeccable live-resume before guessing. The journal under .impeccable/live/sessions/ is canonical and replays unacknowledged work after a helper restart; the injected live.js re-attaches when the page reopens. Fall back to the direct-edit loop only when impeccable live-resume reports no active session, never because disconnects felt frequent.

  8. On exit: run the cleanup at the bottom.

Harness policy:

  • Claude Code: run the poll as a background task (no short timeout); the harness notifies you on completion. Do not block the shell.

  • Cursor: one-shot poll in a background terminal with notify on "type":"(steer|generate|accept|discard|manual_edit_apply|variant_mount_failed|prefetch|exit)"; handle, --reply, restart the poll. Do not use --stream on Cursor (measured ~5s pickup vs sub-second one-shot).

  • Codex: default one-shot poll in a yielded foreground exec session. No &, no --stream, never leave Live without an active foreground poll. Starting the poll is not enough: SERVICE it (keep reading the exec session until it returns an event). Never announce "waiting for the user" and idle; a yielded poll nobody reads is a dead session, and the user's Go sits unanswered.

  • Other harnesses: one-shot foreground unless you know stdout reliably returns when a shell exits.

Delivery policy: atomic single-edit delivery everywhere; do not switch a harness to progressive publishing unless its poll loop is known not to block on the extra calls.

Chat is overhead. No recap, no tutorial output, no pasting PRODUCT / DESIGN bodies. Spend tokens on tools and edits; on failure, one or two short sentences.

Poll loop

LOOP:
  "<skill-base-dir>/scripts/impeccable" live-poll   # default long timeout; no --timeout=
  Read JSON; dispatch on "type"

  "generate"  → Handle Generate; reply done; LOOP
  "steer"     → Handle Steer; reply steer_done; LOOP
  "accept"    → Handle Accept; complete carbonize cleanup if required; LOOP
  "discard"   → Handle Discard; LOOP
  "prefetch"  → Handle Prefetch; LOOP
  "manual_edit_apply" → Handle Manual Edit Apply; reply done|partial|error; LOOP
  "variant_mount_failed" → Fix the variant files; reply done --file <path>; LOOP
  "timeout"   → LOOP
  "exit"      → break → Cleanup

variant_mount_failed means the browser could not render what you published (variant, module url, error). The user sees a persistent error card, not variants. Fix the variant files, then --reply EVENT_ID done --file <manifest or source path>; the browser retries on its own.

Stream mode (--stream, experimental, never on Cursor): one long-lived process, one JSON line per event, --reply from a separate command. Only for harnesses that read incremental stdout reliably.

Start

"<skill-base-dir>/scripts/impeccable" live

Output JSON: { ok, serverPort, serverToken, pageFiles, roots, hasProduct, product, productPath, hasDesign, design, designPath, hasSurfaceBrief, surfaceBrief }. roots is the resolved root manifest; projectRoot mirrors roots.appRoot. The surface brief rides along; do not shell out to impeccable surface-brief separately. Precedence for generation: DESIGN.md wins on visual decisions; PRODUCT.md wins on durable product and voice decisions; the surface brief wins on this surface's strategy. When DESIGN.md is missing, identity is not absent; extract it from CSS variables, computed styles, and sibling components (Step 4 Phase A). Identity preservation is the default; departure requires the user's explicit redesign intent.

serverPort/serverToken belong to the small helper HTTP server (/live.js, SSE, /poll), not your dev server; the page URL is whatever origin serves a pageFiles entry.

If output is { ok: false, error: "config_missing" | "config_invalid", path }, this project needs one-time configuration: read live-setup.md and follow it. If the output carries a non-null configDrift, tell the user once which HTML files are uncovered and suggest adding them or switching files to a glob; never auto-edit the config.

Recovery commands

The append-only journal under .impeccable/live/sessions/ is canonical durable state (not project source). When the chat was interrupted, polling was missed, the helper restarted, or the browser reloaded:

"<skill-base-dir>/scripts/impeccable" live-status      # helper state, active sessions, queued events; works with the helper down
"<skill-base-dir>/scripts/impeccable" live-resume --id SESSION_ID   # active snapshot, pending event, next safe action
"<skill-base-dir>/scripts/impeccable" live-complete --id SESSION_ID # canonical manual final acknowledgement after verified cleanup

Server restart rule: start impeccable live-server again, then poll; startup requeues unacknowledged events, so never ask the user to click Go again unless impeccable live-resume says no active session exists.

Handle generate

Replace mode (default): {id, action, freeformPrompt?, count, pageUrl, element, screenshotPath?, comments?, strokes?}.

Insert mode (event.mode === "insert"): {id, mode: "insert", count, pageUrl, insert: { position, anchor }, placeholder: { width, height }, freeformPrompt?, screenshotPath?, comments?, strokes?}. No action; requires a non-empty freeformPrompt or annotations. placeholder is a soft size hint.

Speed matters; the user is watching the selected element. Reuse preflight metadata, minimize discovery calls.

Insert mode branch
  1. Read the screenshot if present (annotations only).

  2. If event.scaffold is present, use it and do not run the helper again. Otherwise:

"<skill-base-dir>/scripts/impeccable" live-insert --id EVENT_ID --count EVENT_COUNT --position after \
  --element-id "ANCHOR_ID" --classes "class1,class2" --tag "section" --text "ANCHOR_TEXT"

--position ← event.insert.position; anchor flags map exactly like wrap's. The scaffold has no data-impeccable-variant="original"; variants are net-new HTML+CSS at insertLine. On source-preview targets the scaffold carries sourceWritten: false with wrapperBlock and replaceEndLine < replaceStartLine (an insertion): splice variants into wrapperBlock at the marker and insert at replaceStartLine in ONE edit, exactly as the wrap section describes. Decide the visitor mode from the surface and load craft-floor.md before writing net-new markup. Svelte targets follow the same component flow as wrap below (mode: "insert" in the manifest): each variant is a real single-root component under componentDir with no data-impeccable-* attributes; never edit the route during generation; accept splices the chosen markup into sourceFile mechanically. For non-Svelte targets, accept/discard removes the wrapper; the anchor is untouched.

Replace mode (default)
1. Read the screenshot (if present)

event.screenshotPath is sent only when the user annotated before Go; it is a PNG of the element with annotations baked in. Read it before planning. When absent, do not ask for one or screenshot the page yourself: without annotations a screenshot anchors you on the existing design and fights the three-distinct-directions brief; work from element.outerHTML, the computed styles, and the prompt.

Annotation semantics: a comment's {x, y} is element-local and binds the text to the child under that point (a comment near the title is about the title). Comments and strokes are independent unless clearly paired. Strokes read by shape: closed loop = "this thing" (emphasis, not a clipping region); arrow = direction or movement; cross/slash = delete; scribble = emphasis or delete by context. If a stroke's intent is genuinely ambiguous and it changes the brief, ask one short question before generating; otherwise state your reading in one sentence.

2. Wrap the element

When event.scaffold is present, the helper already found the source and computed the wrapper; treat it as the successful output and skip the command. event.scaffoldAttempted with scaffoldError means preflight could not finish; use the command below.

On source-preview targets event.scaffold carries sourceWritten: false. The helper did NOT write the wrapper; it hands you scaffold.wrapperBlock plus the picked element's source range (replaceStartLine, replaceEndLine, 1-indexed). Write the wrapper and all variants in ONE edit: splice your variants into wrapperBlock at the "Variants: insert below this line" marker, then replace lines [replaceStartLine, replaceEndLine] with the result. A separate scaffold write reloads the framework before your variant write lands and strands the browser at 0/N. (replaceEndLine < replaceStartLine means insert mode: insert, remove nothing.) The svelte-component path never sets sourceWritten.

"<skill-base-dir>/scripts/impeccable" live-wrap --id EVENT_ID --count EVENT_COUNT --element-id "ELEMENT_ID" --classes "class1,class2" --tag "div" --text "TEXT_SNIPPET"

Flag mapping (keep separate, never collapse into --query): --element-id ← event.element.id; --classes ← classes joined with commas; --tag ← tagName; --text ← first ~80 chars of textContent, every call: it disambiguates repeated sibling components, without it wrap lands on the first match. If event.pageUrl implies the file, pass --file PATH. If --text still matches several candidates, wrap exits { error: "element_ambiguous", candidates, fallback: "agent-driven" }: pick the right range from page context and write the wrapper manually per the fallback flow.

Success output: { file, insertLine, commentSyntax, styleMode, styleTag, cssSelectorPrefixExamples, cssAuthoring } (plus the sourceWritten: false fields above on source-preview targets). Run directly with no preflight scaffold, it writes the wrapper itself and you splice variants at insertLine. styleMode controls how preview CSS must be authored. Treat it as a detected capability mode, not a framework guess: scoped means @scope ([data-impeccable-variant="N"]) rules; astro-global-prefixed means explicit [data-impeccable-variant="N"] prefixes with the exact returned styleTag. Use cssAuthoring as the source of truth for the current file (styleTag, selector strategy, requirements, forbidden patterns); apply no framework-specific exception unless it says to.

For Svelte/SvelteKit targets, impeccable live-wrap returns previewMode: "svelte-component" with file pointing at a temporary node_modules/.impeccable-live/<id>/manifest.json, componentDir holding the variant components, and sourceFile the real route. The scaffold is AST-based: control-flow blocks ({#each}, {#if}) survive intact and a free each-collection crosses the contract as ONE structured prop (kind collection). The payload includes componentStubMarkup (the prop-substituted markup already written into every stub), so do not read the manifest or stubs back. EDIT v1.svelte, v2.svelte, ... in place; never delete and recreate them; keep the stub's control flow and propContract prop names; never flatten a loop into literal items. The stub <style> arrives seeded with the source rules that currently style the selection; restyle or delete them freely. On accept, any seeded rule your variant does not re-declare is REMOVED from the source (the preview never applied it, so the user approved a design without it). Use semantic class selectors, no @scope, no data-impeccable-*. Reply with --file set to the manifest path; the browser mounts the compiled components so Svelte HMR does not reset page state. Accept merges the chosen component back mechanically (markup restored to route expressions, CSS reconciled, params baked, indentation preserved); you have no post-accept cleanup on this path. When the selection contains constructs a detached preview cannot support (component tags, bind:/use:, await blocks, inline scripts, spread attributes), wrap returns the normal source-preview wrapper with previewFallback: { from: "svelte-component", reason }; just follow the returned shape.

Params on component-preview paths go in a sidecar, never as an attribute (Svelte parses { in attribute values as an expression). Declare them in componentDir/params.json keyed by variant number, using the schema from section 7:

{ "1": [ {"id":"density","kind":"steps","default":"snug","label":"Density","options":[
    {"value":"airy","label":"Airy"},{"value":"snug","label":"Snug"} ]} ] }

Author the component <style> against var(--p-<id>, default) for range/toggle and [data-p-<id>="…"] for steps, wrapped in :global(...) so runtime knob values on the mounted root reach your rules.

Fallback errors. Wrap refuses to write into non-source files (generated, untracked): accepting into one is silent data loss. Three shapes, all with fallback: "agent-driven" (see Handle fallback): file_is_generated (your --file points at a generated file), element_not_in_source with generatedMatch (element only exists generated), element_not_found (likely runtime-injected).

3. Load the action's reference

event.action is impeccable (freeform): work from SKILL.md's design rules plus craft-floor.md; decide the visitor mode from the surface; do not load a sub-command reference. Freeform is not a pass to skip parameters: follow the budget and freeform bias in section 7. Any other action (bolder, quieter, distill, polish, typeset, colorize, layout, adapt, animate, delight, overdrive): read reference/<action>.md before planning; its MUST params layer on top of the section 7 budget.

4. Plan three variants: identity first, then mode, then axes

Live runs on an existing surface; the brand is already chosen. The job is variation within identity, not selection between identities. The worst failure is three off-brand variants the user cannot accept. Four phases, in order.

Phase A: Extract the identity (non-skippable)

Sources in priority order: DESIGN.md's visual system fields; CSS custom properties (de-facto tokens); computed styles on the picked element and parent; sibling components' visual rhetoric. Write ONE sentence recording what is actually on screen: dominant surface and accent color (real values, not "warm"), the loaded font pairing, layout topology (stacked / side-by-side / grid / asymmetric / overlay), surface treatment (corners, borders, shadows, decoration density), and the voice tone read off the copy. Be specific; skip an axis rather than fabricate; do not name an aesthetic family (a conclusion, not data). This sentence is the identity lock: every variant must read as the same brand side by side. Absence of DESIGN.md is never an excuse.

Phase B: Pick mode (default vs departure)

Default preserves the identity and varies expression within it; right for ~90% of sessions. Departure rejects the identity; trigger ONLY on the user's explicit ask in the current request or prompt ("redesign this", "rebuild from scratch", "something completely different"); a stale critique or old note is not authorization. Unsure means default: wrong-default costs "three on-brand variants with similar feel" (recoverable), wrong-departure costs three off-brand variants (unrecoverable).

Phase C: Plan three variants

Default mode. Each variant commits to a different primary axis, preserving the identity sentence. The six axes: 1 Hierarchy (which element commands the eye), 2 Layout topology (stacked / side-by-side / grid / asymmetric / overlay), 3 Typographic system (pairing logic, scale ratio, case/weight, within the available faces), 4 Color strategy (which existing palette role carries the surface: Restrained / Committed / Full palette / Drenched; existing tokens only), 5 Density (minimal / comfortable / dense), 6 Structural decomposition (merge, split, progressive disclosure). Three variants, three DIFFERENT axes: the same brand at three angles. New fonts, new hues, or new aesthetic-family signals belong to departure mode only.

Departure mode. Each variant anchors to a different aesthetic direction derived from the brand, never a fixed catalog: read PRODUCT.md's Brand Personality words; derive physical, spatial, or material experiences that embody them; from those, derive three directions genuinely different from each other AND from the current surface; reject reflex choices whose rationale would fit a neighboring product. Each direction must be one concrete sentence naming a real-world referent ("a museum exhibition label system", not "clean and minimal").

In both modes, name each variant's 2 or 3 parameter knobs while planning (section 7 budget). Parameters are part of the design; deciding "what's tunable" during planning beats retrofitting.

Phase D: Squint test

Default: compare each variant against the Phase A lock; palette, type voice, or rhetoric drift means it crossed into departure by accident: rework. Then confirm three different primary axes; three "tighter density" variants is failure. Departure: two passes, family before sentence. Family pass (non-negotiable): label each variant with a concrete family of your own choosing; shared or interchangeable labels mean rework. Sentence pass: three one-line descriptions side by side; two that rhyme mean rework. When the primary axis is color or theme, the trio must not share theme + dominant hue: three color worlds, not three shades.

Action-specific invocations must vary along the action's dimension; in default mode every variation stays within the available faces and existing tokens:

  • bolder: amplify a different dimension per variant (scale / saturation / structural change).

  • quieter: pull back a different dimension (color / ornament / spacing).

  • distill: remove a different class of excess (visual noise / redundant content / nested structure).

  • polish: a different refinement axis (rhythm / hierarchy / micro-details).

  • typeset: departure varies the pairing AND the scale ratio each; default keeps the faces and varies scale ratio, case, and weight each.

  • colorize: departure gives each a different hue family and varies chroma and contrast strategy; default gives each a different existing palette role carrying the surface (Restrained / Committed / Full palette / Drenched) and a different contrast strategy.

  • layout: different structural arrangement, not spacing tweaks.

  • adapt: different target context per variant (mobile-first / tablet / desktop / print or low-data).

  • animate: different motion vocabulary (cascade stagger / clip wipe / scale-and-focus / morph / parallax).

  • delight: different flavor of personality (micro-interaction / typographic surprise / illustrated accent / sonic-or-haptic / easter egg).

  • overdrive: different convention broken (scale / structure / motion / input model / state transitions); skip its "propose and ask" step, live is non-interactive.

5. Apply the freeform prompt (if present)

event.freeformPrompt is the user's ceiling on direction: all variants honor it while exploring different interpretations within the Phase B mode. Default mode: the prompt narrows the axes, not the identity ("more confident" → one variant amplifies hierarchy, one commits the accent color, one tightens density). Departure mode: the prompt narrows the lanes, not the families ("newspaper front page" → broadsheet vs tabloid vs trade journal, then run the family pass). When the prompt conflicts with a binding brand commitment or DESIGN.md invariant, preserve the invariant unless the user explicitly revokes it.

6. Deliver variants

Complete HTML replacement of the original element per variant, not a CSS-only patch. Colocate preview CSS as a <style> tag inside the wrapper. Atomic default: CSS + all variants + parameter manifests in one edit at insertLine.

<!-- Variants: insert below this line -->
<style data-impeccable-css="SESSION_ID">
  /* rules matching cssAuthoring.rulePattern */
</style>
<div data-impeccable-variant="1">
  <!-- variant 1: full element replacement (single top-level element) -->
</div>
<div data-impeccable-variant="2" style="display: none">
  <!-- variant 2 -->
</div>
<div data-impeccable-variant="3" style="display: none">
  <!-- variant 3 -->
</div>

Replace the style opening tag with cssAuthoring.styleTag when the tool returns a different one, and close it with cssAuthoring.styleClose (</component> on .vue). Each variant div contains exactly one top-level element, same tag as the original; loose siblings break outline tracking and accept. First variant visible, all others display: none. The browser's MutationObserver accepts atomic or progressive arrival; accepting an arrived variant fences the worker, so later publications are rejected.

For styleMode: "scoped", author every :scope rule with a descendant combinator: the @scope boundary is the variant wrapper div, not your element, so a bare :scope { ... } styles a display: contents shell. Always step in (:scope > .card, :scope .hero-title). The fake test agent's CSS in the repo agent template is a faithful template.

JSX / TSX targets: wrap <style> content in a template literal (CSS braces would parse as JSX), use className= / style={{…}}, keep data-impeccable-* attributes as plain strings:

<style data-impeccable-css="SESSION_ID">{`
  @scope ([data-impeccable-variant="1"]) { ... }
`}</style>
<div data-impeccable-variant="2" style={{ display: 'none' }}>
  {/* variant 2 */}
</div>

The wrap script provides a single-rooted JSX wrapper with the marker comments inside; drop the block at the marker and the source stays valid TSX.

7. Parameters (composition-sized, 0-4 per variant)

Each variant can expose coarse knobs; the browser docks one control per parameter with zero regeneration cost (knobs drive a CSS variable or data attribute your scoped CSS is authored against). Wire an axis as soon as the user could plausibly mutter "a bit tighter" or "a touch more accent" without wanting a regeneration; micro-margins and one-off nudges are not parameters. Freeform bias: you chose the axes, so expose them; a hero with 0 params is almost always a mistake, and 1 is underweight unless the design is a genuine fixed point.

Budget scales with the element's VISUAL weight (count visual children, not DOM depth):

  • Leaf / tiny (button, icon, bare heading): 0 params.

  • Small composition (simple card, labeled input, ≤ ~5 visual children): 0-1.

  • Medium composition (section, nav cluster, 6-15 children): target 2; 1 if simple.

  • Large composition (hero, full region, 16+ children or sub-sections): target 2-3, up to 4 when independent axes are all authored in CSS.

Hard cap: four per variant. For named sub-commands, the action reference's MUST params are non-negotiable when expressible; respect the cap, no duplicate knobs.

Declare on the HTML/JSX path as a wrapper attribute (component-preview paths use componentDir/params.json instead, same schema, keyed by variant number; see the wrap section):

<div data-impeccable-variant="1" data-impeccable-params='[
  {"id":"color-amount","kind":"range","min":0,"max":1,"step":0.05,"default":0.5,"label":"Color amount"},
  {"id":"serif","kind":"toggle","default":false,"label":"Serif display"}
]'>

Three kinds: range (slider; drives --p-<id>; author var(--p-color-amount, 0.5); fields min/max/step/default/label), steps (segmented radio; drives data-p-<id>; author :scope[data-p-density="airy"] .grid { ... }; fields options/default/label), toggle (drives both --p-<id>: 0|1 and attribute presence; fields default/label). Reset on variant switch is a known limitation: each variant starts at its declared defaults.

On accept, the browser sends current values and impeccable live-accept writes them as a sibling comment: <!-- impeccable-param-values SESSION_ID: {"color-amount":0.7} -->. Carbonize cleanup bakes them: keep only the matching steps/toggle branch, drop the others, collapse :scope[data-p-…] to semantic rules; substitute range literals or update the var's default.

8. Signal done
"<skill-base-dir>/scripts/impeccable" live-poll --reply EVENT_ID done --file RELATIVE_PATH

RELATIVE_PATH is relative to project root; the browser fetches source directly if the dev server lacks HMR. Then poll again immediately.

Aborting an in-flight session

If wrap or generation fails after the browser flipped to GENERATING, tell the browser so its bar resets: "<skill-base-dir>/scripts/impeccable" live-poll --reply EVENT_ID error "Short reason". Never use live-accept --discard for this (pure file mutator, browser never sees it, bar sticks on dots); --discard is only source-side cleanup for a discard the browser itself initiated.

Handle fallback

When wrap returns fallback: "agent-driven", you pick the source file yourself; the goal is unchanged: three preview variants now, and the accepted one persisted where the next build cannot wipe it.

  1. Find where the element really lives from the error payload: element_not_in_source + generatedMatch means the served HTML is generated, so find the generator's template or partial; element_not_found means runtime-injected, so find the rendering component or data source; file_is_generated resolves the same way. A purely visual change may belong in a shared stylesheet rather than a template.

  2. Preview in the served file: manually write the same wrapper scaffold impeccable live-wrap produces into the file the browser actually loaded, moving the element itself into the original slot: <!-- impeccable-variants-start ID --><div data-impeccable-variants="ID" data-impeccable-variant-count="3" style="display: contents"><div data-impeccable-variant="original">THE ELEMENT, UNCHANGED</div><!-- Variants: insert below this line --></div><!-- impeccable-variants-end ID -->. Insert your variant divs after the marker, then --reply EVENT_ID done --file <served file>. Never drop the original slot: discard restores the element from it and refuses a wrapper without one. This edit is temporary; a regen wiping it is fine.

  3. On accept, write to true source (accept refuses generated files, so _acceptResult.handled is usually false here): structural change → template/component source; visual-only → the right stylesheet; content rendered from data → the data source or render logic. Then remove the temporary wrapper from the served file.

  4. On discard, just remove the temporary wrapper.

Handle accept

Event: {id, variantId, _acceptResult, _completionAck}. The poll script already ran impeccable live-accept deterministically and acknowledged delivery; the browser DOM is already updated.

  • The accept event includes pageUrl; the poll script must forward it to impeccable live-accept --page-url PAGE_URL so accept-time cleanup only scrubs staged copy edits for the current page.

  • _completionAck.ok !== true: do not poll yet. Run impeccable live-status / impeccable live-resume, finish cleanup manually if needed, then impeccable live-complete --id EVENT_ID.

  • handled: true, carbonize: false: nothing to do; poll again.

  • handled: true, carbonize: true: required cleanup below; _acceptResult.todo, _completionAck.requiresComplete, and the stderr banner all point at it.

  • handled: false, mode: "fallback": the session lived in a generated file; you already wrote true source in fallback Step 3; clean the temporary wrapper and poll.

  • handled: false, mode: "error": do not hand-edit the file. source_locked: rerun the same impeccable live-accept command (idempotent) until the publisher releases. accept_receipt_conflict: the session already resolved as priorOperation; run impeccable live-status and tell the user. Anything else: report briefly, run impeccable live-status first.

  • handled: false without mode: manual cleanup: read file, find markers, edit.

Required after accept (carbonize)

carbonize: true means the accepted variant is stitched into source with helper markers and inline CSS (so the browser renders with no gap). That stitch-in is temporary; rewrite it into permanent form before anything else, or dead @scope rules, wrapper divs, and marker comments accumulate across sessions. Five steps, synchronously, before the next poll:

  1. Locate the carbonize block in _acceptResult.file: bracketed by <!-- impeccable-carbonize-start/end SESSION_ID --> with a data-impeccable-css style element; read the <!-- impeccable-param-values --> comment first when present, it drives steps 3 and 4.

  2. Move the CSS rules into the project's real stylesheet (whichever already owns styling for the surrounding element).

  3. Bake param values while rewriting selectors: retarget @scope ([data-impeccable-variant="N"]) to real semantic classes; keep only the :scope[data-p-<id>="VALUE"] branch matching the chosen value; substitute var(--p-<id>) literals or update the var's default.

  4. Unwrap the accepted content: delete the inner variant div (and on JSX the outer data-impeccable-carbonize div); drop data-impeccable-params and all data-p-* attributes.

  5. Delete the inline data-impeccable-css style element, the param-values comment, both carbonize markers, and any @scope rules for non-accepted variants.

Then run impeccable live-complete --id SESSION_ID and verify phase: "completed" before polling again. The command is a gate, not a formality: it refuses with error: "source_dirty" plus findings while any live-mode leftover remains; fix and rerun (--force only for false positives).

Handle discard

Event: {id, _acceptResult, _completionAck}. The poll script already restored the original and acknowledged discarded. Nothing to do unless _completionAck.ok !== true; then impeccable live-complete --id EVENT_ID --discarded and poll again.

Handle steer

Event: {id, message, pageUrl}: page-level direction from the global bar's Steer control (typed or spoken), no element context, no variant cycling. Read message, inspect the page or files as needed, make edits or answer in prose. Reply "<skill-base-dir>/scripts/impeccable" live-poll --reply EVENT_ID steer_done ["Optional short toast"], or on failure --reply EVENT_ID error "Short reason", then poll immediately. No separate pickup reply; the Steer bar unlocks on steer_done or error.

Handle prefetch

Event: {pageUrl}: fired once per route on first selection; the user is likely about to Go on a page you have not read. Resolve the route to its file (root / is usually the boot's pageFile; multi-page sites often map /foo to public/foo/index.html; SPAs map everything to one entry), read it, poll again. No --reply. If you cannot resolve it confidently, skip and poll.

Handle manual_edit_apply

Event: {id, pageUrl, batch: {entries}, evidencePath?, chunk?, repair?, deadlineMs}.

The user already clicked Apply. Do not ask what to do, discard, or redirect to Go. The parent live thread keeps the foreground poll loop and sends the final /poll --reply --data.

When native subagents are available, delegate source edits to impeccable_manual_edit_applier / impeccable-manual-edit-applier. Pass cwd, scripts path, event id, page URL, chunk/deadline, batch, evidencePath, and the canonical JSON result schema. The subagent must not poll or reply. If unavailable, apply inline with the same contract.

An op with deleted: true and removeElement: true is the browser's Remove badge: delete that whole element from source, children included, not just its text. Locate it by sourceHint, then by leaf.outerHTML and originalText, and remove exactly that element's source range; leave no empty wrapper, orphaned children, or dangling markup behind.

If repair is present, the previous Apply changed source but final validation failed. Fix the current source and return the same canonical JSON result; do not roll files back yourself. The browser will ask the user before any rollback.

After source edits finish, reply exactly once with "<skill-base-dir>/scripts/impeccable" live-poll --reply EVENT_ID done --data '{"status":"done","appliedEntryIds":["8hexid"],"failed":[],"files":["src/page.html"],"notes":[]}'. Use status:"partial" or status:"error" with failed[] when not every entry applied. Then poll again. Never reply without the event id; --reply done --file ... is invalid for manual Apply.

Exit

The user stops live mode by saying so in chat, closing the tab (SSE drops; poll returns exit after 8s), or the browser's exit button. On exit, kill any still-running background poll, then clean up.

Cleanup

"<skill-base-dir>/scripts/impeccable" live-server stop

Stops the helper and runs impeccable live-inject --remove to strip the injected script (use stop --keep-inject to keep it for a quick restart; .impeccable/live/config.json persists as project config). Then search for and remove any leftover impeccable-variants-start wrappers and impeccable-carbonize-start blocks.

First-time setup

Only when impeccable live reports config_missing / config_invalid, or configDrift needs explaining, or the config lacks cspChecked: read live-setup.md. It owns the config schema, the per-framework files table, injection adapters, drift healing, and the CSP detection and consent flow.

Requirements and compatibility

Written for: Claude Code

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Claude Code frontmatter, Needs Node.js

Security

What our scanner noticed· Low risk

  • Scripts that your agent may run

This skill includes scripts that your agent may run. Read them before you use it.

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
Paul Bakaus
Publisher
Paul Bakaus (Community)
Source
pbakaus/impeccable · plugin/skills/impeccable · commit 687bc38
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • NOTICE (added by AutoGineer from NOTICE.md)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Paul Bakaus.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download impeccable.zip