- Detector: italic-serif display heroes and hero eyebrow chips
(#129, contributed by @vinaypokharkar).
- Live mode: durable session journal, status/resume/complete
commands (#125, contributed by @nqh-packages).
- Reference files: stripped "Remember:" closer chants, brochure-style
openers (12 files), and 419 em-dashes. Less context per command load,
less repetition the model reads past.
Refresh harness output dirs and plugin/ subtree.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(live): make live sessions recoverable
tired of live mode losing the plot when the browser moved faster than the agent.
now the state is boring: journal it, resume it, finish it.
---
- add durable live-session journal, checkpoint events, and status/resume/complete commands
- split browser session storage into a testable helper and harden accept/discard completion
- fix Astro live CSS preview mode and add recovery/live E2E coverage
- declare Bun as the package manager and add a Bun-native audit script
* fix(live): acknowledge fallback recovery states
* fix(live): flush recoverable handoffs promptly
* fix(live): keep recovery handoffs accurate
* fix(live): preserve poll reply metadata
* fix(live): treat event HTTP failures as failed sends
* fix(live): acknowledge manual completion through helper
* Add .impeccable project state paths
* Fix live disconnect recovery phase
* Refine live CSS authoring contract
* Test live CSS authoring guidance
* Harden live LLM E2E recovery
* Fix live recovery review issues
---------
Co-authored-by: Paul Bakaus <paulbakaus@pauls-mbp-3.lan>
Follow-up to #134, which scoped validateProse to user-facing copy and
left the LLM-facing skill files alone. Bring those to the same bar,
phased so hardening repetition stays intact.
- Em dashes: 419 → 0 across SKILL.md and 35 reference files. Each
replacement picks the right relationship (colon, semicolon, period,
or parens) instead of letting the dash hide the choice.
- Closer cleanup: deleted or rewrote the "Remember:" sermonettes that
were pure adjective chants (bolder/quieter/clarify/delight/extract/
colorize/layout/typeset/audit/adapt). Survivors that load-bear an
instruction now hand off to /impeccable polish instead of summarizing.
- Opener taglines: rewrote the "[Verb] [object] to [outcome]" brochure
openers in 12 older files to lead with the failure mode, the
strongest claim, or a directive. Newer files (live, brand, product,
audit, critique, harden) kept their existing openers.
- data-driven: rephrased the two technical hits in live.md so the
validator can stay strict on this term.
- validateSkillProse: narrow validator scoped to source/skills/impeccable/.
Em-dash check + the small denylist of phrases with no technical
reading. Hardening repetition and structural-prose rules are
deliberately not enforced — those need human judgment.
Test failure on detectUrl is pre-existing (puppeteer needs --no-sandbox
when running as root); unrelated to these changes.
https://claude.ai/code/session_013zZY6rbB1bS8z3D63rX5hW
Co-authored-by: Claude <noreply@anthropic.com>
Site copy was being called out as AI slop (specifically the word
"load-bearing"). Five-pass cleanup with a build validator to keep it
from creeping back.
Pass 1 — mechanical purge:
- Remove "load-bearing" from impeccable.md, brand.md, live.md,
iterate-live.md
- Remove "highest-leverage" from critique.md, typeset.md, designing
- Remove em dashes from all 9 slop-page rule cards
- Replace "leverage" verb in personas.md
Pass 2 — rewrite the worst offenders:
- Changelog v2.0 "Data-driven skill rewrite" entry: drop "data-driven",
"frontier models", "collapses into monoculture", "biggest unlock",
"reflex defaults"; name the actual mechanism
- README opener: drop "deeper expertise and more control"; replace with
three concrete differentiators (7 reference files, 23 commands, 27
detection rules)
- Neo Mirai case study opener: action-first, name the image model used
Pass 3 — editorials:
- Fix negation pivot in distill.md ("simplicity is not about ... It is
about ...")
Pass 4 — homepage why-panels:
- Foundation lead: name the 7 reference files specifically
- Language lead: show the discipline mapping with real command names
- Production-codebases panel: drop "Impeccable isn't a sketchpad"
negation pivot
- Ships-code panel: replace "is native to that world" with "runs there"
Pass 5 — STYLE.md and validator:
- New STYLE.md at root: editorial brief with 12 principles and the
enforced denylist (each rule with a rationale and a suggested
replacement)
- scripts/build.js: validateNoEmDashes becomes validateProse. Adds 21
phrase rules with rationales, catches the \`--\` em-dash substitute,
expands target list to site/pages, site/content, README.md,
README.npm.md
- CLAUDE.md: replace the em-dash section with a STYLE.md pointer and
document the two-content-tree footgun (content/site/ vs site/content/
must be edited in lockstep until they're unified)
Co-authored-by: Claude <noreply@anthropic.com>
* feat(detector): flag italic-serif display heroes and uppercase eyebrow chips (#127)
Two new rules covering the structural tells of late-2025/early-2026
AI-generated marketing pages.
- italic-serif-display: oversized italic serif (Fraunces, Recoleta,
Newsreader, Playfair, Cormorant, Tiempos, ...) as the primary hero
headline. Anchored on h1 (or h2 at >= 48px) with font-style: italic
and a serif primary face.
- hero-eyebrow-chip: uppercase letter-spaced label sitting as the
previousElementSibling of a hero h1 (font-size >= 48px). Bounded
text length 2-30 chars, letter-spacing >= 1.6px, font-size <= 14px.
The pill-chip variant (background + border-radius: 999px) falls out
of the same gates for free.
Both follow the existing icon-tile-stack pattern: pure check function +
browser DOM adapter + jsdom adapter, wired into both element loops.
Two-column fixtures (4 flag / 6 pass each) drive the jsdom tests.
Skill copy in source/skills/impeccable/reference/typography.md and
critique.md calls out the patterns by name. The italic-serif rule's
description acknowledges that editorial/magazine register may legitimately
want the pattern -- judge by context.
Closes#127
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Add sandbox gotchas for Codex
* Trim verbose detector skill copy
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Paul Bakaus <paulbakaus@pauls-mbp-3.lan>
The seven-lane list in Phase C departure mode was acting as a menu:
the model ran "furthest from editorial" as its selection criterion and
converged on Swiss-grid / Terminal / Industrial-signage every time.
Replaced with a brand-voice derivation process (read personality
words, imagine physical experiences, derive visual directions).
Explicitly names the failure mode so the model can't fall into it.
Phase D family-pass labels are now open-ended nouns, not a fixed
vocabulary list that re-anchored the same categories.
Reinforced parameter generation: Phase C (both modes) now requires
naming 2-3 parameter knobs alongside each variant during planning,
not as an afterthought. The freeform bias paragraph aligns with
the budget table (2-3 for large compositions, not 1-2) and frames
0-param heroes as mistakes, not judgment calls.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restructures live.md Step 4 into four phases: identity extraction
(Phase A, non-skippable, falls back to CSS variables and computed
styles when DESIGN.md is absent), default vs departure mode pick
(Phase B), variant planning by primary axis or aesthetic lane
(Phase C), and a family-level squint test before the sentence
pass (Phase D). Default mode preserves identity and varies
expression; departure mode only triggers on explicit signals
(PRODUCT.md anti-references calling out the current surface, or
the user prompt asking for departure).
Adds reflex-reject aesthetic lanes to brand.md as a parallel to
the existing font reflex-reject list. Editorial-typographic is
the first entry. Expands SKILL.md's category-reflex check to two
altitudes (theme + palette from category, then aesthetic family
from category + anti-references).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a configurable lookup path for PRODUCT.md / DESIGN.md / DESIGN.json so
they don't have to live at the project root. Resolution order (first match
wins):
1. process.env.IMPECCABLE_CONTEXT_DIR (absolute or relative to cwd)
2. cwd, when canonical or legacy files are at the root (back-compat)
3. Auto-fallback subdirs of cwd: .agents/context/ then docs/
4. cwd as a default "no context found" location
Existing layouts (PRODUCT.md / DESIGN.md at repo root) keep working unchanged
- step 2 preserves the current behaviour. The auto-fallback covers the two
most common conventions seen in the wild (.agents/context/ for AGENTS.md
auto-import setups, docs/ for the request in the issue) without needing any
configuration.
Changes:
- load-context.mjs: export resolveContextDir() and use it inside
loadContext(); add contextDir to the JSON output
- live-server.mjs: import resolveContextDir and read PRODUCT.md /
DESIGN.md / DESIGN.json from the resolved dir instead of process.cwd()
- SKILL.md: short note on the env var and fallback dirs in Setup -> Context
- tests/load-context.test.mjs: 19 cases covering env var, fallbacks,
legacy migration scope, and back-compat
Legacy .impeccable.md -> PRODUCT.md auto-migration stays scoped to cwd root;
fallback dirs are read-only as far as auto-rename is concerned.
Closes#119
* fix(live): switch live-poll to execFileSync, validate ids strictly
live-poll.mjs built the live-accept invocation with execSync and string
interpolation of event.id and event.variantId. Both fields originate in
the browser; validateEvent only checked truthiness, so shell metacharacters
in either field would land in the shell-parsed command.
Real exploitability is gated by the per-session token (loopback only,
unguessable UUID), so risk is low. The construction itself is structurally
unsafe though, and the fix is small.
- live-poll.mjs: execSync(string) → execFileSync('node', argv). Drops the
hand-rolled single-quote wrap for --param-values; execFileSync passes
each arg as a discrete argv slot, no shell parsing.
- live-server.mjs validateEvent: tighten id and variantId to match the
actual generator shapes (8 hex chars and 1-3 digit numeric strings).
Defense in depth so any value reaching downstream code is inert by
construction.
- live-server.test.mjs: add three regression tests covering accept/discard
rejection of shell-metachar ids and non-numeric variantIds. Update the
three existing fixture ids to match the new pattern.
Reported in #122.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: refresh pnpm-lock.yaml to match package.json
Cloudflare Pages runs pnpm install --frozen-lockfile and was failing on
ERR_PNPM_OUTDATED_LOCKFILE: the lockfile was missing entries for
@ai-sdk/anthropic, @ai-sdk/openai, @anthropic-ai/claude-agent-sdk,
@anthropic-ai/sdk, @google/genai, ai, modern-screenshot, zod, and had
stale specifiers for jsdom, marked, playwright, wrangler, puppeteer.
Drift was introduced when package.json was last edited without a lockfile
regen. Running pnpm install --lockfile-only resolves it; verified with
pnpm install --frozen-lockfile (clean install succeeds).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Paul Bakaus <paulbakaus@pauls-mbp-3.lan>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
On Windows checkouts, SKILL.md may have CRLF line endings, which caused
parseFrontmatter to fall back to {} and the build to prepend a fresh
frontmatter block while leaving the original one in the body. The result
was the dist Qoder SKILL.md shipping with two frontmatter blocks and
losing user-invocable / argument-hint / license / allowed-tools metadata.
Make the regex and YAML line split CRLF-tolerant. Regenerated tracked
.qoder/skills/impeccable/SKILL.md is now a single, well-formed
frontmatter block.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Qoder ships an Agent Skills system at .qoder/skills/{name}/SKILL.md with
slash-command invocation, mapping cleanly onto the existing transformer
pipeline. Adds Qoder as a 13th first-class harness:
- PROVIDER_PLACEHOLDERS entry in scripts/lib/utils.js (model, config_file,
ask_instruction, command_prefix) mirroring the Pi/Rovo Dev shape.
- PROVIDERS entry in scripts/lib/transformers/providers.js with
configDir=.qoder and the OpenCode/Claude Code frontmatter field set
(user-invocable, argument-hint, license, compatibility, metadata,
allowed-tools), since Qoder docs explicitly support those.
- transformQoder named export in scripts/lib/transformers/index.js for
test-spy parity (kept per CLAUDE.md guidance, even though build.js uses
PROVIDERS directly).
- .qoder added to PROVIDER_DIRS in bin/commands/skills.mjs so the CLI
detects existing Qoder installs.
- HARNESSES.md updated: official docs row, frontmatter support column,
directory structure row, and "Last verified" date bumped.
- DEVELOP.md reference link added.
- .github/ISSUE_TEMPLATE/feature_request.md and PULL_REQUEST_TEMPLATE.md
extended with Qoder in the provider checklists.
- Built .qoder/skills/impeccable/ tree committed (per CLAUDE.md harness
output dirs are tracked so npx skills can read them at install time).
The dynamic providers.test.js loop picks up Qoder automatically; all
non-prefix Qoder cases pass. The pre-existing Windows-only prefix-test
flake affects every provider equally and is out of scope for this PR.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>