diff --git a/.gitignore b/.gitignore index ecdd70d..1f2bfe5 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,7 @@ skills/ios-sync skills/design-motion-principles skills/emil-design-eng skills/frontend-design +skills/impeccable # External skills installed via `npx skills add` — auto-created by link.sh skills/darwin-skill @@ -136,6 +137,12 @@ desktop.ini # an update. The source is always re-synced, so no offline copy is needed. skills-external/frontend-design/ +# Impeccable — machine-owned dist produced by `npx impeccable skills install` +# (install-plugins.sh Step 8d, update-all.sh), pinned in plugins.lock.json. +# Not vendored: the installer owns the layout and rewrites it on update +# (ctx7 pattern). Symlinked into skills/ by link.sh. +skills-external/impeccable/ + # npx `skills add` project-scope artifacts — darwin-skill copies itself into # the repo's .agents/ and writes skills-lock.json at root. Our own agents live # in agents/ (no dot) and stay tracked. Anchored to root so only the dotted diff --git a/CHANGELOG.md b/CHANGELOG.md index e690e41..1598990 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Format follows [Keep a Changelog](https://keepachangelog.com/). ## [Unreleased] ### Added +- **impeccable** (pbakaus, Apache-2.0) wired into the toolchain as the design counterpart of semgrep: the `/impeccable` skill (23 verbs under one command: audit, polish, bolder, quieter…) plus the 45-rule deterministic anti-pattern detector (`npx impeccable detect`, exit 0/2, `--json`). Complementary to `frontend-design` (kept — aesthetic direction at build time); impeccable adds the deterministic audit floor and per-project design context (`/impeccable init`). CLI pinned in `plugins.lock.json` (3.2.0 — a silent rules update would change audit output on unchanged code); dist is machine-owned under `skills-external/impeccable/` (gitignored, ctx7 pattern), staged-installed by `install-plugins.sh` Step 8d, refreshed pin-honored by `update-all.sh`, symlinked by `link.sh`, listed in the design/web/web-full/full profiles and the design-work routing. Requires Node ≥ 24 — the install/update steps skip gracefully below that (this host runs 22: bump Node to activate). Not in the design gate's GATE-BLOCK list yet — promotion deliberate, after first dogfood. - `/tour` skill — grouped all-axes sweep over one or several projects: security (pinned-semgrep `security-auditor` agent + `/cso` posture when gstack is ON) → cleanup → re-verify → reconcile (report-only, never edits the target TODO/registries) → doc sync, looping until a full pass applies zero fixes (bounded at 3 iterations). Fixes land on a `chore/tour-` branch the skill never merges; each project gets an append-only `.claude/audits/TOUR.md` report with BREAKING tags on contract-changing security fixes. Built TDD (superpowers:writing-skills): baseline run showed silent TODO rewrites, autonomous registry writes, grep-as-security-pass, no persistent report, scope creep and an unbounded loop — each countered and verified on a seeded fixture. ### Fixed diff --git a/CLAUDE.md b/CLAUDE.md index f17c452..bd6bd56 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -292,8 +292,11 @@ source for design routing; the design-toolchain hook reinforces it. - Build UI (component, page, redesign) → ui-ux-pro-max + frontend-design (anti-slop) + Magic MCP /ui + emil-design-eng (polish) + design-motion-principles (if motion) + design-html (if static). + Post-build floor: `npx impeccable detect ` (45 deterministic + anti-slop rules, exit 2 = findings) when impeccable installed. - Design system / brand → design-consultation first, then the build tools. -- Review / audit → design-review + emil-design-eng + design-motion-principles. +- Review / audit → design-review + emil-design-eng + design-motion-principles + + /impeccable audit|critique (skill) + `impeccable detect` floor. Scope doubt → don't silently skip: ask, or default to Build tier. Gate: lightweight skills run `~/.claude/lib/design-gate.md`; orchestrators via plugin-check. Magic MCP costs API calls — generation, not micro-tweaks. diff --git a/README.md b/README.md index 41270e2..527bcbd 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ Versions are pinned in `plugins.lock.json`. To update: edit the file, then re-ru | `/code-clean` | Dead code removal, style/norm enforcement | | `/doc` | Documentation audit and sync — detect stale docs, patch | | `/seo` | Full SEO/GEO audit and optimization | +| `/impeccable` | Design verbs (audit, polish, bolder…) + deterministic anti-slop detector (`npx impeccable detect`) | | `/commit-change` | Smart commit grouping from staged/unstaged changes | | `/gitflow` | Gitflow branch operations — bootstrap main+develop, start a typed branch, directed merge | | `/release-candidate` | Cut a versioned release — finalize version.txt + CHANGELOG, merge develop→main, tag, push | diff --git a/agents/plugin-advisor.md b/agents/plugin-advisor.md index 44fe054..d617a75 100644 --- a/agents/plugin-advisor.md +++ b/agents/plugin-advisor.md @@ -217,10 +217,10 @@ findings before producing recommendations: | Signal | Enable / Use | Disable / Skip | Notes | |---|---|---|---| -| `frontend` | ui-ux-pro-max, frontend-design, design-motion-principles | — | UI design + polish + motion. frontend-design = anti-AI-slop, design-motion-principles = motion/animation (both external, symlinked) | +| `frontend` | ui-ux-pro-max, frontend-design, design-motion-principles, impeccable | — | UI design + polish + motion. frontend-design = anti-AI-slop, design-motion-principles = motion/animation, impeccable = /impeccable verbs + deterministic detector (`npx impeccable detect`, 45 rules) — all external, symlinked | | `mobile` (React Native/Expo/Flutter) | — | gstack (no browser QA), Docker N/A | ui-ux-pro-max optional | | `monorepo` | per-package plugin recommendations | avoid recommending gstack for whole repo if only one package has browser QA | Specify which plugin applies to which package | -| `design-system` | ui-ux-pro-max, frontend-design, design-motion-principles | — | Design tokens, theme, Storybook, motion | +| `design-system` | ui-ux-pro-max, frontend-design, design-motion-principles, impeccable | — | Design tokens, theme, Storybook, motion; impeccable init persists the design context (DESIGN.md/PRODUCT.md) | | `deploy` + `browser-qa` | gstack | — | Full-product workflow | | `multi-session` | gsd v2 CLI | — | Run `gsd` in terminal, not CC plugin | | `fast-libs` | context7 | — | Doc freshness critical | diff --git a/install-plugins.sh b/install-plugins.sh index 60d79e6..44ca03a 100644 --- a/install-plugins.sh +++ b/install-plugins.sh @@ -750,6 +750,57 @@ else fi echo "" +# ── Step 8d: Impeccable (design anti-pattern detector + skill) ── +# 45 deterministic detector rules (CLI `impeccable detect`, exit 0/2) + +# /impeccable skill (23 verbs). Machine-owned dist: the installer produces +# it, we stage it in a tmpdir then move it under skills-external/ +# (gitignored, ctx7 pattern) — never let the installer write through the +# ~/.claude/skills symlink into the tracked repo dir. +echo "── Step 8d: Impeccable — design anti-pattern detector ────" +echo "" +IMP_DIR="$REPO/skills-external/impeccable" +IMP_VER=$(pinned_version "impeccable") +NODE_MAJOR=$(node -v 2>/dev/null | sed 's/^v//' | cut -d. -f1) +if [ -z "${NODE_MAJOR:-}" ] || [ "$NODE_MAJOR" -lt 24 ]; then + if [ -f "$IMP_DIR/SKILL.md" ]; then + ok "impeccable already present (update skipped — needs Node >= 24, found ${NODE_MAJOR:-none})" + else + warn "impeccable: needs Node >= 24 (found ${NODE_MAJOR:-none}) — skipped. Bump Node, then: make plugin" + fi +else + IMP_PKG="impeccable" + if [ "$IMP_VER" != "latest" ]; then + IMP_PKG="impeccable@${IMP_VER}" + info "Installing impeccable ${IMP_VER} (pinned in plugins.lock.json, staged)..." + else + info "Installing impeccable latest (consider pinning in plugins.lock.json)..." + fi + IMP_STAGE=$(mktemp -d) + if (cd "$IMP_STAGE" && npx -y "$IMP_PKG" skills install -y --providers=claude --scope=project --no-hooks >/dev/null 2>&1); then + IMP_SRC=$(find "$IMP_STAGE" -type d -name impeccable -path "*skills*" 2>/dev/null | head -1) + if [ -n "$IMP_SRC" ] && [ -f "$IMP_SRC/SKILL.md" ]; then + rm -rf "$IMP_DIR" + mv "$IMP_SRC" "$IMP_DIR" + ok "impeccable synced to skills-external/ (CLI ${IMP_VER})" + else + warn "impeccable: installer ran but produced no skills/impeccable/SKILL.md — layout changed? Inspect: npx impeccable skills install" + fi + else + if [ -f "$IMP_DIR/SKILL.md" ]; then + ok "impeccable already present (installer failed — existing dist kept)" + else + warn "impeccable install failed — run manually: npx impeccable skills install -y --providers=claude --scope=project --no-hooks" + fi + fi + rm -rf "$IMP_STAGE" +fi +if [ -L "$HOME/.claude/skills/impeccable" ]; then + ok "impeccable symlink OK" +else + info "Symlinking — will be created by link.sh" +fi +echo "" + # ============================================================ # STEP 8.5 — EXTERNAL SKILLS (npx skills add …) # ============================================================ @@ -949,6 +1000,7 @@ echo " 🔄 context7 CLI — ctx7 (npm global, standalone or MCP setup echo " 🔄 graphifyy (CLI: graphify) — codebase knowledge graph (pipx, PreToolUse hook)" echo " 🔄 emil-design-eng — UI polish, animations, component craft (curl → symlink)" echo " 🔄 frontend-design — distinctive frontend interfaces, anti-AI-slop (anthropic-agent-skills)" +echo " 🔄 impeccable — /impeccable design verbs + 45-rule deterministic detector (npx impeccable detect)" echo " 🔄 design-motion-principles — motion/animation design, 3-designer lens (kylezantos)" echo " 🔄 darwin-skill — autonomous skill optimizer (npx skills, ~/.agents/skills/)" echo " 🔄 find-skills — skill discovery helper (npx skills, ~/.agents/skills/)" diff --git a/lib/design-gate.md b/lib/design-gate.md index 6991f57..2b2bfed 100644 --- a/lib/design-gate.md +++ b/lib/design-gate.md @@ -40,7 +40,7 @@ and if not, point at ONE command — `/profile design`. Tier does NOT change WHAT gets checked. Every non-trivial design tier draws from the one `design` profile — so the gate checks that profile's **design-core tools** (the `# GATE-BLOCK:` allowlist in `design.profile`: ui-ux-pro-max, -frontend-design, emil-design-eng, design-motion-principles, design-html, +frontend-design, emil-design-eng, design-motion-principles, impeccable, design-html, design-review, design-consultation, magic). The profile also bundles browser/plan/shotgun tooling and graphify for convenience; those never trip the gate. Motion (`design-motion-principles`) and static-HTML (`design-html`) are diff --git a/lib/profiles/design.profile b/lib/profiles/design.profile index d03de02..8610b7c 100644 --- a/lib/profiles/design.profile +++ b/lib/profiles/design.profile @@ -28,6 +28,7 @@ plan-ceo-review emil-design-eng external frontend-design external design-motion-principles external +impeccable external # Plugin (auto-toggle) ui-ux-pro-max plugin@ui-ux-pro-max-skill diff --git a/lib/profiles/full.profile b/lib/profiles/full.profile index 75fb1c1..0907157 100644 --- a/lib/profiles/full.profile +++ b/lib/profiles/full.profile @@ -78,6 +78,7 @@ guard emil-design-eng external frontend-design external design-motion-principles external +impeccable external ui-ux-pro-max plugin@ui-ux-pro-max-skill # pr-review-toolkit REMOVED from full (audit 2026-07-02 #12): heaviest # single plugin cost (~2.2k tokens of agent descriptions/session), useful diff --git a/lib/profiles/web-full.profile b/lib/profiles/web-full.profile index cad7e46..a5c5be5 100644 --- a/lib/profiles/web-full.profile +++ b/lib/profiles/web-full.profile @@ -48,6 +48,7 @@ qa-only emil-design-eng external frontend-design external design-motion-principles external +impeccable external ui-ux-pro-max plugin@ui-ux-pro-max-skill magic mcp diff --git a/lib/profiles/web.profile b/lib/profiles/web.profile index 32d6e65..d7a340b 100644 --- a/lib/profiles/web.profile +++ b/lib/profiles/web.profile @@ -36,6 +36,7 @@ web-validate personal emil-design-eng external frontend-design external design-motion-principles external +impeccable external # Plugin: UI/UX intelligence (auto-toggle) ui-ux-pro-max plugin@ui-ux-pro-max-skill diff --git a/link.sh b/link.sh index 20523d9..f46590b 100644 --- a/link.sh +++ b/link.sh @@ -71,7 +71,7 @@ if [ -d "$GSTACK_SRC/browse/dist" ]; then fi fi -EXTERNAL_SKILLS=(emil-design-eng frontend-design design-motion-principles) +EXTERNAL_SKILLS=(emil-design-eng frontend-design design-motion-principles impeccable) for _ext_skill in "${EXTERNAL_SKILLS[@]}"; do if [ -d "$REPO/skills-external/$_ext_skill" ]; then if [ -L "$CLAUDE/skills/$_ext_skill" ] && [ "$(readlink "$CLAUDE/skills/$_ext_skill")" = "$REPO/skills-external/$_ext_skill" ]; then diff --git a/plugins.lock.json b/plugins.lock.json index f42e496..4f6c114 100644 --- a/plugins.lock.json +++ b/plugins.lock.json @@ -37,5 +37,10 @@ "path": "skills/emil-design-eng/SKILL.md", "managed_by": "curl", "note": "Emil Kowalski's design engineering skill — UI polish, animations, component craft. Downloaded to skills-external/emil-design-eng/, symlinked by link.sh." + }, + "impeccable": { + "source": "npm:impeccable", + "version": "3.2.0", + "note": "Design anti-pattern detector (45 deterministic rules, CLI 'impeccable detect', exit 0/2) + /impeccable skill (23 verbs) by pbakaus. Pin = CLI version; the skill dist has its own release track fetched by 'skills install'. Pinned for audit reproducibility (LRN-077 class: a rules update silently changes audit output). Requires Node >= 24 — install step skips gracefully below that. Machine-owned: synced to skills-external/impeccable/ (gitignored), symlinked by link.sh." } } diff --git a/update-all.sh b/update-all.sh index 09f7b0c..2a0b5d2 100644 --- a/update-all.sh +++ b/update-all.sh @@ -341,6 +341,47 @@ else info "design-motion-principles not installed — skipping" fi +# ── Impeccable (design anti-pattern detector + skill) ── +echo "" +echo "── Updating impeccable..." +IMP_DIR="$REPO/skills-external/impeccable" +if [ ! -f "$IMP_DIR/SKILL.md" ]; then + info "impeccable not installed — skipping (run: make plugin)" +else + IMP_VER="" + if [ -f "$REPO/plugins.lock.json" ] && command -v python3 &>/dev/null; then + IMP_VER=$(python3 -c " +import json +with open('$REPO/plugins.lock.json') as f: + d = json.load(f) +print(d.get('impeccable',{}).get('version','latest')) +" 2>/dev/null || true) + fi + IMP_NODE=$(node -v 2>/dev/null | sed 's/^v//' | cut -d. -f1) + if [ -z "${IMP_NODE:-}" ] || [ "$IMP_NODE" -lt 24 ]; then + info "impeccable update skipped — needs Node >= 24 (found ${IMP_NODE:-none}); existing dist kept" + else + IMP_PKG="impeccable" + # Pin honored (LRN-077 class: a silent rules update changes audit + # output on unchanged code) — bump the pin deliberately, then update. + [ -n "$IMP_VER" ] && [ "$IMP_VER" != "latest" ] && IMP_PKG="impeccable@${IMP_VER}" + IMP_STAGE=$(mktemp -d) + if (cd "$IMP_STAGE" && npx -y "$IMP_PKG" skills install -y --providers=claude --scope=project --no-hooks >/dev/null 2>&1); then + IMP_SRC=$(find "$IMP_STAGE" -type d -name impeccable -path "*skills*" 2>/dev/null | head -1) + if [ -n "$IMP_SRC" ] && [ -f "$IMP_SRC/SKILL.md" ]; then + rm -rf "$IMP_DIR" + mv "$IMP_SRC" "$IMP_DIR" + ok "impeccable refreshed (CLI ${IMP_VER:-latest})" + else + warn "impeccable: installer produced no dist — existing kept" + fi + else + warn "impeccable refresh failed — existing dist kept" + fi + rm -rf "$IMP_STAGE" + fi +fi + # ── 7.5. Update external skills (npx skills) ── echo "" echo "── Updating external skills (npx skills)..."