Commit Graph
160 Commits
Author SHA1 Message Date
Paul BakausandClaude Opus 4.7 cd8dbff014 fix(live-accept): handle JSX self-closing <style />, single-line variants, and same-line style blocks
Three related extraction bugs surfaced in the EAC session all rooted
in the line-based state machine:

1. `<style ... />` (JSX self-closing) had no separate `</style>` for
   the "skip until close" mode to exit on, so the state machine stuck
   and every `data-impeccable-variant` marker after it got missed.
   Accept reported `handled: false, error: "Variant N not found"`.
2. A variant whose entire `<div ...>...</div>` sits on one line had
   its body silently discarded — the marker line was `continue`d past,
   and the extractor started capturing from the next line, which
   usually belonged to a different variant or the wrapper close.
3. `extractCss` kept scanning for `</style>` after a self-closing
   opener, greedily swallowing every subsequent variant div as "CSS".
   Result: a mangled carbonize block stuffed with HTML and a duplicate
   variant rendered below.

## Fix

Replaced the line-based state machine with a string-based flow:

- `stripStyleAndJoin(lines, block)` returns the wrapper text with
  `<style>` elements fully removed. Handles self-closing, same-line
  open+close, and multi-line open/close. Markers inside CSS strings
  (e.g. `@scope ([data-impeccable-variant="1"])`) are gone by the
  time extraction runs — no false positives.
- `extractInnerByAttr(text, attrMatch)` is a balanced-tag matcher that
  walks the joined text finding `<TAG ...attrMatch...>…</TAG>` with
  proper depth tracking for nested same-tag elements. Handles
  single-line, multi-line, and deeply nested variants.
- `extractOriginal` and `extractVariant` are thin wrappers over the
  above.
- `extractCss` gets explicit same-line handling: returns null for
  self-closing (nothing to carbonize), extracts inner content via
  regex for same-line `<style>…</style>`, falls through to the
  existing multi-line path otherwise.

## Tests

New tests/live-accept.test.mjs with four cases — all failing before,
all passing after:

- Self-closing `<style />` with dangerouslySetInnerHTML
- Single-line `<style>…</style>`
- Multi-line `<style>...</style>` (regression baseline)
- Discard restores the original element after self-closing style

Wired into `bun run test`. Full suite passes.

Credit: precise repro + root-cause trace from the other agent in the
EAC session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 01:01:43 -07:00
Paul BakausandClaude Opus 4.7 a4832adf2f fix(live-wrap): JSX/TSX correctness — multi-line tags, className, tag narrowing
Five related bugs that surfaced in a real Next.js App Router project
(EAC) all rooted in live-wrap.mjs treating source as line-anchored HTML:

1. findElement matched on raw substring anywhere, so it landed on a
   className continuation line of a multi-line JSX tag whose class
   happened to collide with a later target. The wrong tag got wrapped
   (really, its attribute line got wrapped, producing broken JSX).
2. findClosingLine's opener regex required whitespace or `>` after the
   tag name, so a bare `<section\n  className="..."\n>` opener was
   unrecognised; it returned `start` silently, capturing only one line.
3. buildSearchQueries only emitted `class="..."`, missing React's
   `className="..."`. The full-combo query never fired in JSX, so
   search silently degraded to single-class substring matching.
4. Wrapper output used `style="display: contents"` unconditionally,
   which is invalid JSX (type error in strict setups, parser hazard
   in production transforms).
5. --tag was ignored during the primary class search. Ambiguous class
   hits inside the wrong element type weren't filtered out.

## Fixes

- New OPENER_RE `/<([A-Za-z][A-Za-z0-9]*)(?=[\s/>]|$)/` recognises
  tag openers at end-of-line too.
- New findOpenerLine(lines, matchLine, tag): walks up to 10 lines
  backward to the enclosing opener when the match lands on a
  continuation line. Aborts the walk if it hits a different tag.
- findElement now iterates all matches (not just the first), takes
  a tag parameter, and routes through findOpenerLine; wrapCli passes
  --tag through.
- buildSearchQueries emits both `class="..."` and `className="..."`
  for multi-class queries, and both `<tag class="..."` /
  `<tag className="..."` for tag+class combos.
- Wrapper builder emits `style={{ display: "contents" }}` when
  commentSyntax is JSX and `style="display: contents"` otherwise.
- findClosingLine uses the same OPENER_RE so its tag-name extraction
  works on multi-line openers too.

## Tests

Five new regression tests in tests/live-wrap.test.mjs, all failing
before the fix, all passing after:

- wraps the correct <section> when a class collides with a multi-line
  tag elsewhere
- emits JSX-safe style attribute ({{ }}) in .tsx files
- finds elements via className= (React) when the exact class combo is
  unique there
- respects --tag to reject matches inside the wrong element type
- findClosingLine recognises an opener line where the tag sits at
  end-of-line (multi-line JSX)

31/31 in tests/live-wrap.test.mjs and 54/54 in
tests/framework-fixtures.test.mjs pass.

Credit: precise bug report from the other agent in the EAC session
made diagnosis and test design straightforward.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:19:32 -07:00
Paul BakausandClaude Opus 4.7 67e468f84c fix(cleanup): authoritative lock signal + fingerprint fallback for orphan dirs
The content heuristic for deciding whether a deprecated skill dir belongs
to us returned false for harden and optimize (their v2.x SKILL.md never
said "impeccable"), while lock-entry cleanup used the authoritative
source field. Result: lock entries purged, dirs orphaned.

Layer three signals now: lock source (authoritative), word heuristic,
then per-skill description fingerprints for the two stock v2.x skills
that predate the self-identification convention.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:54:29 -07:00
Paul BakausandClaude Opus 4.7 05b0ac3e1f feat(live): extend CSP detection to SvelteKit and Nuxt
Shape names renamed to describe the patch mechanism (what the agent does)
rather than the origin (where the CSP lives). One template now covers
multiple frameworks.

## Shape rename

- shared-helper   → append-arrays
- inline-headers  → append-string

append-arrays applies wherever CSP is a structured directive array.
append-string applies wherever CSP is a literal value string.

## New detection coverage

- SvelteKit kit.csp.directives in svelte.config.js → append-arrays
- Nuxt routeRules / nitro.routeRules CSP header → append-string
- Nuxt-security module's contentSecurityPolicy → append-arrays

## New fixtures

- sveltekit-csp/: SvelteKit config with kit.csp.directives. Includes
  expected-after-patch.js showing the array spread.
- nuxt-csp/: Nuxt 3 config with routeRules CSP. Includes
  expected-after-patch.ts showing the string splice.

## Skill docs

Single append-arrays template covers Next monorepo, SvelteKit, and
Nuxt-security. Single append-string template covers inline Next
headers() and Nuxt routeRules. Per-framework specifics listed as
sub-bullets under each shape.

54 tests across 9 fixtures, all passing. Clean fixtures (plain vite,
nextjs-app, astro, sveltekit, multipage-with-generator) still classify
as shape: null.

Astro and Vue (non-Nuxt) left unhandled by design: Astro has no
first-party CSP mechanism; Vue without Nuxt is covered by the existing
Vite fixture. Plain Svelte has no framework CSP primitive and inherits
from its bundler (Vite/Rollup).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:47:43 -07:00
Paul BakausandClaude Opus 4.7 d5480caee3 feat(live): CSP detection + consent-gated patch flow at first-time setup
Real-world tests (EAC Next turborepo) confirmed that CSP is the common
blocker for live mode. Adds setup-time detection with a one-time user
consent flow — the patch becomes a permanent, dev-guarded entry in the
user's own config, not a transient add/remove.

## Changes

- New detect-csp.mjs helper: grep-based classifier returning
  { shape, signals }. Shape is one of:
    - "shared-helper" (monorepo CSP helper with additional*Src arrays)
    - "inline-headers" (literal CSP string in headers())
    - "middleware" (response.headers.set in middleware.ts; detect-only v1)
    - "meta-tag" (<meta http-equiv>; detect-only v1)
    - null (no CSP)
  Max depth 6, skips node_modules / build / cache dirs, 64KB per file.

- cspChecked boolean on config.json. First-run setup runs detection;
  subsequent runs skip. Users re-trigger by deleting the flag.
  Validator accepts it.

- Skill live.md gains:
    - CSP detection step in first-time setup (gated by cspChecked)
    - Consent-prompt template (so every agent phrases it the same way)
    - Shape 1 patch template: append `...__impeccableLiveDev` to
      additionalScriptSrc/additionalConnectSrc in the app's config
    - Shape 2 patch template: two-point edit — declare a dev-only
      variable, interpolate into script-src and connect-src in the
      CSP literal string
    - Troubleshooting note for "said no but now live doesn't work"

## Fixtures

- nextjs-turborepo/: Turborepo shape (shared CSP helper with
  additionalScriptSrc options). Sanitized from a real monorepo so the
  patch mechanics get tested against realistic layering. Includes
  expected-after-patch.ts for human/agent review.

- nextjs-inline-csp/: app-level next.config.js with a literal CSP
  string. Includes expected-after-patch.js showing the Shape 2 edit.

## Tests

Framework-fixture harness extended with a detect-csp shape-classification
assertion per fixture. 42 tests across 7 fixtures pass. Clean fixtures
(vite-react, nextjs-app, astro, sveltekit, multipage-with-generator)
correctly return shape: null.

## Deliberately not doing

- No patches[] array, no marker-based rollback, no add/remove lifecycle.
  The patch is a permanent dev-guarded config line — the same kind of
  edit a user would make themselves.
- No base URL rewriting or proxy mechanism. Script tag still points at
  localhost:8400; CSP permits it once patched. No browser-side changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:41:11 -07:00
Paul BakausandClaude Opus 4.7 c9c152f0f0 test(live): framework fixture matrix for inject / wrap / is-generated
Five representative project shapes under tests/framework-fixtures/ that
stage into fresh tmp git repos and drive the live scripts against each:

- vite-react: tracked index.html shell + src/App.jsx
- nextjs-app: app/layout.tsx as JSX inject target
- astro: src/layouts/Layout.astro
- sveltekit: src/app.html shell + src/routes/+page.svelte
- multipage-with-generator: src/ tracked, dist/ gitignored (our own
  repo's shape); exercises the is-generated guard and
  element_not_in_source fallback

Each fixture declares its config, expected source/generated paths, and
wrap cases in fixture.json. The harness copies into tmpdir, applies
gitignore, commits, then asserts:

- inject --port lands the script tag at the correct anchor across all
  configured files
- inject --remove strips it cleanly
- is-generated classifies source vs generated paths correctly
- wrap routes to the expected source file or emits the expected
  fallback error

Plumbing + bug caught while building out the matrix:

- IMPECCABLE_LIVE_CONFIG env var so tests can point live-inject at a
  fixture-specific config.json without clobbering the harness copy.
  Backwards-compatible.
- live-wrap.mjs no longer hardcodes dist/build in its directory skip
  list. Only node_modules and .git remain universal skips; the
  isGeneratedFile check is now the sole guard for generated paths. This
  lets the includeGenerated second pass find elements in dist/ and
  report generatedMatch, which is what the multipage-with-generator
  fixture needs to exercise.

Wired into bun run test. 25 tests, 5 suites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 22:42:28 -07:00
Paul BakausandClaude Opus 4.7 37b8e8ba33 fix(live): multi-file inject, generated-file protection, and accept-flow correctness
Addresses every issue surfaced during hands-on live-mode testing.

## Injection across multi-page sites

- Config schema: `file` → `files: string[]` so multi-page static sites can
  opt into script-tag injection across every HTML entry the browser loads.
- `live-inject.mjs` loops the array, reports per-file results, and
  refuses silently with `config_invalid` if the schema is stale.
- `insertBefore` switched from first-match to last-match (lastIndexOf)
  so the anchor lands at the true close of `</body>`, not the first one
  embedded inside a `<pre><code>` documentation sample.

## Source-vs-generated detection

- New `is-generated.mjs` helper: gitignore check + generated-header
  markers. Edge-case `generatedFiles` config dropped — the two real
  signals cover every project shape we tested.
- `live-wrap.mjs` excludes generated files from auto-search and returns
  clear fallback errors: `file_is_generated`, `element_not_in_source`
  (with `generatedMatch` path), and `element_not_found`.
- `live-accept.mjs` refuses to persist into generated files; returns
  `mode: "fallback"` so the agent takes over via the Handle fallback
  flow.

## Accept correctness

- `extractVariant` / `extractOriginal` now skip `<style>` regions when
  matching markers. Previous regex substring match treated
  `@scope ([data-impeccable-variant="N"])` in CSS as the target HTML
  div, capturing garbage and producing orphan CSS that rendered as
  prose on the page.
- On accept, the chosen variant's content is wrapped in
  `<div data-impeccable-variant="N" style="display: contents">` so the
  carbonize block's `@scope` selectors keep matching. Users see the
  accepted design immediately; no pre-carbonize dead state.

## Browser-side UI

- `positionBar` gains a third case: when the selected element is taller
  than the viewport, pin the bar to a stable viewport anchor instead of
  teleporting between top and bottom as the user scrolls.
- No-HMR source-fetch path (`injectVariantsFromSource`) now calls
  `hideShaderOverlay()` on state transition to CYCLING. Previously the
  shader kept running after variants arrived via the fetch fallback.
- `pickVariantContent` helper replaces fragile `> :first-child`
  selection for outline positioning. Skips non-visual tags (style,
  script, link, meta, template) and falls back to the variant div
  itself when a variant contains multiple visual children.
- `resumeSession` re-captures and restarts the shader overlay when
  the page reloads mid-generation (Bun HTML HMR does a full reload
  and destroys the canvas).
- MutationObserver re-anchors `selectedElement` when the original
  element is detached by HMR, preventing zero-rect highlight drift.

## Skill docs

- `live.md` reframes `config.files` as "the HTML files the browser
  actually loads" and documents the regen-wipes-inject caveat for
  multi-page generator projects.
- New Handle fallback section covers the three wrap error shapes and
  how the agent should manually wrap for preview and commit to real
  source on accept.
- Handle accept documents the new `data-impeccable-variant` wrapper
  and the carbonize agent's duty to strip it.

## Prefetch feature (landed but disabled)

A `prefetch` event fires from the browser on first CONFIGURING per
route so the agent can pre-Read the source file before Go. Real latency
win in the linger-before-Go case but costs a harness round trip when
Go fires quickly. Disabled via a `PREFETCH_ENABLED = false` flag in
`live-browser.js`; server validator and skill dispatch stay so re-
enabling (with a browser-side debounce) is a one-line change.

## Harness guidance

Earlier skill rewrite compressed two load-bearing instructions:
- Restored prescriptive wording for "open the tab via Chrome MCP
  before the first poll" and the Claude Code background-poll policy.
- Flag-mapping for `live-wrap` rewritten as explicit bullets so models
  don't collapse `--element-id`/`--classes`/`--tag` into a single
  `--query` argument.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 22:30:27 -07:00
Paul BakausandClaude Opus 4.7 e2279ddab1 fix(live): restart shader and re-anchor selection on HMR page reload
Bun's HTML HMR does a full page reload when the live-wrap.mjs edit
lands, so the shader canvas is destroyed and in-memory capture blob is
lost. resumeSession rehydrated state from localStorage but never
restarted the overlay, so the wait went dead.

resumeSession now re-captures the original's content (still in the DOM
inside the variant wrapper) and restarts showShaderOverlay when we
reload mid-generation. Also swaps the two remaining :first-child
selectors in resumeSession for pickVariantContent so the earlier
loose-children robustness fix carries across reloads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 15:45:46 -07:00
Paul BakausandClaude Opus 4.7 9ccb240dc7 fix(live): variant outline accuracy and shader re-anchor after wrap
Two regressions surfaced in smoke testing, both traceable to state
drift when live-wrap.mjs rewrites the source file and HMR swaps the
DOM.

1. Variant outline on the wrong element. The skill rewrite lost the
   explicit "each variant must be a complete element replacement"
   rule and dropped the "full element replacement" comments from
   variants 2 and 3. Models started producing variants with loose
   sibling children, so live-browser's :first-child selector framed
   only the first sibling. Restored the rule, made all three comments
   consistent, and replaced :first-child with pickVariantContent —
   which skips non-visual tags (style/script/link/meta/template) and
   falls back to the variant div itself when a model still ships
   multiple visual children.

2. Loading shader freezes after wrap. The MutationObserver only woke
   up when new non-original variants arrived, so when the wrapper
   first appeared via HMR with just the original inside, selectedElement
   was left dangling on the now-detached pre-wrap node. Scroll-tracking
   read a zero rect on every frame and collapsed the shader canvas to
   0x0. The observer now re-anchors selectedElement to the original's
   content the moment the wrapper shows up, keeping overlays positioned
   until real variants land.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 15:30:09 -07:00
Paul BakausandClaude Opus 4.7 62e5b2bb92 fix(live): restore prescriptive browser-open and background-poll guidance
The skill rewrite compressed two load-bearing instructions into ambient
context:

- "Navigate the browser to the URL" lost the signal that models with
  Chrome MCP should proactively open the tab before the first poll.
  Restored the forcing phrasing and the "before the first poll" anchor.
- "Claude Code can background the poll" read as permission rather than
  prescription. Models fell back to foreground blocking by default.
  Restructured harness guidance as a bulleted policy, prescriptive per
  harness, with the reason attached (harness notifies on completion so
  the conversation stays free).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 14:46:18 -07:00
Paul BakausandClaude Opus 4.7 4daabe5232 feat(skill): register split, color strategy, and pre-design intake
Splits the skill into two register references (editorial, product),
replaces category-based theme selection with a forced physical-scene
inference, and introduces a four-step color strategy axis (Restrained /
Committed / Full palette / Drenched) with editorial permission for the
bold three.

Adds a seed mode to /impeccable document for pre-implementation
projects, updates /impeccable teach Step 5 to offer the seed path, and
grows /impeccable shape with Design Direction + Scope intake
(fidelity, breadth, interactivity, time). Extends live-mode variant
distinctness to forbid three variants sharing theme and dominant hue.

Also drops the anti-pattern validator coupling, consolidates a11y into
audit.md, and updates CLAUDE.md with the register architecture.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 14:13:29 -07:00
Paul BakausandClaude Opus 4.7 81f880d030 feat(live): annotation capture, comment pins, drawing, and halftone loading shader
Adds a full annotation pipeline to /impeccable live. On Go, the browser
captures the selected element as a PNG (with annotations composed in),
uploads it to the live helper, and sends the generate event with the
screenshot path so the agent reads user intent visually instead of from
HTML alone.

Annotation tools (while an element is picked):
- Click inside the outline to drop a magenta comment pin with a text input
- Drag to paint a magenta SVG stroke (5 px click-vs-drag threshold)
- Click a pin to edit; double-click to delete; drag a pin to reposition
- Click a stroke to delete it (wider invisible hit path)
- Clear chip top-right wipes everything; hidden when no annotations

Capture pipeline:
- modern-screenshot vendored as an IIFE (scripts/modern-screenshot.umd.js)
  and lazy-loaded from the live helper
- Font fix: cross-origin @font-face rules are fetched and fonts are inlined
  as base64 data URIs before being handed to modern-screenshot via
  font.cssText, since SVGs rasterized via canvas can't fetch external
  resources (fix for "Impeccable" rendering bold-serif and items wrapping
  wrong in the capture)
- Annotations are temporarily attached to the live element (not only the
  clone) so computed styles resolve during the embed pass
- Session screenshots live in .impeccable-live/annotations/session-*/ in
  the project root (gitignored) so the agent's Read tool doesn't trip a
  per-path permission prompt

Loading shader (activates during GENERATING):
- WebGL overlay rendering the captured PNG as a halftone — cells with
  luma-driven dot radius, rendered on paper-cream underneath a magenta
  roller that sweeps top-to-bottom with a 3.4s cycle and clean overshoot
- Fixed asymmetric bandAt() using one-sided smoothsteps (previous reversed
  smoothstep was undefined on d>0, giving "trail=1 everywhere below")
- Graceful <img> fallback when WebGL is unavailable; prefers-reduced-motion
  freezes the band at t=0

Server:
- POST /annotation endpoint (raw image/png body, token + eventId query),
  session-scoped tmpdir cleaned up on shutdown
- GET /modern-screenshot.js serves the vendored UMD with aggressive caching
- Optional screenshotPath / comments / strokes fields on generate events
- Fixed pre-existing /source crash on ENOENT (writeHead called twice)

Agent side:
- reference/live.md step 0 tells the agent to Read the screenshot first,
  with four rules for interpreting annotations: comments are position-
  anchored and scoped to the sub-element under their {x,y}; strokes are
  gestures (loop=focus, arrow=direction, cross=delete); comments and
  strokes are independent unless adjacent; don't silently guess on
  ambiguous strokes

Also:
- Generating bar no longer claims "Generating 1 of 3..." (variants arrive
  atomically) — now says "Generating N variants..."
- tests/live-server.test.mjs fixed to read the PID file from project root,
  matching the server; adds coverage for the new endpoints and validator
  fields
- .impeccable-live/ added to .gitignore

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 09:38:48 -07:00
Paul Bakaus 51d28cf1eb smooth detect outline transitions 2026-04-20 13:13:59 -07:00
Paul Bakaus 66630a0ead chore: sync skills, live tooling, and eval ignores
- Ship design-parser and refreshed live scripts/document refs across provider
  skill trees; align live.mjs and live-poll with source
- Update build/skills harness metadata, skills CLI test, and devDependencies
  (AI SDKs, zod)
- Gitignore .codex/ harness artifacts and tests/evals-v2/

Made-with: Cursor
2026-04-17 18:04:45 -07:00
Paul Bakaus 90cddb4f3c feat(live): remove injected script when stopping live server
live-server.mjs stop now runs live-inject.mjs --remove after the HTTP
server shuts down, so HTML entries do not keep loading a dead localhost
live.js URL. Add stop --keep-inject to stop only the helper.

Update reference/live.md cleanup steps and sync all provider skill copies.

Made-with: Cursor
2026-04-17 18:02:53 -07:00
Paul Bakaus 0c90533055 docs(skill): clarify live-poll foreground vs background for Cursor and Claude Code
Document that Cursor Composer should run live-poll blocking in the same turn
(with a link to Cursor subagent foreground vs background docs). Claude Code may
use a background poll when the harness surfaces completion. Sync reference to
all provider skill bundles.

Made-with: Cursor
2026-04-17 17:08:11 -07:00
Paul BakausandClaude Opus 4.6 0b4bc377f2 Polish live-mode bar and DESIGN.md panel
Global bar is now a single compact unit: Pick → Detect → DESIGN.md
with the Impeccable brand mark as a full-height slab on the left.
Labels are icon-only at rest and expand as a group when the bar is
hovered, so moving the cursor across buttons no longer triggers
per-button layout thrashing. Button styling flips automatically based
on the page's ambient luminance — dark bar on light pages, light bar
on dark pages — so the bar doesn't fight with the host design.

The DESIGN.md panel chrome now matches the bar (same surface, hairline,
mono filename title) while the body canvas stays neutral so tile colors
and rendered component primitives look true. The separate floating
"Design" FAB is gone; the panel toggle lives in the bar. Panel always
starts closed; only the tab and collapsed-section preferences persist.

Other fixes: toggling pick off now clears the selection + hides the
contextual bar and action picker. PRODUCT.md presence is the signal
for "project context loaded" for variant generation (DESIGN.md lives
under its own empty-state in the panel). The live-poll client sets a
global undici dispatcher with no headers/body timeouts so one poll can
sit open indefinitely — fixes the silent "fetch failed" that killed
polls at the 5-minute mark.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 15:01:17 -07:00
Paul BakausandClaude Opus 4.6 fcb347b9b5 Add design system panel to /impeccable live
The live-mode float-bar now includes a "Design" toggle that slides a
panel in from the right. Tile-based layout (neutral canvas, one level
of hierarchy, no nested cards) with color swatches and tonal ramps,
typography specimens, corner radii, shadow previews, and *live
component primitives* rendered from the project's real tokens.
Collapsible Named Rules / Do's-and-Don'ts / Overview hold the
narrative context without crowding the tiles.

The /impeccable document command now writes a DESIGN.json sidecar
alongside DESIGN.md. The sidecar carries structured tokens plus
self-contained HTML+CSS snippets per component — this is what lets
the panel render each project's actual button/input/nav instead of
generic approximations. The document spec documents the translation
rules for Tailwind, CSS-in-JS, shadcn, and framework components.

The live server exposes /design-system.json and /design-system/raw.
If DESIGN.json is missing but DESIGN.md is present, the panel falls
back to a limited "basic view" parsed from the markdown and prompts
the user to run /impeccable document for the full visualization. A
stale hint appears when DESIGN.md has been edited after DESIGN.json.

Includes a hand-authored DESIGN.json for this project so the panel
has something to render against out of the box, and a deterministic
DESIGN.md parser (design-parser.mjs) as the fallback source.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 12:11:10 -07:00
Paul BakausandClaude Opus 4.6 50dfeef39f Tighten typography.md; remove reference/pin.md
typography.md had a parallel 4-step font-selection procedure and a smaller
banned-fonts list (5 fonts: Inter, Roboto, Open Sans, Lato, Montserrat)
that duplicated SKILL.md's authoritative <font_selection_procedure> with
its 23-font list. Removed the duplicate procedure and deferred to SKILL.md
for the banned list. Kept the unique material: anti-reflex corrections,
system-font note, pairing principles, web font loading, OpenType, fluid
type guidance, accessibility — and all of the scale/rhythm/measure
content that SKILL.md doesn't cover.

pin.md removed for the same reason as context.md: SKILL.md's inlined
pin section already covers what an agent needs (what pin does, usage,
valid commands, how to report back). No value in the indirection.

SKILL.md: 386 → 388 lines (slight growth from inlining pin details)
typography.md: 142 → 132 lines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 10:56:07 -07:00
Paul BakausandClaude Opus 4.6 2c1d2a5a54 Remove reference/context.md; SKILL.md already covers the protocol
The main skill now has enough detail to stand alone: two files, load
command, no-truncate rule, never-infer warning, session cache, teach
fallback, DESIGN.md nudge, and the live-mode "already warmed"
exception. context.md was indirection without added value.

Inlined the two bits from context.md worth keeping:
- Content validity: treat empty / <200 chars / [TODO]-placeholder
  PRODUCT.md as missing
- live.mjs auto-warms, don't double-load with load-context.mjs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 10:53:00 -07:00
Paul BakausandClaude Opus 4.6 473dbd52ef Trim SKILL.md plumbing; extract context + pin protocols to references
Before: 422 lines. After: 386 lines. The cut is conservative because
evals/AGENT.md revealed that most of what looked like bloat is actually
load-bearing: the font_selection_procedure with its 23-font ban list
(lesson 6), the theme_selection with audience examples (lesson 9), and
the absolute_bans with literal CSS patterns (lesson 7) all drive
measurable eval improvements and must stay inline.

What moved out of SKILL.md:
- Context Gathering Protocol (52 → ~18 lines). The full protocol — cache
  semantics, dispatch tree, teach/document/live exceptions, why-it-matters
  — moved to reference/context.md. SKILL.md keeps only the compact hook:
  load command, "never infer from codebase" warning, and pointer.
- Pin/Unpin (14 → 6 lines). Details moved to reference/pin.md.
- Spatial principles: dropped 4pt-vs-8pt rationale, gap-vs-margins CSS
  technicality, and container-queries-vs-viewport explanation (not
  load-bearing in the main skill). Kept all load-bearing rules
  including the 80-char body-text line (detector-backed).

What did NOT move (load-bearing per evals):
- <font_selection_procedure> with the 23-font ban list
- <theme_selection> with the 8 audience examples
- <absolute_bans> with literal CSS patterns
- All XML tag structure (lesson 8: XML works better than markdown
  for reasoning models, especially OpenAI)

Also added:
- reference/context.md (new) — full context protocol
- reference/pin.md (new) — full pin/unpin docs
- "Never infer brand, audience, or tone from the codebase" warning
  restored to SKILL.md (was dropped in an earlier refactor)

Fixed:
- reference/colorize.md had "Accent borders: Add colored left/top
  borders to cards or sections" which directly contradicted
  SKILL.md's absolute_ban on border-left/right > 1px. Rewrote the
  accent-border advice to use hairline borders, surface tints, or
  leading glyphs instead, with an explicit reference to the ban.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 10:02:19 -07:00
Paul BakausandClaude Opus 4.6 268a5e15cc Clarify context gathering protocol: session cache, no truncation, exceptions
Two observed failure modes:
1. Smoke-test style truncation (`| head -N`) in bash commands defeats the
   whole point of load-context.mjs — Claude needs the FULL file contents,
   not the first few lines of JSON.
2. The old protocol didn't clearly explain session caching, leading to
   repeated load-context.mjs calls across commands in the same session
   (thousands of wasted tokens on 3-5KB files re-fetched 3-5 times).

Context Gathering Protocol rewrite:
- PRODUCT.md required (blocker), DESIGN.md optional (one-line nudge if
  missing). Greenfield projects can't yet have a DESIGN.md to document.
- Explicit session cache: if content is in conversation history, do not
  re-fetch. Exceptions listed (after teach/document/manual edit).
- Explicit "never truncate" rule: consume the full load-context.mjs
  output, never pipe through head/tail/grep/jq with field filters.
- Content validity check: hasProduct=true but content <200 chars or
  full of [TODO] markers = treat as missing, run teach.
- Missing-PRODUCT.md flow spells out task resumption: user asked for
  /impeccable polish ButtonGroup, we must run teach, then RESUME polish
  of ButtonGroup with fresh context — not silently abandon intent.
- Three explicit exceptions to the protocol:
  - /impeccable teach skips it (teach creates PRODUCT.md)
  - /impeccable document loads PRODUCT.md only (creates DESIGN.md)
  - /impeccable live already warms context via live.mjs — don't also
    run load-context.mjs

teach.md Step 6 and document.md Step 5 now re-run load-context.mjs at
the end so the freshly-written files surface in conversation history
and subsequent commands use the new version, not a stale earlier read.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 08:54:38 -07:00
Paul BakausandClaude Opus 4.6 1ebe204b1b Align DESIGN.md format with official Google Stitch spec
The format at https://stitch.withgoogle.com/docs/design-md/format/ defines
exactly six sections in a fixed order: Overview, Colors, Typography,
Elevation, Components, Do's and Don'ts. Our previous format used
non-compliant names (Visual Theme & Atmosphere, Color Palette & Roles,
Typography Rules, Component Stylings), a non-existent "Layout Principles"
section, and had no Do's and Don'ts.

Changes to reference/document.md:
- Fixed section list to match the spec character-for-character
- Added mandatory "Creative North Star" pattern at top of Overview
- Added Named Rules pattern (e.g. "The No-Line Rule") — stickier than
  bullet lists for AI consumers, mirrors Stitch's own generator output
- Added explicit Do's and Don'ts section with concrete, forceful guardrails
- Elevation is now its own section (was buried in Components)
- Layout/motion/responsive content folds into Overview + Components
  rather than inventing new top-level sections
- Guidance on forceful voice ("prohibited"/"forbidden"/"never") matching
  PRODUCT.md's expert-decisive tone
- Pitfalls section warns against renaming sections or adding new ones

Changes to our DESIGN.md:
- Rewrote to use spec-compliant section headers with evocative subtitles
  (e.g. "## 2. Colors: The Warm-Paper Palette")
- Opened with "Creative North Star: The Editorial Sanctuary"
- Added 11 Named Rules across sections (The One Voice Rule, The Paper-
  Not-White Rule, The OKLCH-Only Rule, The Italic-Is-Voice Rule,
  The 1.6 Leading Rule, The Fluid-Headlines-Only Rule, The Flat-By-
  Default Rule, The Low-Alpha Rule, The Tinted-Shadow-Only-For-Accent
  Rule, plus the existing implicit ones)
- Full Do's and Don'ts section with 10 Dos and 15 Don'ts, many of which
  translate PRODUCT.md anti-references into concrete prohibitions
- Elevation section documents shadow vocabulary separately from Components
- Layout/spacing/motion content relocated to a sub-section under Components

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 19:08:27 -07:00
Paul BakausandClaude Opus 4.6 af2d6e1194 Support PRODUCT.md + DESIGN.md as canonical context files
Pioneers a two-file convention for project context:
- PRODUCT.md (strategic): users, brand, principles — answers who/what/why
- DESIGN.md (visual): follows Google's Stitch DESIGN.md spec — answers how-it-looks

Both files live at the repo root. Filename matching is case-insensitive.
DESIGN.md wins on visual conflicts, PRODUCT.md wins on strategic/voice.

Legacy .impeccable.md is auto-migrated to PRODUCT.md on first read by the
new shared loader. This is silent and one-shot — the rename is permanent.

What changed:
- New scripts/load-context.mjs: shared context loader used by every command
  that needs project context. Reads both files, handles legacy migration.
- New reference/document.md: /impeccable document command that generates
  DESIGN.md by auto-extracting tokens (colors, typography, spacing, radii,
  shadows, components) from CSS/Tailwind/theme files, then asking the user
  to confirm descriptive language for atmosphere and color character.
  Follows Google's Stitch DESIGN.md format for tool compatibility.
- SKILL.md Context Gathering Protocol updated to load both files and
  nudge the user to run /impeccable document when DESIGN.md is missing.
- reference/teach.md rewritten to split discovery cleanly: strategic
  questions go to PRODUCT.md, visual/design-system work is delegated to
  /impeccable document (skipped on empty projects).
- reference/live.md consumes {product, design, productPath, designPath,
  migrated} from the loader instead of a single context blob.
- scripts/live.mjs uses the shared loader instead of inline file reading.
- Command count updated 22 → 23 (new: document). Metadata, router table,
  command menu, periodic table viz, and homepage data all updated.
- .gitignore adds PRODUCT.md + DESIGN.md (repo-local, not shared).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 18:14:13 -07:00
Paul BakausandClaude Opus 4.6 f339796b2b Extend action-specific diversity rules to all live actions
Previously only bolder/quieter/animate/colorize/typeset/layout had
variant diversity rules. Added the same level of guidance for distill,
polish, adapt, delight, and overdrive so every live action has a
clear "each variant must differ on THIS axis" rule.

Also noted that overdrive should skip its reference's "propose and ask"
step in live mode (it's non-interactive — the user picks from variants).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 17:09:31 -07:00
Paul BakausandClaude Opus 4.6 7386b3033f Force variant diversity and mandatory reference loading in live mode
Two failure modes observed:
1. Claude generates N near-identical variants (small shade/size tweaks)
   instead of meaningfully different design directions
2. When a sub-command like /bolder is chosen in the picker, Claude skips
   loading reference/bolder.md and generates generic variants

Fixes:
- "Load reference file" is now a MANDATORY Step 2a, separate and
  non-negotiable, called out as a critical failure to skip
- Added Step 2b "Plan 3+ distinctly different directions" with 7
  structural axes variants must differ on (hierarchy, layout topology,
  typography system, color strategy, density, tone, decomposition)
- Added action-specific diversity rules (bolder = different dimensions,
  animate = different motion vocabulary, colorize = different hues, etc.)
- Freeform prompt guidance: honor the prompt direction but explore
  meaningfully different interpretations, not three near-copies

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 17:07:23 -07:00
Paul BakausandClaude Opus 4.6 996c9af78c Add live.mjs combined entry point for fast startup
Previously, starting live mode required ~5-6 sequential bash calls:
read .impeccable.md, start server, check config, read reference, inject
tag, verify. The new live.mjs does all of this in a single command
(~340ms cold, ~90ms when reusing a running server) and returns everything
the agent needs in one JSON blob.

Workflow is now:
  1. node live.mjs        # start + inject + load context (1 bash call)
  2. navigate browser     # optional MCP call
  3. node live-poll.mjs   # enter poll loop

Reference doc collapsed to a single "Start Live Mode" section with the
one-command path plus a first-time config creation fallback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:56:20 -07:00
Paul BakausandClaude Opus 4.6 8030bc226a Add live-inject.mjs: per-project config for instant script tag management
First live run: agent auto-detects framework and writes a small config.json
(file, insertBefore/insertAfter anchor, comment syntax). Every subsequent
run: live-inject.mjs handles insert/remove deterministically, no LLM needed.

The config lives at {scripts_path}/config.json and is gitignored — it's a
per-project cache that wipes on skill update and regenerates on next use.

- New live-inject.mjs: --port (insert), --remove, --check modes
- Idempotent insert: re-running with a different port replaces cleanly
- Reference doc: one-time detection step, then instant insert/remove

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:44:26 -07:00
Paul BakausandClaude Opus 4.6 f397b9f123 Fix keyboard nav and click-to-deselect in live mode picker
- Arrow keys now pass through to element picker when the freeform input
  is empty, instead of being swallowed by stopPropagation
- Arrow nav works in both PICKING and CONFIGURING states, so you can
  change your element selection while the config bar is open
- Clicking outside the selected element and bar returns to PICKING mode,
  matching the expected deselect behavior

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:31:03 -07:00
Paul BakausandClaude Opus 4.6 830fe8e5fc Instant accept/discard for live mode, SSE heartbeats, background server startup
Accept and discard in live variant mode are now handled by a deterministic
script (live-accept.mjs) that runs inside the poller before returning to
the agent. The browser updates the DOM instantly on click (fire-and-forget)
so the user is never blocked waiting for LLM-driven file cleanup.

Key changes:
- New live-accept.mjs: deterministic accept/discard file operations
- Poller auto-runs accept script for accept/discard events (_acceptResult)
- Browser handleAccept() now commits DOM change instantly, no SAVING state
- CSS+HTML colocated in one write (style tag inside variant wrapper)
- SSE heartbeat every 30s prevents silent connection drops
- Poll timeout increased from 2min to 10min
- EventSource onopen resets retry counter for reliable reconnection
- Server --background flag for clean single-command startup

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:06:03 -07:00
Paul BakausandClaude Opus 4.6 9b573de1fb Add ADR for live variant mode architecture
Comprehensive architecture decision record covering the live variant
mode: context, key decisions (source modification over DOM patching,
SSE over WebSocket, self-contained skill scripts, HTTP long-poll for
agent), full architecture diagram with message flows, variant wrapper
format, browser UI states, session persistence, security model,
server resilience, performance optimizations, test coverage, known
limitations, and future work.

Also picks up improvements from parallel thread: poll timeout bumped
to 10 min, SSE heartbeat every 30s, and other minor fixes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:16:07 -07:00
Paul BakausandClaude Opus 4.6 4092ee5f22 Move PID file to project root (.impeccable-live.json)
os.tmpdir() returns /var/folders/.../T/ on macOS, not /tmp/. The skill
reference was telling the agent to cat /tmp/impeccable-live.json which
didn't exist. Moving the PID file to the project root makes it
predictable across platforms and project-scoped (multiple projects can
run independent live sessions).

Changed in: live-server.mjs, live-poll.mjs, live.md reference.
Added .impeccable-live.json to .gitignore.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 12:32:42 -07:00
Paul BakausandClaude Opus 4.6 4b52756edd Fix live server startup: read port/token from PID file after background start
The server is started with & (backgrounded), so its stdout output isn't
captured by the agent's Bash tool. The skill reference now tells the
agent to sleep 2s then cat the PID file (/tmp/impeccable-live.json) to
get the port and token. The PID file is written by the server as soon
as it starts listening.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:37:45 -07:00
Paul BakausandClaude Opus 4.6 0a1e5614e9 Add global floating bar with detect/pick toggles
Compact floating pill at the bottom center of the viewport, always
visible during live mode. Matches the action bar's light, translucent
aesthetic with brand-tinted active states.

Controls:
- "Impeccable" brand mark (capitalized, brand magenta)
- Detect toggle: eye icon, loads anti-pattern scanner in extension mode,
  waits for impeccable-ready before first scan, shows issue count badge
  inside the button. Toggle off removes overlays.
- Pick toggle: crosshair icon, enables/disables element picker. Active
  by default. When pick is active, detect overlays get pointer-events:
  none so the picker sees through them.
- Exit button: sends exit event and tears down all UI.

Detect + pick coexistence fixes:
- Picker highlight z-index raised above detect overlays (100001 vs 99999)
  so the selection outline and element path are always visible.
- Removed layout-property transitions (top/left/width/height) from the
  highlight to avoid triggering the anti-pattern detector and to give
  instant cursor tracking.
- First-click-on-detect fix: script loads async, scan command is queued
  until the impeccable-ready postMessage arrives.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:35:48 -07:00
Paul BakausandClaude Opus 4.6 52b050bb7e Fix 5 bugs from real-world live mode testing
1. Skill reference: poll should run as background task with no timeout.
   Changed "blocking poll loop" to "background task, no timeout" so the
   agent keeps the main conversation free for other work.

2. Resume restores selectedAction from localStorage: the bar was showing
   "Freeform" after page reload even when the user picked "Bolder". Also
   improved selectedElement targeting to prefer the visible variant's
   content over the wrapper parent.

3. Discard no longer shows "Applying variant...": accept shows the
   saving→confirmed flow, but discard now dismisses immediately and
   cleans up the DOM. Different intent, different UX.

4. Picker works after discard: cleanup() now removes the variant wrapper
   from the live DOM and restores the original element. Previously the
   stale wrapper with data-impeccable-variant attributes confused the
   picker's isPickable/own checks.

5. Stop live mode: added "Stopping Live Mode" section to the skill
   reference. The user can say "stop live mode" in the conversation, and
   the agent proceeds to cleanup (remove script tag, stop server).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:04:31 -07:00
Paul BakausandClaude Opus 4.6 e4d1d96926 Auto-generate argument hint with all commands grouped by category
The static "[command] [target]" hint didn't help users discover available
commands. The build now reads command-metadata.json and groups commands
by category (from SKILL_CATEGORIES) with middle-dot separators for
natural line-breaking in the prompt bar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 09:22:09 -07:00
Paul BakausandClaude Opus 4.6 455fe39155 Add 41 tests for live-wrap and live-server, add auto-execute guards
Tests:
- tests/live-wrap.test.mjs (26 tests): unit tests for buildSearchQueries,
  findElement, findClosingLine, detectCommentSyntax (20 pure function
  tests) + integration tests for the full wrapCli on HTML and JSX
  fixtures with temp dirs (6 tests covering wrapping, ID/class lookup,
  error handling, content preservation).

- tests/live-server.test.mjs (15 tests): integration tests that start a
  real server on port 8499, then test /health, /live.js, /detect.js,
  /poll (timeout + auth), /events POST (validation + auth), browser→agent
  event flow (POST event → poll receives it), agent→browser SSE flow
  (POST reply → SSE stream delivers it), /source (read, path traversal
  rejection, auth, 404).

Also:
- Added auto-execute guards to live-wrap.mjs and live-poll.mjs so they
  work when run directly with `node live-wrap.mjs ...` (needed for both
  skill instructions and integration tests).
- Exported buildSearchQueries, findElement, findClosingLine,
  detectCommentSyntax from live-wrap.mjs for unit testing.
- Updated package.json test script to include the new test files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 19:35:26 -07:00
Paul BakausandClaude Opus 4.6 7011a523e0 Remove live commands from CLI, delete src/live, add server-lost cleanup
1. CLI cleanup: removed live, poll, and wrap commands from bin/cli.js
   and the liveCli export from detect-antipatterns.mjs. These now live
   exclusively in the skill scripts (node scripts_path/live-server.mjs).

2. Deleted src/live/: server.mjs, poll.mjs, wrap.mjs, browser.js,
   protocol.mjs. The source of truth is now source/skills/impeccable/
   scripts/live-*.

3. Graceful server-lost handling: the browser tracks SSE reconnection
   attempts (max 5). After exhausting retries, it cleans up the UI:
   hides the bar, highlight, and cycler, shows a "Live server
   disconnected" toast, resets state to IDLE. This handles agent
   crashes, server kills, and network issues without leaving the
   browser stuck in a "Generating..." state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 19:25:29 -07:00
Paul BakausandClaude Opus 4.6 5bad08723d Replace WebSocket with SSE, move live scripts into skill (self-contained)
Two architectural changes that make the live variant mode self-contained:

1. SSE replaces WebSocket: the server now uses Server-Sent Events for
   server→browser push and regular fetch POST for browser→server
   events. This eliminates the ws npm dependency entirely. The live
   server is now zero-dependency pure Node.js (http, crypto, fs, net).

   Browser: EventSource replaces WebSocket. sendEvent() uses fetch POST.
   Server: GET /events returns SSE stream, POST /events receives browser
   events. All other endpoints (poll, source, health, stop) unchanged.

2. Scripts moved to source/skills/impeccable/scripts/: live-server.mjs,
   live-poll.mjs, live-wrap.mjs, live-browser.js are now part of the
   skill itself. Users who install the skill via npx skills get the live
   mode without needing npm install impeccable separately.

   The skill reference uses {{scripts_path}}/live-server.mjs etc.
   The CLI (bin/cli.js) delegates to the skill scripts as a convenience.

   Removed ws from package.json dependencies.

The old src/live/ files remain as the development copy. The build system
syncs source/skills/ to all harness dirs (11 providers).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 19:19:36 -07:00
Paul BakausandClaude Opus 4.6 a832fe778c No-HMR fallback: fetch raw source and inject variants into DOM
For dev servers without HMR (Bun static imports, simple HTTP servers),
the browser can't see file changes automatically. Three changes fix this:

1. /source endpoint on live server: reads a project file from disk,
   gated by session token + path-traversal guard. The browser fetches
   the raw HTML directly, bypassing the dev server's cache.

2. poll --reply --file flag: agent passes the source file path when
   replying done. The browser receives it via WS and knows where to
   fetch. Skill reference updated to always include --file.

3. Browser injectVariantsFromSource(): on "done" with 0 DOM variants,
   fetches the raw HTML from /source, parses with DOMParser, extracts
   the variant wrapper, finds the matching element in the live DOM by
   class/ID, and replaces it. MutationObserver picks up the injected
   variants and the cycling bar appears.

Also: wrap CLI no longer hides the original element (was display:none).
The original stays visible until the first variant arrives, preventing
a flash of empty content between wrap and variant insertion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 19:02:41 -07:00
Paul BakausandClaude Opus 4.6 4535525f8e Add wrap CLI helper and optimize agent generation loop
Three optimizations to cut the generate loop from ~40s to ~15-20s:

1. wrap CLI helper (src/live/wrap.mjs): finds an element in source
   by ID, class names, or tag+class combo, wraps it in the variant
   container with original snapshot, and returns the file path + insert
   line. Replaces 3-4 agent tool calls (grep + read + edit) with one.

   Supports --element-id, --classes (comma-separated), --tag, --query
   (fallback). Searches in priority order: ID > class combo > single
   class > raw text. Auto-detects comment syntax (HTML vs JSX).

2. Batch variant writes: skill reference updated to instruct the agent
   to write ALL variants in a single file edit instead of one per
   variant. Saves N-1 tool call round-trips (~3-5s each).

3. Page URL in generate event: browser now includes location.pathname
   so the agent can map URL to source file directly (/ = index.html,
   /about = about.tsx, etc.) without grepping.

Net effect: agent flow is now 4 tool calls (wrap + edit + read-variant
+ poll-reply) instead of 8+ (grep + read + create-wrapper + N edits
+ poll-reply).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:32:51 -07:00
Paul BakausandClaude Opus 4.6 bb94dadda0 Add live variant mode: element picker, action panel, poll/reply bridge (22 commands)
New feature: /impeccable live starts an interactive visual iteration server.
Users select elements in the browser, pick a design action (bolder, quieter,
etc.), and the agent generates HTML+CSS variants written directly to source.
The dev server's HMR hot-swaps them in, and MutationObserver progressively
reveals each variant in a cycler UI as it arrives.

Architecture:
- src/live/server.mjs: HTTP + WebSocket server with session token auth,
  long-poll /poll endpoint for the agent, WebSocket for the browser
- src/live/poll.mjs: CLI client (npx impeccable poll / poll --reply)
- src/live/browser.js: element picker with keyboard nav (arrows=siblings,
  shift+arrows=parent/child), action panel (12 commands, freeform input,
  variant count), variant cycler with progressive reveal via MutationObserver
- src/live/protocol.mjs: shared message types and event validation
- source/skills/impeccable/reference/live.md: agent loop instructions
  (inject script, poll loop, generate variants, accept/discard, cleanup)

CLI changes:
- bin/cli.js: added "poll" top-level command
- src/detect-antipatterns.mjs: liveCli() now delegates to src/live/server.mjs
- package.json: added ws dependency

Registered /impeccable live as command #22 across all standard locations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 17:13:53 -07:00
Paul BakausandClaude Opus 4.6 e58cbc432f Split /onboard back out as its own command (21 commands total)
Pre-3.0, onboard was folded into /harden when we were trying to reduce
namespace pollution. In the single-skill model that tradeoff is gone,
so the weakest of the old merges is the first to undo.

Harden and onboard live in different mental modes. Harden is defensive
(edge cases, i18n, overflow, errors). Onboard is activation (first-run
flows, empty states as CTAs, progressive disclosure). A user thinking
"design the onboarding flow" was never going to type /impeccable harden.

Changes:
- New reference file at source/skills/impeccable/reference/onboard.md,
  restored from the pre-merge version in git history rather than the
  condensed 33-line summary that was in harden.md.
- Removed the "Onboarding & First-Run Experience" section from
  source/skills/impeccable/reference/harden.md.
- Updated harden description/editorial/process-steps to drop onboarding
  keywords; split commandProcessSteps so harden stays focused on
  production resilience and onboard gets its own phases.
- Registered onboard in: SKILL.md description + command menu + router
  table, command-metadata.json, IMPECCABLE_SUB_COMMANDS, pin.mjs
  VALID_COMMANDS, SKILL_CATEGORIES, COMMAND_RELATIONSHIPS, data.js
  commandCategories + commandProcessSteps + commandRelationships,
  framework-viz commandSymbols + commandNumbers.
- Reused the existing content/site/skills/onboard.md editorial wrapper
  (it was orphaned by the merge but never deleted), updating it to use
  /impeccable onboard.
- Bumped all user-facing count references 20 -> 21: public/index.html,
  CLAUDE.md, README.md, NOTICE.md, plugin.json, marketplace.json,
  sitemap.xml, build-sub-pages.js.
- Harness dir audit.md and critique.md changes are the
  {{available_commands}} placeholder expanding to include onboard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:21:45 -07:00
Paul BakausandClaude Opus 4.6 b0f44f83c6 Consolidate 18 skills into 1 /impeccable skill with 20 commands
Biggest change in a while. Users previously had 18 standalone skill
entries cluttering their /menu; now they have one entry (/impeccable)
that routes to 20 specialized commands via argument dispatch. The pin
mechanism (/impeccable pin audit) restores standalone shortcuts on
demand for commands users hit all the time.

## Architecture

- Single /impeccable skill with command router section in SKILL.md
- 20 commands served via reference files under source/skills/impeccable/reference/
- /impeccable pin <command> creates a lightweight redirect shim so users
  who prefer /audit, /polish, etc. can still have them
- Context gathering (teach) auto-runs on first use
- command-metadata.json is the single source of truth for command
  descriptions, argument hints, and relationships

## Site rewrite

- Docs URL: /skills renamed to /docs (with /skills permanent redirects)
- Homepage hero frames Impeccable as "one skill with 20 commands"
- "Get Started" split into 50/50 install + how-to-use with editorial
  numbered steps, /impeccable shown as the home command with three modes
- New /docs overview: home command hero card + dense category rows
  matching the old cheatsheet density, with leads-to/pairs-with/
  combines-with relationship metadata served from a shared source
- Cheatsheet merged into /docs, /cheatsheet redirects
- Magazine spread and mobile cards show /impeccable as a stacked
  namespace label above the command name at full display size
- Periodic table updated with craft/teach/extract as first-class cells
- Skill detail pages generate from reference files, with an editorial
  wrapper per command for tagline + body
- Tutorials and anti-patterns pages updated to use /impeccable <cmd>

## Build system

- Dead code removed (scripts/lib/transformers/shared.js)
- Build log wording fixed ("1 skill" not "1 skills (1 user-invocable)")
- generateApiData fallback branch removed (throws loudly if metadata
  missing instead of silently degrading)
- Commands API includes editorial tagline alongside the long description;
  UI surfaces prefer tagline for human display, description for auto-
  trigger keyword matching

## Gitignore

- Added .claude/scheduled_tasks.lock, .claude/settings.local.json to
  ignore list (local Claude Code state that should not be tracked).
- Harness skill directories (.claude/skills/, .agents/skills/, etc.)
  remain tracked by design: npx skills reads them from this repo at
  install time and they enable clean submodule use.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:45:17 -07:00
Paul BakausandClaude Opus 4.6 45b92bf9fe Improve cleanup UX: explain to user why files are being deleted
The post-update-cleanup section now instructs the AI to tell the user
what's happening and why before running the script, so file deletions
don't feel unexpected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:49:50 -07:00
Paul BakausandClaude Opus 4.6 f30475cdf4 Remove deprecated source stubs, update FAQ and install copy, add CLI cleanup
- Delete source/skills/ directories for deprecated skills (arrange,
  normalize, onboard, extract, frontend-design, teach-impeccable).
  The cleanup script handles migration; stubs are no longer needed.
- Add "npx skills update" command to the Stay Updated install section
- Rewrite FAQ update answer: lead with npx skills update, add
  troubleshooting for failed updates (re-install + run /impeccable)
- Run cleanup script in `npx impeccable skills update` before
  delegating to npx skills update, preventing failures from
  deprecated entries in skills-lock.json
- Run cleanup script after `npx impeccable skills install` to remove
  leftover files from previous versions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:34:38 -07:00
Paul BakausandClaude Opus 4.6 f9b50d65be Add cleanup script for deprecated skills with 20 tests
Bundled as source/skills/impeccable/scripts/cleanup-deprecated.mjs,
runs via the self-deleting <post-update-cleanup> section in the skill.

The script:
- Finds all harness skill dirs (.claude, .cursor, .agents, etc.)
- Deletes deprecated skill directories (arrange, normalize, onboard,
  extract, frontend-design, teach-impeccable) and i-prefixed variants
- Verifies each file contains "impeccable" before deleting to avoid
  touching unrelated user skills with the same name
- Handles both symlinks and regular directories
- Removes matching entries from skills-lock.json (only if source is
  pbakaus/impeccable)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:16:37 -07:00
Paul BakausandClaude Opus 4.6 5a22894b1f Mark arrange, normalize, onboard, extract as DEPRECATED in source
The build counts active commands by checking for DEPRECATED in the
skill description. Without this, the old source files were still
counted as active (22) while the site says 18, failing CI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 21:36:16 -07:00
Paul BakausandClaude Opus 4.6 8c480843e7 Bump to v2.1.0: changelog, self-deleting cleanup for deprecated skills
- Version bump across package.json, plugin.json, marketplace.json
- Changelog entry for v2.1 in index.html
- Hero version link updated
- Added <post-update-cleanup> section to impeccable SKILL.md that
  detects and removes leftover files from renamed/merged skills
  (arrange, normalize, onboard, extract, frontend-design,
  teach-impeccable). Verifies files contain "impeccable" before
  deleting to avoid touching unrelated user skills. Self-deletes
  after first run so it only executes once per update.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 20:47:24 -07:00
Paul BakausandClaude Opus 4.6 faa7453db7 Consolidate skills from 21 to 18: rename, merge, and fold
- Rename /arrange to /layout for clarity
- Merge /normalize into /polish (design system discovery + cleanup phases)
- Merge /onboard into /harden (onboarding, empty states, progressive disclosure)
- Fold /extract into /impeccable extract sub-mode (reference file, sidebar link)
- Update all counts, cross-references, data files, demos, and metadata
- Remove System category (now empty)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 20:39:02 -07:00