Field report: impeccable SaaS-ified a developer docs page; the Opus
galleries showed the same on an album page. Root cause: two registers
force every surface into persuade-or-operate grammar. The register
section now names the visitor's mode first (Persuade / Operate / Read /
Experience) with mode-borrowing called out as the canonical failure,
and PRODUCT.md's register field maps as family (brand = Persuade +
Experience, product = Operate + Read) for compatibility. Read mode:
comprehension deliverable, navigable structure, chrome out of the way.
Experience mode: the artifact leads at every screen size.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Add OpenAI plugin submission bundle
Build a Codex-native OpenAI plugin with bundled hooks, public listing metadata, submission guidance, privacy coverage, and regression tests.
AI assistance: OpenAI Codex prepared and validated these changes under maintainer direction.
* Fix provider script command rendering
Replace heuristic rewrites across executable scripts with one explicit provider marker, render pinned shortcuts per target harness, and remove the personal email from the public publisher manifest.
Addresses automated review feedback on PR #363.
AI assistance: OpenAI Codex prepared and validated these changes under maintainer direction.
Lower the CLI engine floor to Node 22.12 so npx no longer falls back to stale 2.x releases for Node 22/23 users.
Add Node 22.12 CI coverage while preserving the stable required test check, and document the 3.2.1 CLI release notes including the detector and installer fixes already waiting on main.
AI-assisted-by: Codex
* Add mechanical pre-scan for typeset and layout commands.
Introduce --scope filtering, layout/type rule scopes, DESIGN.md font-size validation, and pre-scan steps in the skill references so agents run detect before LLM judgment.
Fixes#149
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add isolated sub-agent orchestration for typeset and layout pre-scans.
Run the mechanical detector and visual assessment in parallel sub-agents so deterministic findings cannot anchor LLM judgment, matching the critique pattern Paul requested on PR #345.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix: reject bare --scope so detect never scans unscoped by mistake.
When --scope had no value, the CLI dropped the flag and ran a full scan instead of failing, which could silently use the wrong rule set during typeset/layout pre-scans.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix: require both typeset and layout assessments in sub-agents.
Close a loophole where agents ran only the mechanical pre-scan inline by interpreting "running both" as permitting one inline assessment.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Abdul Wahab <abdulwahab@Abduls-MacBook-Pro-2.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
The Pinstripe display face was single-weight, so every `font-weight` on it
was inert — the documented h1/h2 weight split never actually rendered.
Switch --ks-font-display (and --ks-font-wordmark) to plain Alumni Sans, which
honors weight, and set the display scale intentionally:
- Display / h1 -> weight 100 (thin hairline hero)
- Headline / h2 -> weight 300 via --ks-type-headline-weight (light anchor)
- Wordmark 400, body 400, title 500 unchanged
Centralize h2 weight: the eight section-title sites that hardcoded 600 now
read var(--ks-type-headline-weight), so h2 weight is a single lever.
Google Fonts now loads Alumni Sans wght@100;300;...;700 and no longer pulls
the Pinstripe family. DESIGN.md, design.json, and the token/CSS comments are
updated to match (family, weights, Two-Face and Weight-Inversion rules).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codex loads bundled plugin lifecycle hooks from `hooks/hooks.json` using a
strict schema that accepts only the top-level `hooks` field. The
plugin-packaged manifest carried a top-level `description`, so Codex rejected
the whole manifest with `unknown field description, expected hooks` and the
post-edit design detector never registered (issue #330).
Drop `description` from `buildClaudePluginHooksManifest()` and regenerate
`plugin/hooks/hooks.json`. The Claude Code plugin path is unaffected (it only
reads the `hooks` object). Add a regression assertion for the plugin artifact
and bump the skill version to 3.9.1.
Claude-Session: https://claude.ai/code/session_013GTTHY6uHwESUyAgjUEm7x
Co-authored-by: Claude <noreply@anthropic.com>
* Add codex-grid-background detector rule
Detects the Codex two-axis grid-line background tell: a single background
value carrying two or more hairline `linear-gradient(... 1px, transparent
1px)` layers (one per axis), usually paired with a repeating
`background-size` cell. Gated behind --gpt like the sibling codex tells,
off by default.
Counts hairline stops within a single background declaration (not across
the page) so unrelated single-axis ruled lines don't add up to a false
flag, and matches the stop directly rather than parsing whole gradient
layers, since colors like oklch(...) carry nested parens.
Extends the gpt-tells fixture with one flag case and two pass cases
(single-axis rule, two-color blend), regenerates the browser detector
bundle, and bumps the rule count 44 -> 45.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Require tiling background-size for codex-grid-background
Address review: two hairline gradients alone draw a fixed crosshair, not a
grid. Scope detection to a single style block (CSS rule body or inline
style attr) and require both >=2 hairline stops AND a tiling
`background-size` px cell in the same block, matching the skill rule's
"plus background-size" wording. Add a crosshair-without-tiling pass case.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Scope codex-grid-background hairline count to background values
Address review: count hairline stops only inside background/background-image
declaration values, not the whole style block, so a hairline in an unrelated
property (mask-image, border-image) can't stand in for the grid's second
axis. Add a bg+mask-image hairline pass case.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the static Install/First run/Update boxes with a tabbed "Install
via" selector (impeccable / marketplace / skills.sh). Switching a tab swaps
the install and update commands together, with a per-method note.
- impeccable tab marked recommended with a gold star; carries a Node 24+
requirement and a collapsed "Why one command, many builds" diagram that
animates impeccable branching per harness. The diagram foregrounds the
model-specific slop rules compiled into the Gemini and Codex builds
(verified against skill/SKILL.src.md provider tags).
- GitHub Copilot is built into the app, so it's a quiet de-boxed callout
under the tabs rather than a tab, catching Copilot users before they
install something they don't need.
- Add claude-mark.png (transparent-background Claude starburst) for the
marketplace tab.
- Tabs baseline-align with the "INSTALL VIA" label; diagram scales and the
tablist wraps cleanly on mobile.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Add inline, in-file ignore comments for the detector (issue #283)
Complement config ignores with eslint-disable-style waivers that live where
they apply and travel with the file when it leaves the repo. The motivating
case is a generated/exported standalone document that legitimately uses a
first-party brand typeface (on the overused-font list) and is later scanned
without .impeccable/config.json present.
Marker is comment-syntax-agnostic (works in //, /* */, <!-- -->, #, {/* */}):
impeccable-disable <rule>[, <rule>...] [-- reason | : reason] whole file
impeccable-disable-line <rule>... same line
impeccable-disable-next-line <rule>... next line
Bare directive or * means every rule; reason is optional and discarded at
scan time. Behavior is suppression, for parity with config ignores.
Implementation:
- New pure module cli/engine/shared/inline-ignores.mjs (parser + filter, no
Node deps). Static-HTML findings have no line number, so only whole-file
directives apply there -- exactly the standalone-document case; the
regex/text engine additionally honors the line-scoped forms.
- Wired into detectText and detectHtml, gated by options.inlineIgnores.
- detect CLI applies inline ignores by default; --no-inline-ignores skips
just them, --no-config skips config and inline ignores together.
Docs: config.md (new section), detector.md, README. skill/reference/hooks.md
reversed its prior "inline comments are not supported" guidance and now points
the agent to inline waivers for the travels-with-the-file case. Changelog 3.x.
Tests: tests/inline-ignores.test.mjs (parser units, detectText/detectHtml
integration, CLI end-to-end), registered in the detector suite.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Reconcile design hook wording with inline ignores
Two hook-side fixes prompted by review of the new inline-ignore feature:
1. Clean-ack steer line. The old line ("Keep typography hierarchy, spacing
rhythm, and color contrast intentional on the next change.") read as an
odd non-sequitur after "No anti-patterns." Reworded the whole clean ack to
say what it means: a clean scan only clears the deterministic rule set, not
overall design quality, so keep following the design system and skill
guidance. Now: "Design hook scanned X. No deterministic design-quality
issues found. That does not mean the design is good: keep following the
project design system and the impeccable skill guidance."
2. Directive footer. It still told the agent "Do not add source comments such
as `impeccable: ignore`; those pollute the code and do not suppress hook
findings." That is now misleading: the hook runs the same detector engine
as the CLI, which honors inline `impeccable-disable` waivers, so they DO
suppress hook findings (consistent with config ignores, which filterFindings
already honors). Reworded to: don't silence a real finding to skip fixing
it; suppress only after the user confirms intent; prefer a config ignore,
and reach for an inline `impeccable-disable <rule>` comment only when the
waiver must travel with a file that leaves the repo.
Added a hook test asserting an inline `impeccable-disable-line` comment makes
the hook scan the file clean (locks in the cross-cutting behavior), and updated
the clean-ack / footer assertions to the new wording.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Address review on inline-ignores parser
- Case-insensitive fast-path bail-out (Cursor): the cheap substring guard was
lowercase-only while DIRECTIVE_RE has the `i` flag, so a mixed-case marker
like `Impeccable-Disable` skipped parsing entirely and never suppressed.
Switched the guard to `/impeccable-disable/i.test(...)`. Added a regression
test.
- Removed the unreachable `-->` branch from TRAILING_CLOSER_RE (Greptile):
`--+>` already matches `-->` and any longer dash run.
- Replaced the always-truthy lazy-match + `if (sep)` reason strip with an
explicit first-separator slice (Greptile): clearer and drops the dead branch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Align inline-ignore line numbering with the detector (CRLF/CR endings)
parseInlineIgnores split lines with /\r\n|\r|\n/, but detectText numbers lines
with split('\n'). On classic `\r`-only endings the two diverged, so a
disable-line / disable-next-line directive could key a different line than the
finding it should waive (Cursor review). Split on '\n' only, matching the
detector exactly; the directive regex already excludes '\r', so a trailing '\r'
on CRLF files is never captured into the rule list. Added a CRLF regression test
through the real detectText.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Context files (PRODUCT.md / DESIGN.md) resolve child-first then fall back to the repo root, and /impeccable live lets the user pick a child app in a monorepo. Single-app behavior is unchanged. Closes#202. Co-Authored-By: abdulwahabone
Audit of every user-facing surface that enumerates supported harnesses
found GitHub Copilot missing or buried in several. Bring it to parity with
Claude Code, Codex, Cursor, and Gemini.
Missing -> added:
- site/content/reference/hooks.md: the public /docs/hooks page (tagline,
the post-edit list, and the manifest table) now covers GitHub Copilot,
including the `.github/hooks/impeccable.json` surface and the
default-branch/trust note. (Only skill/reference/hooks.md was updated in
the feature PR; this is the website doc.)
- README.md Design hook section + the manifest surface list.
- site/content/tutorials/getting-started.md hook note.
- site/pages/faq.astro tool-specific setup list and the docs-links list.
- PRODUCT.md audience line and README.npm.md suite description.
Prominence + naming:
- README "Supported Tools" and the homepage hero logo row: move GitHub
Copilot up to third (after Claude Code) instead of trailing.
- site/pages/designing: list GitHub Copilot earlier, full name.
- README "Supported Tools": the harness link now points at GitHub Copilot
(github.com/features/copilot) instead of the unrelated VS Code entry.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Add GitHub Copilot hook support (CLI + cloud agent)
Wire the Impeccable design detector into GitHub Copilot's hook system so
direct file edits get the same post-edit design feedback the Claude Code,
Codex, and Cursor harnesses already receive.
GitHub Copilot's contract differs from the existing harnesses (verified
against Copilot CLI 1.0.63):
- Repo-level manifest at `.github/hooks/impeccable.json` (read by both the
CLI, once committed to the default branch, and the cloud/app agent).
- Flat `postToolUse` entries with `bash`/`timeoutSec` and a full-match
`matcher` regex; the file-editing tools are `edit` and `create`.
- The stdin event uses camelCase `toolName`/`toolArgs`, where `toolArgs` is
a JSON *string* carrying the touched file under `path`.
- Context is injected via a top-level `additionalContext` string.
Changes:
- hooks.js: buildGitHubHooksManifest() + route `github` in hooksJsonFor().
- providers.js: emitHooks/hooksManifestRel for the github provider.
- hook-lib.mjs: detect the github harness, normalize the camelCase event
(parse the JSON-string toolArgs -> tool_input.file_path), and emit the
`additionalContext` payload shape.
- hook-admin.mjs / skills.mjs: install + idempotent-repair the
`.github/hooks/impeccable.json` manifest (bash-aware marker stripping).
- hooks.md: document GitHub Copilot as a supported harness.
- Tests for the builder, routing, event normalization, and end-to-end run.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Cover Copilot apply_patch edits in the hook (live-verified)
The first cut matched only `edit|create`, the tool names `copilot -p` uses.
A live trace against Copilot CLI 1.0.63 in an interactive session showed it
edits files via `apply_patch`, whose toolArgs is a raw OpenAI-format patch
string (`*** Begin Patch` / `*** Add File:`), not JSON. With the narrow
matcher the hook command never ran.
- hooks.js / hook-admin.mjs: matcher -> `edit|create|apply_patch`.
- hook-lib.mjs: normalizeGitHubEvent now routes apply_patch's raw patch
string into tool_input.command (reusing the existing parseApplyPatchPaths /
resolveTargetFiles plumbing) and only JSON-parses toolArgs for the
edit/create/view tools. tool_name is normalized to apply_patch so the patch
path is extracted even if a future build relabels the tool.
- Tests: apply_patch matcher assertions, event normalization, and an
end-to-end runHook covering the interactive/cloud path.
Verified live: a trusted interactive `apply_patch` edit fires the hook and
returns the expected `additionalContext` design reminder.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Address review feedback + add changelog entry
- hook-lib.mjs (Bugbot, low): looksLikeApplyPatch no longer misroutes an
edit/create event whose edited *content* contains apply_patch markers. A
real apply_patch payload is a raw string that does not parse as JSON; an
edit payload is a JSON object, so only non-JSON-object strings are treated
as apply_patch. Edit events keep extracting `path`. Adds a regression test.
- skills.mjs (Bugbot, medium): document why `.github` is intentionally
excluded from hookScriptPathForProvider. Its hook manifest is committed and
shared (read by the Copilot cloud agent and teammates), so the command must
stay portable via `$(git rev-parse ...)`; rewriting it to a machine-local
absolute path would break those. GitHub skills are project-scoped, so the
project-relative path resolves.
- changelog: add an Upcoming (v3.x placeholder) entry for the Copilot hook.
Version is not bumped yet (batching with other changes).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bundled detector's cli/main.mjs imports ../../lib/impeccable-config.mjs,
which in the source CLI resolves to cli/lib/impeccable-config.mjs. The skill
build only copies cli/engine/** into scripts/detector/**, leaving that
dependency behind, so from the bundled scripts/detector/cli/main.mjs the same
import resolved to scripts/lib/impeccable-config.mjs and failed with
"Cannot find module .../lib/impeccable-config.mjs". /impeccable critique (and
any detector-backed command) crashed on startup for every provider since #252.
Teach the detector bundler to copy out-of-bundle engine dependencies into the
skill's scripts/lib/, and add a build test that walks every bundled script and
asserts each relative import resolves to another bundled file, so a future
out-of-bundle dependency fails the test instead of the user.
Skill v3.7.1 (patch). CLI unchanged — the engine resolves fine in the CLI's
own tree; only the skill bundling was wrong.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On Node v24.16.0 / v26.1.0+, `impeccable install` printed "Downloading
impeccable skills...", exited 0, and installed nothing. A Node streams
regression (nodejs/node#63487) made pause()/resume() no-ops on destroyed
streams, stalling extract-zip's yauzl/fd-slicer read stack partway through;
its promise never settled and the process exited clean with no error.
Swap extract-zip for fflate across both extraction call sites
(downloadAndExtractBundle, copyOrExtractLocalBundle) via a new extractZip
helper. fflate decompresses from an in-memory buffer and never touches the
fs stream path, so it is immune on every Node version. It is pure JS with
zero dependencies, so the Windows fix from #198 (no `unzip` binary) holds.
Unlike extract-zip, fflate is actively maintained.
Because extractZip writes entries itself, it guards against zip-slip (`../`
entries escaping the target dir). Tests add a many-file regression guard
(fails on partial extraction) and a zip-slip rejection test.
Verified end-to-end: the real 1,194-file universal bundle extracts and
installs completely.
Fixes#250.
Co-authored-by: Claude <noreply@anthropic.com>
* Fix: tear down annotation overlay when Escape exits live pick mode.
The configure prompt auto-focuses and bypasses the global Escape handler, so its local path must hide the annot overlay; togglePick off now does the same as a safety net.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Improve live mode steer pill typing affordance.
Show a visible caret and placeholder when focused, expand on pointerdown, and drop the muddy border so the graphite surface carries the affordance alone.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Improve live mode configure bar layout and pill styling.
Align pills and input on a shared text track, refine muted pill chrome with a quiet action border, and center the row with symmetric inset so spacing reads evenly in the 36px bar.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add x1 to live mode variant count picker.
The configure bar count pill now cycles 1→2→3→4→1 so users can request a single variant.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Polish live mode configure bar, edit badge, and action picker.
Refine selection pill layout and tooltips, shrink edit copy to an icon aligned with the outline, right-align the action picker, and sync demo styles and regression coverage.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix live mode element nav when configure input is focused.
Passthrough empty arrow keys from the configure and steer prompts so handleKeyDown can move between pickable elements without breaking autofocus typing.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Remove accidental live.js inject from Base.astro.
Strip the localhost helper script tag left over from local live mode iteration so the PR ships only intentional UI changes.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix review findings: pick-cursor state sync, anchor recovery, e2e selectors.
Code review of this branch surfaced ten confirmed bugs plus three smaller
ones; this commit fixes all of them.
- Route every interaction-state transition through a new setLiveState()
helper that re-syncs the pick-mode crosshair, fixing four confirmed
cursor bugs: never appearing on pick toggle (sync ran before the state
change), sticking through the configure phase, surviving teardown
page-wide, and the style mounting inside the adapter's shadow root
where it can't match the host document (now document.head).
- Anchor recovery: a matching id is decisive again (hashed class names
and component tags broke recovery), empty-text elements can no longer
match the fuzzy text passes (".includes('')" hole plus shortest-text
preference), and the dead 2-class-subset fallback is removed.
- Selection pill: drop the hover-only "armed" guard so keyboard
activation works; the pill arms on focus as well as hover.
- Configure chrome: remove the configure-bar tooltip on teardown, align
restorePickerBarChrome padding with initBar (5px), share the
configure-input stylesheet with the insert row, and sync the
ui-core.mjs surface inventory with live-browser.js.
- Site demos: delete the stale duplicate .live-demo-ctx-selection rule
that killed the teal pill on dark pages, and keep the configure-phase
demo bar on the overlay's dark surface in light mode so the near-white
prompt text stays readable.
- E2E/contract tests: match the icon-only submit button by aria-label
("Generate variants") instead of the removed "Go" text, and update
source-contract pins for setLiveState and buildConfigureSubmitButton.
Verified: bun run test green, live-mode E2E 23/23 across all fixtures.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Wire insert voice button into syncVoiceUi listening state.
Voice on the insert configure row runs through the same 'configure' mode,
but syncVoiceUi only stamped data-listening/aria state on the replace
row's #impeccable-live-configure-voice, so the insert button never pulsed
while listening. Target whichever of the two row buttons is mounted, the
same either-row pattern syncConfigureInputChrome uses.
Addresses Bugbot review comment on PR #242.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Reinject from source when the session wrapper lands during anchor recovery.
The anchor-recovery observer stood down as soon as the session's variant
wrapper appeared in the DOM, without running injectVariantsFromSource.
A wrapper can land incomplete (wrap HMR landed, variant insert did not),
which is exactly the case injectVariantsFromSource's existing-wrapper
replace path handles - so recovery ended with the bar stuck and no
variants. Route both the anchor-found and wrapper-landed cases through
injectVariantsFromSource, which owns wrapper replacement, recovery-flag
clearing, and variant display.
Addresses Bugbot review comment on PR #242.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Restore inline edit drafts before configure chrome teardown disables editing.
teardownConfigureChrome called disableInlineEdit() ahead of hideBar(),
wiping inlineEditRows and the impeccableOriginalText metadata that
hideBar()'s EDITING-state restoreInlineEditDrafts() needs - so turning
Pick off mid "Edit copy" left edited DOM text in place, neither saved
nor canceled. Let hideBar() own the sequence: it restores drafts first,
then disables inline edit.
Addresses Bugbot review comment on PR #242.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Derive a Gecko-compatible manifest at build time and package
extension-firefox.zip alongside the Chrome zip:
- background service worker is declared as an event-page `scripts`
entry (top-level listeners + in-memory Map run unchanged on Gecko)
- browser_specific_settings.gecko with id, strict_min_version 140.0,
and data_collection_permissions (required by AMO; honored on 140+)
- packZip helper parameterized over cwd/excludes; `*.DS_Store` strips
junk at every depth and .DS_Store is excluded from the staging copy
- guard against a missing background.service_worker shape
CI now builds the extension and runs a pinned `web-ext@8 lint` over
the staged Firefox tree (innerHTML warnings are non-blocking); the
unpacked staging dir is excluded from the uploaded artifact. The
release script attaches both zips and points to AMO.
Bumps the extension to v1.2.0 with a changelog entry.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com>
Rewrite the hero around the why (the missing design vocabulary) instead of the
live-mode how: "The missing design vocabulary for agents." The live demo now
opens the picker's command palette and picks a verb before generating, which is
the move that makes the live approach unique and was previously skipped.
- Demo palette mirrors the real action picker (live-browser.js): same 12 verbs,
the same SVG icons, a 4-col icon-over-label grid, selected chip on a kinpaku
wash with its icon recolored. Light + dark covered.
- Shared <LiveDemoPalette> component renders the grid from one list, so the hero
and /live-mode no longer hand-copy the markup. /live-mode lands on "delight",
the hero on "colorize" (via data-demo-pick); pages without a palette filter the
switcher beats out of the shared timeline.
- Trim the opening beats so the cursor clicks the element at ~1.3s (was ~2s), and
slow the palette browse so the vocabulary is readable.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Default is "auto", which inherits from the OS via prefers-color-scheme
and follows it live. Clicking cycles auto → light → dark → auto; the
explicit choice persists in localStorage while auto stores nothing.
The toggle shows the active preference (half-circle / sun / moon) keyed
on a new data-theme-pref attribute, so "auto" is its own visible state
rather than collapsing into whatever the OS resolved to.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fix live preview state for framework components
* Complete stateful live preview coverage
* Record Svelte manual validation
* Fix Svelte live mode adapter
* Fix live Steer apply flow
* Fix Svelte live variant refresh recovery
* Fix live exit bar teardown
* Consolidate Svelte live DeepSeek sweep
* Reconcile Svelte live browser after main rebase
* Fix live accept review regressions
* Fix carbonize column-zero indentation
* Fix live poll lease expiry flake
* Fix Svelte shader preview capture
* Fix GitHub Copilot site mentions
* Fix mobile command blocks
* Fix mobile nav drawer centering
* Align mobile nav controls
* Align mobile nav controls
* Pad mobile nav drawer
* Fix light mobile nav drawer
* Remove light drawer active border
* Restore light drawer active underline
* Fix designing mobile layout
* Tune designing mobile loop
* Fix designing mobile section gutters
* Keep polish commands on one mobile row
* Fix designing mobile bento gutters
The `i-` prefix install option was a holdover from the multi-skill era.
With a single `impeccable` skill it only ever renamed that one skill to
`i-impeccable`, while the install message wrongly advertised `/i-audit`
style commands that never existed, and the unscoped rename could clobber
unrelated third-party skills in the same harness folder.
- Drop `--prefix=`, the interactive prompt, and all prefix machinery
(renameSkillsWithPrefix, prefixSkillContent, detectPrefix, undoPrefix,
prefixedCommandHint, isImpeccableSkillName).
- Add migrateUnprefixImpeccable: install --force and update rename any old
`<prefix>impeccable` back to canonical `impeccable` before the fresh copy
lands, scoped by name so foreign `i-*` skills are left untouched.
- Fix FAQ + editorial that wrongly described pinned commands as `i-`
prefixed (pins are bare `skills/<command>/` dirs).
- Tests now exercise the real exported migration, not a reimplementation.
- CLI 2.3.1 -> 2.3.2 with a changelog entry.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes the documentation gap from #177: how to update an installed
version was nowhere on the site. Install and Update now sit as paired,
equally-visible commands, with `npx impeccable skills check` and the
Claude Code `/plugin` path called out alongside.
Also a full pass on the section's composition:
- Commit to left-aligned asymmetry so content has one spine and the gold
seam owns the right edge, instead of floating left-of-center
- Make the install command pop: bright kinpaku frame + gold `$` prompt +
left-aligned mono so it reads as a runnable line, not a decorative chip.
Update box mirrors it one notch quieter in patina (the "updated" state)
- Group install/update/alternatives tightly, rule off the secondary
surfaces, drop the duplicate "Get started:" closing label
- Repurpose the "Stay updated" cell to "Follow along" so it stops
colliding with the real Update command
FAQ already had a strong #update entry; added the `skills check`
companion for parity. Getting-started tutorial gains a short update note
after Step 1. Both themes synced.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(home): command-wheel contrast, slop copy, line-length
Address P1/P2/P3 findings from /impeccable critique of the homepage:
- Command wheel (The Language): off-center command names floored at
~1.43:1 contrast were illegible (WCAG 1.4.3 fail) and hid most of the
23-command vocabulary. Raise the fisheye opacity floor 0.25 -> 0.62,
MIN_SCALE 0.35 -> 0.52, and lift the base color from --ks-text-muted to
--ks-text. Off-center now measures >=4.59:1; full list stays scannable
while gold + size + weight still carry focus.
- Slop section copy: rewrite all 7 discipline cards off the uniform
"No X. No Y. No Z." triad into varied cadence with positives, and lead
the section with what Impeccable does instead of the "Skills can't..."
negation pivot. Drops the en-dash joiners too.
- Line length: cap .downloads-rebuild-note (was unbounded, ~102ch) and
tighten the homepage .section-lead 68ch -> 62ch (rendered ~86 actual
chars/line).
The diagonal plinth ramp on the slop grid is intentionally kept per
design preference.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(home): de-warm and brighten the text ramp
Warmth now lives only in the gold accents and surfaces, not the type.
Body, headings, and the secondary tiers read crisp on lacquer instead of
mushing into the warm floor:
- --ks-champagne 84% .035 82 -> 91% .006 90 (headings/strong, now neutral;
token name kept for compatibility)
- --ks-text 81% .03 82 -> 88% .008 90 (body)
- --ks-text-muted / -faint / -mute-deep lifted and de-warmed to match
DESIGN.md frontmatter + prose synced to the new values.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(home): outlined testimonials + cleaner hero boundary
Testimonials:
- Flatten the double container: drop the t-plinth shelf wrapper (markup +
CSS); the marquee sits directly in the section and carries its inset.
- Outlined cards: no fill, 1px solid neutral border (oklch .64 0 0 / .22),
no dead drop-shadow. Removes the mushy gray-on-gray blend and the stacked
dotted-divider + gold-hairline chrome.
- Section has no background of its own (rides the body lacquer gradient) and
no top padding, so cards sit right under the hero divider.
Hero:
- Drop the bottom fade and the top nav scrim; the kintsugi art runs at full
strength. A 1px neutral border-bottom (matching the card border) marks the
testimonials boundary instead of a wash.
- "How it works" is the kit ghost link (white), not an outlined button.
Foundation/slop cards: lift the surface 9% -> 15% so they read as raised
specimen cards instead of vanishing into the ground.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(live): quieter, more refined picker chrome
Gold is reserved for the brand mark and the active control instead of
ringing every container. Applied to the homepage demo, /live-mode, and the
real injected picker (skill/scripts/live-browser.js, rebuilt into the
harness dirs):
- Container: neutral 1px hairline + tight neutral shadow (was a 1.5px gold
border + gold halo ring); radius 10px -> 8px.
- Active toggle: crisp graphite pill with gold text (was a murky kinpaku-dim
wash).
- Internal control borders (action pill / input / count): neutral hairline
(was a warm gold rule); configure-row controls share one 30px baseline.
- Pick outline: crisp 1.5px line, no soft gold glow ring; tighter radius.
- Demo browser chrome: small uniform neutral dots, neutral URL pill, slimmer
bar; frame edge neutral hairline + tighter shadow that registers on dark.
DESIGN.md "Live Mode Picker" spec + "Picker Is Brand Rule" updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(design): neutral default hairline (--ks-rule)
The default border/divider token was a warm gold hairline, used ~200x as
the site-wide default border — so every small label, pill, counter, card,
and divider carried warmth. Redefine it neutral so borders read clean;
gold stays where it signals.
- --ks-rule oklch(58% 0.065 82 / 0.32) -> oklch(78% 0 0 / 0.16)
- --ks-rule-strong (active/focus/brand borders) unchanged, still gold
- GitHub star pill: explicit near-white border (oklch 92% 0 0 / 0.18)
- DESIGN.md hairline mirror + prose synced
Verified across home, /design-system, and /docs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(home): testimonials separator + visible star-pill border
- Move the dotted accent to the bottom of the testimonials (neutral dots)
as a deliberate separator into the slop section; drop the oversized
bottom padding to 1em so cards sit near the separator.
- Star-counter pill: solid oklch(80% 0 0) border. The previous near-white
at 0.32 alpha rendered as faded mid-gray on the near-black pill; a solid
light border reads as the intended white hairline.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(design): neutralize body text (--ks-text)
Drop the last bit of warm chroma from the body text token; it still read
slightly warm at 0.008 chroma.
--ks-text oklch(88% 0.008 90) -> oklch(88% 0 0) (pure neutral)
DESIGN.md mirror + prose synced.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(design): neutral text everywhere
Zero the residual warm chroma across the rest of the text ramp so no text
tier carries warmth (warmth lives only in gold accents + surfaces).
- --ks-champagne 91% .006 90 -> 91% 0 0
- --ks-text-muted 72% .01 90 -> 72% 0 0
- --ks-text-faint 62% .008 90 -> 62% 0 0
- --ks-text-mute-deep 52% .008 90 -> 52% 0 0
(--ks-text was already neutralized.) DESIGN.md mirror + prose synced.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(home): crisp, neutral Desloppification section
- Foundation card background: oklch(15% .004 95) -> oklch(15% 0 0) (neutral
graphite) so cards read crisp, not warm.
- Plinth hatch: kinpaku gold -> neutral (oklch 80% 0 0 / .07) on a neutral
base; the gold hatch was washing the section champagne.
- Remove the plinth bottom mask-fade so the pedestals end on a clean edge.
Gold stays only on the card icons as the accent.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(home): drop the homepage warm-token overrides
The homepage redefined --ks-rule, --ks-rule-strong, and --ks-muted to warm
values locally (an old "busier surfaces" tweak), so homepage borders and
secondary text stayed champagne even after the global de-warm. That's why
the Desloppification cards still read warm.
- Remove the --ks-rule / --ks-rule-strong overrides; inherit the global
tokens (neutral default border, gold strong/active border).
- Alias --ks-muted to the global --ks-text-muted (no divergent value);
legacy code still reads the --ks-muted name.
Result: all homepage borders + secondary text are neutral; gold stays on
accents (icons, mark, CTAs, active/focus).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(design): canonical code tokens (inline + block)
Code styling was all over the place: homepage inline code was gold-on-gold,
the slop CLI was a one-off gold-on-raised-lacquer, downloads used a separate
--card-cmd-* set, docs used yet another. Add one shared token set and point
the canonical surfaces at it.
New :root tokens:
- --ks-code-fg / --ks-code-bg / --ks-code-radius (inline: neutral chip)
- --ks-code-block-fg / -bg / -border / -radius (block/CLI: lacquer terminal)
- --ks-code-cmd (code that's a command link)
Migrated: homepage inline code (was gold -> neutral chip), slop-teaser-cli
(the "weird color" -> neutral terminal), downloads-cmd, and the docs inline +
fenced-block rules (now the token source of truth; block text also neutralized).
Remaining pages (designing, changelog/faq, detector, case studies) swept next.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(design): sweep remaining pages onto code tokens
Point the rest of the site's code rules at the shared code tokens so inline
code and blocks are consistent everywhere:
- Inline code (designing, changelog, faq): gold -> neutral chip
(--ks-code-fg / --ks-code-bg).
- Detector rule pills + table cells: code text -> --ks-code-fg.
- Neon-mirai case-study code block -> --ks-code-block-* tokens.
Command tags (the gold /command pills: spread-flow-cmd, docs-flow-cmd,
designing-phase-cmd, why-ci-cmd, etc.) are intentionally left as their own
interactive category, not generic code.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(home): polish "The Language" section
- Command tags (/polish, /adapt): gold command text on a neutral code chip
(--ks-code-cmd / --ks-code-bg), dropping the muddy gold-tint border.
- Commands panel kept as the solid oklch(0.17 0 0) panel (no border).
- Demo preview cleaned up to a single framed split: strip the grid ::before,
the gold-grid/radial-glow container background, and the inner drop-shadow;
before-half inherits the panel, after-half is near-black, with one thin
neutral border on the demo itself (caption sits outside it).
- Periodic table: crisp flat neutral graphite tiles. Removed the JS-inlined
category bg (var(--cat-*-bg)) + 1.5px colored border + hover drop-shadow,
the gold-leaf ::before texture, the ::after accent line, the inset box-shadow,
and the gold hover glow. Now a 1px neutral border, white symbols, readable
neutral names, and a clean neutral-border hover with no shadow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(design): roomier inline-code padding
Inline code chips were tight top/bottom (the homepage one was only 0.05em).
Add a --ks-code-pad token (0.3em 0.5em) and point every inline-code rule at
it so the chips have consistent breathing room.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(home): drop non-steering commands from the command palette
impeccable, init, extract, document, and live are setup/management commands,
not steering verbs. Filter them out of the palette (fisheye + mobile carousel)
via a shared PALETTE_EXCLUDED set. They stay in the periodic table, which is
rendered separately by framework-viz.js.
Palette: 23 -> 18 commands.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(designing): flatten the pre-ship nested box
The pre-ship cards were a box-in-box: a legacy .designing-polish-grid panel
(cream bg + L/R/B border + padding, from docs-visuals.css) wrapping cards that
already have their own border + fill. Override the grid to a plain transparent
layout so the three cards are the only surface.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(designing): remove step counter + flatten design-debt boxes
- Drop the cryptic "03 · 04" pre-ship step counter (.designing-polish-band-meta)
and tighten the band to a single bottom hairline.
- Design-debt: flatten the box-in-box (bento plinth > tile > stage). The
.designing-maintain-stage no longer adds its own border + fill; the demo
sits directly in the bento tile.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(designing): neutralize code/terminal/panel surfaces
The terminal block, surface-cmd chips, command pills, live-frame, and other
dark panels used a slightly-warm dark fill (oklch 1X% 0.006 95). Drop the warm
chroma so they read neutral like the rest of the de-warmed site; the page
ground + deep surfaces stay lacquer-warm.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(designing): neutralize inline code + live-mock picker chrome
- Inline code: the phase-sub and avoid-title code were still gold; point them
at --ks-code-fg so all inline code reads neutral (gold stays only on command
*links*).
- docs-viz-live mock: bring the duplicated picker chrome in line with the
refactored neutral treatment — neutral 1px container borders (no gold halo),
neutral active "Pick" pill (was the kinpaku-dim wash), crisp pick outline
(no glow), tighter radii.
- CTAs (SEND ME ONE, Accept): pale-cream kinpaku-pale -> solid kinpaku gold.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(designing): flatten lanes + avoid sections
- Brand/Product lane mock cards: drop the inner border+fill box; the mock sits
directly in the bento tile, separated by a top hairline (no plinth>tile>mock
nesting).
- "What to avoid" list: flatten the boxed list cards into a clean divided list
(hairline separators, no per-item border/fill).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(designing): clean up the Brand/Product lanes
- Drop the bento plinth (0.17 fill + 8px gutter that drew the weird gutter
"borders") and the tile fill; the two lanes sit on the page split by a single
center hairline.
- Brand mock title used the pinstripe display face at 1.6rem (reads broken at
that size, the "champagne text"); switch it to the clean body face so it
matches the product mock title.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(site): update GitHub star count to 31k
31,188 stars as of now; header pill + aria-label were stale at 30k.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Add Neo Kinpaku light mode across the site.
Wire theme persistence and a header toggle, then layer light-mode overrides for docs viz contrast, command demos, live-mode pathway cards, and the designing/home surfaces.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(designing): replace em dashes flagged by prose validator
Brand/Product lane copy used em dashes ("the deliverable —", "the task —");
swap for colons per STYLE.md so the Cloudflare build's validateProse passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(designing): address Cursor bugbot nits
- Fold the duplicate .designing-avoid { gap: 0 } override into the original
rule (the gap: 18px was dead code).
- Drop the leftover el.style.boxShadow = 'none' in the periodic-tile deactivate
handler — activate no longer sets a box-shadow, so this only left a dead
inline none that could suppress a future CSS shadow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
The .codex/agents sidecar + boot-time self-heal it described was reverted
in CLI v2.3.1 (nested in-skill agent is the whole delivery now), so the
bullet no longer matched shipped behavior. Removed from the changelog and
the skill-v3.5.0 GitHub release notes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(live): correct the generation shader's capture + halftone on dark and textured surfaces
The live-mode "ink-wash" loading shader rendered correctly on light
elements but broke on dark and textured ones. Root causes and fixes:
- Ground the halftone on the element's own background tone (new u_paper
uniform) instead of a fixed cream paper, so dark elements stop flashing
bright as the roller passes.
- Drive dot size by each cell's contrast from that ground, not absolute
darkness, so content (text, buttons) becomes the dots on light and dark
alike instead of inverting on dark elements.
- Cap the dot radius so a solid dark region stays separated dots rather
than flooding into a gold bar.
- Parse computed colors by rasterizing through a canvas, so oklch()/color()
tokens resolve instead of falling back to white.
- Two-stage dissolve (flatten to ground, then dots emerge) so the raw
element never bleeds through the band's soft core/trail.
- Carry the capture's alpha through the shader so rounded corners and
transparent regions show the live backdrop instead of rendering black.
- When an element is transparent up to the root but its backdrop comes from
an ancestor's image or a covering layer (e.g. a hero art div), capture
that ancestor and crop to the element. Fixes the homepage hero heading
capturing on white, and embeds the real backdrop in the model upload too.
The halftone ground is sampled from just outside the element so it tracks
the true backdrop rather than a muddy average of the content.
Adds /shader-lab, a standalone harness that runs the real capture + shader
pipeline against a matrix of background shapes (light, dark, gradient,
image, glass, rounded, and a homepage-hero replica) with raw vs
capture+shader side by side. The capture/shader code is copied from
live-browser.js and kept in sync.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(live): clear the cached color-parse canvas before each fill
Cursor Bugbot (PR #171): cssColorToRgb01 reuses a cached 2D context, so a
semi-transparent input (alpha 0<a<1, which isTransparentColor lets through)
blended source-over with the previous call's pixel, making the result depend
on call history. clearRect before the fill makes each call independent.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pick an element, Edit copy in the browser, and on Apply a subagent
rewrites the real source the text renders from and repairs anything wired
to it. Folds into the v3.5.0 Live Mode bullet alongside the Steer bar.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>