mirror of
https://github.com/boxpositron/absolute-dotfiles.git
synced 2026-10-24 08:23:19 +00:00
Compare commits
18 Commits
cac5c1d036
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 3975a5b97d | |||
| 66d1d21011 | |||
| 5805f45358 | |||
| 161d205dfd | |||
| 721d7fbb0a | |||
| 786925b583 | |||
| dd90b462f5 | |||
| cd0ed704ab | |||
| 2c58626e0b | |||
| c9059d4867 | |||
| 46e7c8e04b | |||
| c155860ff1 | |||
| b2eca8e1a0 | |||
| adf62ac948 | |||
| d92041b6dd | |||
| 5fbdaa9810 | |||
| ea570af409 | |||
| 12f283e7c9 |
+1
-1
Submodule .config/nvim updated: 13ddbe2f56...d24b3ba574
@@ -0,0 +1,27 @@
|
||||
// Enter is caught before the editor submits, where omo handles /quit, so :q never fires prompt hooks
|
||||
// such as UserPromptSubmit. ctx.shutdown() waits for the agent to go idle, so :q mid-turn quits after it.
|
||||
import type { ExtensionAPI } from "@code-yeongyu/senpi";
|
||||
import { Key, matchesKey } from "@earendil-works/pi-tui";
|
||||
|
||||
const QUIT_COMMANDS = new Set([":q", ":q!", ":qa", ":wq"]);
|
||||
|
||||
export default function (pi: ExtensionAPI) {
|
||||
let unsubscribe: (() => void) | undefined;
|
||||
|
||||
pi.on("session_start", (_event, ctx) => {
|
||||
unsubscribe?.();
|
||||
unsubscribe = ctx.ui.onTerminalInput((data) => {
|
||||
if (!matchesKey(data, Key.enter) || !QUIT_COMMANDS.has(ctx.ui.getEditorText().trim())) {
|
||||
return undefined;
|
||||
}
|
||||
ctx.ui.setEditorText("");
|
||||
ctx.shutdown();
|
||||
return { consume: true };
|
||||
});
|
||||
});
|
||||
|
||||
pi.on("session_shutdown", () => {
|
||||
unsubscribe?.();
|
||||
unsubscribe = undefined;
|
||||
});
|
||||
}
|
||||
@@ -3,7 +3,8 @@
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"hooks": [
|
||||
{ "type": "command", "command": "~/.local/bin/omo-notify", "timeout": 10 }
|
||||
{ "type": "command", "command": "~/.local/bin/omo-notify", "timeout": 10 },
|
||||
{ "type": "command", "command": "~/.local/bin/owt hook", "timeout": 5 }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"app.interrupt": "ctrl+g",
|
||||
"app.editor.external": "ctrl+q"
|
||||
}
|
||||
@@ -110,6 +110,33 @@
|
||||
"reasoning": "high",
|
||||
"prompt_append": "Before substantive UI work, load frontend-workflow. Follow the product's design context, keep one writer per file set, inspect actual desktop and mobile screenshots, exercise the primary interaction, and report verification evidence. Stop when acceptance criteria pass."
|
||||
},
|
||||
// impeccable critique. A = design-director review (taste, heuristics): Opus 5.5 has the top Design Arena
|
||||
// website Elo of the models we run (1339 vs Sonnet 5.5 1322, Fable 5.1 1318; GPT-6 unranked, Oct 2026).
|
||||
// B = detector + browser evidence (mechanical tool use): GPT-6.1 Sol, with a Claude fallback so B stays available.
|
||||
"design-critique-a": {
|
||||
"models": [
|
||||
{
|
||||
"model": "anthropic-subscription/claude-opus-5-5",
|
||||
"reasoning": "xhigh"
|
||||
},
|
||||
{
|
||||
"model": "anthropic-subscription/claude-fable-5-1",
|
||||
"reasoning": "xhigh"
|
||||
}
|
||||
]
|
||||
},
|
||||
"design-critique-b": {
|
||||
"models": [
|
||||
{
|
||||
"model": "chatgpt-subscription/gpt-6.1-sol",
|
||||
"reasoning": "high"
|
||||
},
|
||||
{
|
||||
"model": "anthropic-subscription/claude-sonnet-5-5",
|
||||
"reasoning": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
"writing": {
|
||||
"models": [
|
||||
{
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
---
|
||||
description: Analyze vault structure and organization
|
||||
agent: general
|
||||
subtask: true
|
||||
---
|
||||
|
||||
# Analyze Vault Structure
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
description: Design, critique, audit, or polish a frontend interface with the impeccable skill
|
||||
argument-hint: "[shape · audit|critique · animate|bolder|colorize|delight|layout|overdrive|quieter|typeset · adapt|clarify|distill · harden|onboard|optimize|polish · init|document|extract|live|generate] [target]"
|
||||
requires-arguments: false
|
||||
---
|
||||
Read the impeccable skill at `~/.omo/agent/skills/impeccable/SKILL.md` and follow its `Setup` and `Commands` sections to handle: $ARGUMENTS
|
||||
@@ -1,7 +1,5 @@
|
||||
---
|
||||
description: Ingest local documentation files to Obsidian vault
|
||||
agent: general
|
||||
subtask: true
|
||||
---
|
||||
|
||||
# Ingest Notes
|
||||
-2
@@ -1,7 +1,5 @@
|
||||
---
|
||||
description: Preview which documentation files will be delegated to vault vs local
|
||||
agent: general
|
||||
subtask: true
|
||||
---
|
||||
|
||||
# Preview Notes Delegation
|
||||
@@ -1,7 +1,5 @@
|
||||
---
|
||||
description: Reorganize vault with AI-assisted suggestions
|
||||
agent: general
|
||||
subtask: true
|
||||
---
|
||||
|
||||
# Reorganize Notes
|
||||
@@ -1,7 +1,5 @@
|
||||
---
|
||||
description: Intelligently analyze and setup documentation architecture for the project
|
||||
agent: general
|
||||
subtask: true
|
||||
---
|
||||
|
||||
# Intelligent Documentation Setup
|
||||
@@ -1,7 +1,5 @@
|
||||
---
|
||||
description: Bidirectionally sync documentation files between local project and Obsidian vault
|
||||
agent: general
|
||||
subtask: true
|
||||
---
|
||||
|
||||
# Sync Notes
|
||||
@@ -1,7 +1,5 @@
|
||||
---
|
||||
description: Teleport documentation files from Obsidian vault to local project
|
||||
agent: general
|
||||
subtask: true
|
||||
---
|
||||
|
||||
# Teleport Notes
|
||||
-2
@@ -1,7 +1,5 @@
|
||||
---
|
||||
description: Validate .withcontextconfig.jsonc for errors and warnings
|
||||
agent: general
|
||||
subtask: true
|
||||
---
|
||||
|
||||
# Validate Notes Configuration
|
||||
@@ -0,0 +1,63 @@
|
||||
# Vendored agent skills
|
||||
|
||||
These skills are vendored copies, not submodules. `link-ai-configs.sh` links every
|
||||
directory here into `~/.omo/agent/skills/`, and all of them except
|
||||
`frontend-workflow` into `~/.claude/skills/`, so OmO and Claude Code read one
|
||||
canonical source instead of divergent copies.
|
||||
|
||||
They moved here from `.config/opencode/skills/` when OpenCode was retired; the
|
||||
OpenCode-era evaluation notes and rollback steps are in git history at
|
||||
`.config/opencode/README.md`.
|
||||
|
||||
## Provenance
|
||||
|
||||
| Skill | Upstream | Revision | License |
|
||||
|---|---|---|---|
|
||||
| `impeccable` | [pbakaus/impeccable](https://github.com/pbakaus/impeccable) (`.opencode` integration, tag `skill-v4.6.0`, engine 0.1.15) | `8a0e198da34ebc5b936a9d5975fb7a3b1cf353b7` | Apache 2.0, included |
|
||||
| `web-design-guidelines` | [vercel-labs/agent-skills](https://github.com/vercel-labs/agent-skills) (`skills/web-design-guidelines/SKILL.md`) | `063bee94c3f4df8453406c830b0a7df0f2860278` | per upstream |
|
||||
| ten marketing and copy skills | [coreyhaines31/marketingskills](https://github.com/coreyhaines31/marketingskills) (`skills/`) | `b9ba399dd88b082b926e261e8ccfb843d20aa066` | MIT, copied into each skill |
|
||||
| `frontend-workflow` | local | - | - |
|
||||
| `sound-design` | local | - | - |
|
||||
|
||||
The ten marketing skills are `product-marketing`, `copywriting`, `copy-editing`,
|
||||
`emails`, `cold-email`, `content-strategy`, `seo-audit`, `ai-seo`, `launch` and
|
||||
`social`.
|
||||
|
||||
## Local modifications
|
||||
|
||||
- **`impeccable`**: every `.opencode/skills/impeccable/scripts/impeccable` command
|
||||
path was rewritten to `~/.omo/agent/skills/impeccable/scripts/impeccable`,
|
||||
including the `allowed-tools` Bash entry and the base-directory fallback in
|
||||
`SKILL.md`. Without this the detector and live-server verbs do not resolve under
|
||||
OmO. `reference/critique.md` also carries an OmO routing line that sends
|
||||
Assessment A to the `design-critique-a` category and Assessment B to
|
||||
`design-critique-b` (defined in `.config/omo/omo.jsonc`). `LICENSE` comes from the
|
||||
upstream repository root, because the `.opencode` directory ships without one. The
|
||||
engine binary is not vendored: on first run, `scripts/impeccable` downloads the
|
||||
version named in `scripts/VERSION` into `~/.impeccable/bin/<version>/` and checks it
|
||||
against the published checksum.
|
||||
- **`web-design-guidelines`**: unchanged. It fetches the current
|
||||
[Web Interface Guidelines](https://raw.githubusercontent.com/vercel-labs/web-interface-guidelines/main/command.md)
|
||||
when invoked, so its rule feed is intentionally not pinned.
|
||||
- **marketing skills**: unchanged. They read a per-project
|
||||
`.agents/product-marketing.md` for product context, and a project's own copy
|
||||
skill overrides their generic direct-response advice. Links to the upstream
|
||||
repo's top-level `tools/` directory were not vendored and resolve to nothing.
|
||||
|
||||
## Upgrading
|
||||
|
||||
Re-copy the same directories from a newer upstream revision, update the revision
|
||||
in the table above, then re-apply the local modifications listed for that skill
|
||||
and rerun `link-ai-configs.sh`. For `impeccable`, re-apply the path rewrite:
|
||||
|
||||
```bash
|
||||
cd .config/omo/skills/impeccable
|
||||
rg -l -F '.opencode/skills/impeccable/scripts' . \
|
||||
| xargs sed -i '' 's#\.opencode/skills/impeccable/scripts#~/.omo/agent/skills/impeccable/scripts#g'
|
||||
```
|
||||
|
||||
This pattern also covers the base-directory fallback in `SKILL.md`, which ends at
|
||||
`scripts` rather than `scripts/impeccable`. Keep `LICENSE` when re-copying (for
|
||||
example `rsync -a --delete --exclude LICENSE <upstream>/.opencode/skills/impeccable/ .`),
|
||||
and re-add the OmO routing line after the "Delegate Assessment A and Assessment B"
|
||||
paragraph in `reference/critique.md`.
|
||||
+1
-1
@@ -30,7 +30,7 @@ Delegation handoff must include: purpose/action; context and reference paths; ap
|
||||
|
||||
Run the affected build/type/tests. Start the app on loopback using its documented command. Inspect at desktop and mobile widths, with an intermediate width when breakpoints or layout complexity warrant it. Use product targets, or proposed defaults 1280×900, 390×844, and 768×900. Record URL, viewport, state, and screenshot path.
|
||||
|
||||
After capture, check whether the tool response contains an actual image. If it returns only a path, use the native image-capable `read` tool to open the PNG, or attach it to the GPT session (`opencode run --model <existing-GPT-model> --file <screenshot> -- <inspection-prompt>`). Keep existing model identifiers; do not invent one. Describe concrete visible details to demonstrate receipt. DOM checks are complementary, not substitutes. If the model cannot see pixels, report the exact failing delivery step and do not claim visual QA.
|
||||
After capture, check whether the tool response contains an actual image. If it returns only a path, use the native image-capable `read` tool to open the PNG, or hand the screenshot path to a GPT worker through `task(category: "visual-engineering")` and have it open the PNG with its own image-capable `read` tool. Keep existing model identifiers; do not invent one. Describe concrete visible details to demonstrate receipt. DOM checks are complementary, not substitutes. If the model cannot see pixels, report the exact failing delivery step and do not claim visual QA.
|
||||
|
||||
## 5. Bounded critique and correction
|
||||
|
||||
+5
-4
@@ -1,13 +1,13 @@
|
||||
---
|
||||
name: impeccable
|
||||
description: Use when the user wants to design, redesign, shape, critique, audit, polish, clarify, distill, harden, optimize, adapt, animate, colorize, extract, or otherwise improve a frontend interface. Covers websites, landing pages, dashboards, product UI, app shells, components, forms, settings, onboarding, and empty states. Handles UX review, visual hierarchy, information architecture, cognitive load, accessibility, performance, responsive behavior, theming, anti-patterns, typography, fonts, spacing, layout, alignment, color, motion, micro-interactions, UX copy, error states, edge cases, i18n, and reusable design systems or tokens. Also use for bland designs that need to become bolder or more delightful, loud designs that should become quieter, live browser iteration on UI elements, or ambitious visual effects that should feel technically extraordinary. Not for backend-only or non-UI tasks.
|
||||
version: 4.3.1
|
||||
version: 4.6.0
|
||||
user-invocable: true
|
||||
argument-hint: "[shape · audit|critique · animate|bolder|colorize|delight|layout|overdrive|quieter|typeset · adapt|clarify|distill · harden|onboard|optimize|polish · init|document|extract|live|generate] [target]"
|
||||
license: Apache 2.0
|
||||
allowed-tools:
|
||||
- Bash(npx impeccable *)
|
||||
- Bash(.opencode/skills/impeccable/scripts/impeccable *)
|
||||
- Bash(~/.omo/agent/skills/impeccable/scripts/impeccable *)
|
||||
---
|
||||
|
||||
This skill gives you the tools and permission to create design that earns to be called out-of-distribution craft: Whereas before, your design work would have been safe, timid and measured, you now approach every design task as an award-winning design director with impeccable understanding for what makes exceptional design work: production-grade code, peak creativity, a clear POV, deep understanding of the needs of the client and users, and exceptional craft.
|
||||
@@ -19,7 +19,7 @@ Core principles:
|
||||
|
||||
## Setup
|
||||
|
||||
1. Run `<skill-base-dir>/scripts/impeccable context` once per session, where `<skill-base-dir>` is the directory that contains this SKILL.md (the skill folder, not a plugin root two levels above it); keep cwd at the user's project. That base directory resolves every `.opencode/skills/impeccable/scripts/impeccable <verb>` command in this skill and its references, and `.opencode/skills/impeccable/scripts` is the fallback only when the runtime reports no base directory. On a Windows shell without `sh`, call `.opencode/skills/impeccable/scripts/impeccable.cmd` instead. The launcher runs a self-contained binary that ships next to it or is downloaded once on first run; no Node or other runtime is required. Pass a named source file or route as `--target <path>`. It loads PRODUCT.md, DESIGN.md, the matching surface brief, and native-platform guidance when applicable; follow its directives and do not rerun it.
|
||||
1. Run `<skill-base-dir>/scripts/impeccable context` once per session, where `<skill-base-dir>` is the directory that contains this SKILL.md (the skill folder, not a plugin root two levels above it); keep cwd at the user's project. That base directory resolves every `~/.omo/agent/skills/impeccable/scripts/impeccable <verb>` command in this skill and its references, and `~/.omo/agent/skills/impeccable/scripts` is the fallback only when the runtime reports no base directory. On a Windows shell without `sh`, call `~/.omo/agent/skills/impeccable/scripts/impeccable.cmd` instead. The launcher runs a self-contained binary that ships next to it or is downloaded once on first run; no Node or other runtime is required. Pass a named source file or route as `--target <path>`. It loads PRODUCT.md, DESIGN.md, the matching surface brief, and native-platform guidance when applicable; follow its directives and do not rerun it.
|
||||
2. Load the request's playbook: its Commands-table reference for an explicit/implied sub-command, or [reference/new-work.md](reference/new-work.md) for a new surface or replacement visual world. Inspect target and incumbent visual truth before editing. When the app cannot run, start with committed visual-regression goldens or screenshot fixtures; verify target and freshness against current tokens, CSS, components, or assets, resolve conflicts, and compare theme/variant captures.
|
||||
3. After resolving analysis and direction, read [reference/craft-floor.md](reference/craft-floor.md) immediately before any UI edit, including small refinements. It carries the quality floor, the absolute bans, and the reflexes no detector catches. Do not load it for planning-only work.
|
||||
|
||||
@@ -29,6 +29,7 @@ Core principles:
|
||||
|
||||
- **The brief wins.** Honor pinned aesthetics, eras, materials, fonts, and palettes even when they conflict with a saturated-pattern warning. Redirecting a clear brief toward your taste is failure.
|
||||
- **Refinement preserves; redesign replaces.** Refinement keeps the incumbent identity, behavior, copy, and everything outside scope. Ask before replacing factual copy or adding claims. Redesign keeps product truth, content, function, native affordances, and constraints, but treats the old look as evidence and anti-reference; choose a replacement world in new-work and replace DESIGN.md. Never split the difference into polish on the discarded look.
|
||||
- **Loaded symbols stay out of the decoration.** A subject's world does not license emblems tied to militarism, supremacy, or hate movements as motifs, badges, or ornament, such as the Rising Sun flag's rays, the Confederate battle flag, or Nazi-era insignia and their stylised variants; reach for that world's neutral forms instead. Content that documents such a symbol as fact stays as it is.
|
||||
- **Visual authority is evidence, not a filename.** Missing DESIGN.md alone does not make a project greenfield; new-work decides whether to preserve, expand, or replace the incumbent world.
|
||||
|
||||
## Modes
|
||||
@@ -81,7 +82,7 @@ Routing:
|
||||
|
||||
After init writes PRODUCT.md, resume without rerunning `impeccable context`; init loads the native platform reference itself when the platform it recorded is `ios`, `android`, or `adaptive`.
|
||||
|
||||
**Pin / Unpin:** `.opencode/skills/impeccable/scripts/impeccable pin <pin|unpin> <command>` creates or removes a standalone `/<command>` shortcut. Report the script's result concisely; relay stderr verbatim on error.
|
||||
**Pin / Unpin:** `~/.omo/agent/skills/impeccable/scripts/impeccable pin <pin|unpin> <command>` creates or removes a standalone `/<command>` shortcut. Report the script's result concisely; relay stderr verbatim on error.
|
||||
|
||||
**Hooks:** `/impeccable hooks <on|off|status|ignore-rule|ignore-file|ignore-value|reset>` manages the design detector hook for this project (auto-runs the detector after UI file edits and surfaces findings). Load [reference/hooks.md](reference/hooks.md) when the user invokes it with any argument.
|
||||
|
||||
+2
-2
@@ -69,8 +69,8 @@ Run the bundled detector and verify each finding in context. Look for repeated i
|
||||
|---|-----------|-------|-------------|
|
||||
| 1 | Accessibility | ? | [most critical a11y issue or "--"] |
|
||||
| 2 | Performance | ? | |
|
||||
| 3 | Responsive Design | ? | |
|
||||
| 4 | Theming | ? | |
|
||||
| 3 | Theming | ? | |
|
||||
| 4 | Responsive Design | ? | |
|
||||
| 5 | Implementation Integrity | ? | |
|
||||
| **Total** | | **??/20** | **[Rating band]** |
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# Plan and asset review
|
||||
|
||||
Use this checkpoint on comp-led builds once every raster region has its plate and the plates gate has scored them, before any page code exists. The approved comp is the reference. The user reviews two things: the plates that will ship, and the production plan for everything else, meaning which regions code draws. A painted region planned as code is the most expensive mistake a comp-led build makes, and this is where the user catches it. Text, controls and chrome are judged later, in the assembled first viewport.
|
||||
|
||||
## Plan, capture, serve
|
||||
|
||||
Run `~/.omo/agent/skills/impeccable/scripts/impeccable component-review plan`. It writes `.impeccable/review/components.json` from the measured spec, the comp and the plate files, and refuses, naming each one, while any raster region lacks its plate. Never write or edit that file for this stage: the packet is derived from the spec, so every change belongs in the regions file.
|
||||
|
||||
If the harness exposes `component_review`, call it with `manifest_path` set to `.impeccable/review/components.json`. The host captures, presents the review and returns the user's decisions. A suspended request is waiting for the user; it is not a failed build or an approval.
|
||||
|
||||
Otherwise run `~/.omo/agent/skills/impeccable/scripts/impeccable component-review capture --manifest .impeccable/review/components.json`, then start `~/.omo/agent/skills/impeccable/scripts/impeccable component-review serve --session <returned session>` in the background. Open the URL it prints in the available browser and wait for the user; `serve` exits 0 once they submit. Read the decisions with `~/.omo/agent/skills/impeccable/scripts/impeccable component-review status --session <id>`; `~/.omo/agent/skills/impeccable/scripts/impeccable component-review verify --manifest .impeccable/review/components.json` confirms approval and refuses pending, needs-work and stale input. Never submit the page or write a receipt on the user's behalf.
|
||||
|
||||
`serve` exits 2 when this session has no browser (the same signal as the decision page) and 4 when it closes after 30 idle minutes without a decision. Either way no one is reviewing: stop waiting, do not approve anything yourself, and do not build past this checkpoint. End the run and report the plan and asset review as pending with its session ID, so the user can resume it. A waiting review is pending work, not a completed build.
|
||||
|
||||
## Act on the receipt
|
||||
|
||||
Apply the user's decisions as given, never your own favorable verdict in their place.
|
||||
|
||||
- **approve**: once every item is approved and the inventory is confirmed, advance to the hero.
|
||||
- **revise** (a plate): regenerate that plate at the same path with the user's feedback.
|
||||
- **revise with split** (an asset): replace that region in the regions file with its layers: a frame plate with a transparent opening (kind `plate`, same box), the content as its own `image` region at the opening's box, and each moving part (a shutter, a door) as its own plate. Name each layer after the original region, as `<id>-frame`, `<id>-view` or `<id>-shutter-left`, so the next round shows it as part of the user's request. Rerun `~/.omo/agent/skills/impeccable/scripts/impeccable comp-spec --comp <comp.png> --regions <regions.json>` and produce the plates.
|
||||
- **revise** (a plan item): change the regions file as the feedback says (resize or extend a raster region, split material into its own plate region, or adjust the code region), rerun `~/.omo/agent/skills/impeccable/scripts/impeccable comp-spec --comp <comp.png> --regions <regions.json>`, and produce any new plates.
|
||||
- **reclassify** (a code region): in the regions file, change that region's `kind` to the one the user chose and rewrite its `note` to describe the material. Rerun `~/.omo/agent/skills/impeccable/scripts/impeccable comp-spec --comp <comp.png> --regions <regions.json>`, then produce the new plates, with the asset producer when subagents are available.
|
||||
- **missing**: add the region to the regions file, rerun `~/.omo/agent/skills/impeccable/scripts/impeccable comp-spec --comp <comp.png> --regions <regions.json>`, and produce its plate if it is raster.
|
||||
|
||||
Then run `plan`, `capture` and `serve` again. Unchanged decisions carry over, so the user sees only what changed. Any spec change, or a plate replaced after acceptance, needs a new round; the build-phase gate stays closed until the review of the current spec is accepted.
|
||||
|
||||
## Assemble and review
|
||||
|
||||
Build the first viewport from the approved plates and plan, and run the hero gate. Human review does not waive its integrity checks. After three failed hero attempts, or three failed responsive attempts before any first viewport is accepted, stop iterating and present the first-viewport review with the current build; the user's eye settles what the readings could not.
|
||||
|
||||
Present a second manifest at `.impeccable/review/hero.json`. You write this one, and its shape is fixed:
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"stage": "hero",
|
||||
"id": "hero",
|
||||
"title": "First viewport",
|
||||
"comp": {"path": ".impeccable/mocks/comp.png", "width": 1536, "height": 1024},
|
||||
"components": [{
|
||||
"id": "first-viewport",
|
||||
"name": "First viewport",
|
||||
"medium": "HTML / CSS",
|
||||
"note": "Assembled first viewport",
|
||||
"box": {"x": 0, "y": 0, "w": 1, "h": 1},
|
||||
"preview": {"kind": "page", "path": "index.html"},
|
||||
"dependencies": ["styles.css", "assets/plates/sky.png", "fonts/display.woff2"]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
- `schemaVersion` is 2. Version 3 is the plan review packet and requires stage `components`. `codeRegions` and `specSha256` exist only in version 3 and are refused here. `reviewGroup` is refused too: version 3 rejects it, and any other version accepts it only on a page preview in a `components`-stage manifest, never in a hero manifest.
|
||||
- `comp.path` is the `comp` value in `.impeccable/build/spec.json`, and `width` and `height` are that PNG's pixel size.
|
||||
- Exactly one component, with `box` exactly `{"x": 0, "y": 0, "w": 1, "h": 1}` and `name`, `medium` and `note` as strings.
|
||||
- `preview.path` is the page entry the build gates (`artifact` in `.impeccable/build/state.json`).
|
||||
- `dependencies` lists every other file the page loads (stylesheets, scripts, plates, images, fonts) as bare strings. Every path, here and above, is project-relative and plain: no leading `./` or `/`, no `..`, no URL, no `?`, `#`, `%`, `:` or backslash. A request to a file missing from this list, or to another host, fails the capture.
|
||||
|
||||
The reference stays the approved comp. Call the same host review tool, or run `capture`, `serve` and `verify` with this manifest. Needs-work feedback starts another assembly round.
|
||||
|
||||
Acceptance closes human review for this build: never request plan, asset or assembly approval again. While the page renders what the user accepted, the hero score, the palette check and every numeric reading are advisories; material vetoes still hold (a missing or unreferenced plate, an SVG illustration, an organic clip, a clipped plate, invented ink, failed rendered presence). A text, control or chrome region the accepted screenshot also lacks is settled by the acceptance; a plate it lacks is a question for the user that the gate's reason spells out: do not move off what they accepted on your own, but carry out their answer, including placing the plate. When the capture no longer matches the accepted screenshot, restore what the user accepted; until then the readings apply. Complete the rest of the page, responsive behavior, finish checks and documentation with the accepted first viewport as the visual direction. This is first-viewport calibration, not a claim that the user reviewed the rest of the page. Shared stylesheet edits do not reopen approval. Preserve the accepted direction; a later explicit user change is a new task.
|
||||
|
||||
Assembled-page capture executes inline and declared local scripts from the pinned inputs. Network APIs, frames and workers are unavailable; the initial viewport must settle before capture. Keep the real page and declare its scripts rather than removing behavior to pass review.
|
||||
+15
-10
@@ -4,11 +4,11 @@ Resolve one stable target, run two independent assessments, synthesize a design
|
||||
|
||||
### Hard Invariants
|
||||
|
||||
- Assessment A (design review) and Assessment B (detector/browser evidence) are both required.
|
||||
- Assessment A and B MUST run as two isolated sub-agents whenever a sub-agent/Task tool is exposed. Running them inline in this context is "possible" but is NOT permitted; it is a degraded run. Inline is allowed ONLY when no sub-agent tool exists (or the user declined, on harnesses that ask).
|
||||
- Assessment A (design review) and Assessment B (detector/browser evidence) are both required, except on a native platform (see Assessment Orchestration).
|
||||
- Assessment A and B MUST run as two isolated sub-agents whenever a sub-agent/Task tool is exposed. Running them inline in this context is "possible" but is NOT permitted; it is a degraded run. Inline is allowed ONLY when no sub-agent tool exists (or the user declined, on harnesses that ask). Native platforms run A alone (see Assessment Orchestration).
|
||||
- If you degrade for any reason, the report's first line MUST be a banner: `⚠️ DEGRADED: single-context (<reason>)`. A silent degraded critique is a failed critique.
|
||||
- Assessment A must finish before detector findings enter the parent synthesis context. Detector output is deterministic, but it still anchors judgment.
|
||||
- A skipped detector is a failed critique run unless `impeccable detect` is missing or crashes after a real attempt.
|
||||
- A skipped detector is a failed critique run unless `impeccable detect` is missing or crashes after a real attempt, or the platform is native (see Assessment Orchestration).
|
||||
- Viewable targets require browser inspection when available.
|
||||
- Any local server started only for critique visualization must run in the background, have a recorded stop method, and be stopped before final reporting unless the user asks to keep it.
|
||||
- Do not claim a user-visible overlay exists unless script injection succeeded and the detector ran in the page.
|
||||
@@ -23,15 +23,19 @@ Resolve one stable target, run two independent assessments, synthesize a design
|
||||
- "this page" -> the current URL or source file
|
||||
2. **Confirm the target slugs cleanly**:
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable critique-storage slug "<resolved-path-or-url>"
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable critique-storage slug "<resolved-path-or-url>"
|
||||
```
|
||||
Every later command also accepts the resolved target directly and derives the same slug internally; never hand-write a slug. If this exits non-zero, skip persistence and trend for this run, but continue the critique.
|
||||
3. **Read `.impeccable/critique/ignore.md`** if it exists. Drop matching findings silently; it is the only prior-run input critique consumes.
|
||||
|
||||
### Assessment Orchestration
|
||||
|
||||
**Native platforms** (`ios` / `android` / `adaptive`): Assessment B does not apply, because `impeccable detect` and the browser overlay read only web markup. Run Assessment A alone in this context and skip both sub-agent gates below, the Codex permission question included: with no B there is nothing to isolate A from, so this is the complete native method and carries no degraded banner. Do not run `impeccable detect` on native source; its empty result reads as clean.
|
||||
|
||||
Delegate Assessment A and Assessment B to separate sub-agents. They must not see each other's output. Do not show findings to the user until synthesis.
|
||||
|
||||
OmO routing: when the task tool accepts a category, spawn Assessment A with `category: "design-critique-a"` and Assessment B with `category: "design-critique-b"`. Never pass `model` with a category.
|
||||
|
||||
Sub-agent gate (all harnesses):
|
||||
- Unless a harness-specific gate below overrides this, spawn A and B as two isolated, parallel sub-agents whenever a sub-agent/Task tool is exposed. This is the default and is mandatory; do not run them inline because it is faster.
|
||||
- "Unavailable" means exactly one thing: no sub-agent/Task tool is exposed in this session (or, on harnesses that ask, the user declined). It does not mean inconvenient.
|
||||
@@ -55,11 +59,11 @@ Return: design-specificity verdict, heuristic scores, cognitive load, emotional
|
||||
|
||||
### Assessment B: Detector + Browser Evidence
|
||||
|
||||
Run the bundled detector and browser visualization evidence. Assessment B is mandatory and must remain isolated from Assessment A until both are complete.
|
||||
Run the bundled detector and browser visualization evidence. On web, Assessment B is mandatory and must remain isolated from Assessment A until both are complete.
|
||||
|
||||
CLI scan:
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable detect --json [target]
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable detect --json [target]
|
||||
```
|
||||
|
||||
- Pass markup files/directories as `[target]`; do not pass CSS-only files.
|
||||
@@ -73,7 +77,7 @@ Browser visualization is required for a viewable target when browser automation
|
||||
1. Create a fresh tab and navigate. Prefer the harness's native/browser-canvas screenshot path before hand-rolling a Playwright/Puppeteer script; only fall back to a custom script when no native browser tool is exposed.
|
||||
2. Preflight mutable injection by setting `document.title` and appending a `<script>` tag. Read-only evaluate APIs do not count.
|
||||
3. If mutation is unavailable, skip live server, browser presentation, and injection; report fallback signal.
|
||||
4. If mutation is available, start `.opencode/skills/impeccable/scripts/impeccable live-server --background`, present the browser if supported, label `[Human]`, scroll top, inject `http://localhost:PORT/detect.js`, wait 2-3 seconds, read `impeccable` console messages, then stop the live server.
|
||||
4. If mutation is available, start `~/.omo/agent/skills/impeccable/scripts/impeccable live-server --background`, present the browser if supported, label `[Human]`, scroll top, inject `http://localhost:PORT/detect.js`, wait 2-3 seconds, read `impeccable` console messages, then stop the live server.
|
||||
5. For multi-view targets, inject on 3-5 representative pages.
|
||||
|
||||
Return: CLI findings JSON/counts, browser console findings if applicable, false positives, and skipped/failed browser steps with concrete reasons.
|
||||
@@ -93,6 +97,7 @@ Structure your feedback as a design director would:
|
||||
The report's first line MUST declare how the assessments were run, so a degraded run is never silent:
|
||||
- Dual-agent: `Method: dual-agent (A: <agent-id> · B: <agent-id>)`
|
||||
- Degraded: `⚠️ DEGRADED: single-context (<reason, e.g. no sub-agent tool exposed>)`
|
||||
- Native: `Method: design review only (detector not applicable, native platform)`
|
||||
|
||||
#### Design Health Score
|
||||
> *Consult the [Heuristics Scoring Guide](#heuristics-scoring-guide) section below.*
|
||||
@@ -125,7 +130,7 @@ Be honest with scores. A 4 means genuinely excellent. Most real interfaces score
|
||||
|
||||
**LLM assessment**: Your unanchored evaluation of design specificity. Cover overall coherence, structural sameness, category-interchangeable choices, and missed opportunities for product character.
|
||||
|
||||
**Deterministic scan**: Summarize what the automated detector found, with counts and file locations. Note any additional issues the detector caught that you missed, and flag any false positives.
|
||||
**Deterministic scan**: Summarize what the automated detector found, with counts and file locations. Note any additional issues the detector caught that you missed, and flag any false positives. On a native platform, write `not applicable (native platform)` instead.
|
||||
|
||||
**Visual overlays** (if injection succeeded): Tell the user that overlays are now visible in the **[Human]** tab in their browser, highlighting the detected issues. Summarize what the console output reported. If browser visualization was attempted but injection failed, say that no reliable user-visible overlay is available and report the fallback signal instead.
|
||||
|
||||
@@ -195,7 +200,7 @@ Skip this step if the Setup slug was null (vague or root-level target).
|
||||
2. **Pass the structured metadata** through `IMPECCABLE_CRITIQUE_META` (JSON), then run the write command:
|
||||
```bash
|
||||
IMPECCABLE_CRITIQUE_META='{"target":"<user phrasing>","total_score":<n>,"max_score":<n>,"na_heuristics":"<comma-separated numbers, or empty>","p0_count":<n>,"p1_count":<n>}' \
|
||||
.opencode/skills/impeccable/scripts/impeccable critique-storage write "<resolved target>" <body-file>
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable critique-storage write "<resolved target>" <body-file>
|
||||
```
|
||||
`max_score` is the applicable maximum from the heuristic table (40 when every heuristic applied), so a later run can tell a renormalized total from a full one. For a local file target, the helper also records an exact content fingerprint so polish can distinguish the assessed bytes from later edits without relying on Git state or timestamps. The helper prints the absolute path it wrote. Leave that file on disk. Polish closes it; this run does not.
|
||||
|
||||
@@ -203,7 +208,7 @@ Skip this step if the Setup slug was null (vague or root-level target).
|
||||
|
||||
4. **Read the trend** for context:
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable critique-storage trend "<resolved target>" 5
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable critique-storage trend "<resolved target>" 5
|
||||
```
|
||||
This returns a JSON array of the last 5 frontmatter entries (including the one you just wrote).
|
||||
|
||||
+9
-4
@@ -11,7 +11,11 @@ Do not redesign. Preserve the reference's visual role, silhouette, palette, ligh
|
||||
|
||||
## Decision Comps
|
||||
|
||||
When the parent hands you a decision card packet instead of an approved mock, the job is one comp: one card, one file, written to the card's declared `comp` path the moment it renders. The parent runs several of you in parallel, one per card, so this card is your entire contract; generate first, plan never, because the file on disk is the deliverable and the decision page is waiting on it. Work from the card's structured fields and PRODUCT.md alone; report a card too thin to brief a comp, never pad it from imagination. Render the card's direction as a north-star comp at full fidelity: the requested surface's first viewport, prompt led by the surface's own structure (regions named in order with their scale relationships, never the world's atmosphere), fully committed in the card's own palette, type character, and material world. A native app or mobile-first surface is a portrait frame at its device viewport, never a landscape default. Every sibling renders at the same full fidelity in its own grammar, one surface, one aspect; equal commitment keeps the comparison honest. Real product name and real content only; never invent commercial claims, prices, benchmarks, or dates PRODUCT.md does not carry. Exclusions bind those claims, never a medium the card's own world has not excluded: a subject that lives in photographs keeps its photographs. Write the prompt sidecar beside the file. Return one line naming the path and any deviation, nothing more. Everything below this section is the asset-production job; none of it applies to a decision-comp run.
|
||||
When the parent hands you a decision card packet instead of an approved mock, the job is one comp: one card, one file, written to the card's declared `comp` path the moment it renders. The parent runs several of you in parallel, one per card, so this card is your entire contract; generate first, plan never, because the file on disk is the deliverable and the decision page is waiting on it. Work from the card's structured fields and PRODUCT.md alone; report a card too thin to brief a comp, never pad it from imagination. Render the card's direction as a north-star comp at full fidelity: the requested surface's first viewport, prompted in the short shape visualize.md gives (the product and the visitor's job with real content, what leads, the parts in reading order, the frame), with the look taken from the card's world: its card images attached as references when the packet names them, otherwise two to four sentences of concrete look. A native app or mobile-first surface is a portrait frame at its device viewport, never a landscape default. Every sibling renders at the same full fidelity in its own grammar, one surface, one aspect; equal commitment keeps the comparison honest. Real product name and real content only; never invent commercial claims, prices, benchmarks, or dates PRODUCT.md does not carry. Exclusions bind those claims, never a medium the card's own world has not excluded: a subject that lives in photographs keeps its photographs. Write the prompt sidecar beside the file. Return one line naming the path and any deviation, nothing more. Everything below this section is the asset-production job; none of it applies to a decision-comp run.
|
||||
|
||||
## Review handoff
|
||||
|
||||
Return the actual files and any unresolved drift to the parent for the user's plan and asset review in [component-review.md](../component-review.md). A parent or automatic visual check is not a substitute for that human checkpoint. The parent may call you again after it: for regions the user reclassified from code to raster (the spec now lists them with a plate path), or for plates the user asked to revise, with their feedback as the prompt notes. Produce only those, preserve unchanged assets, and hand off real files as before; never self-approve. This checkpoint does not apply to the Decision Comps job above.
|
||||
|
||||
## Input Contract
|
||||
|
||||
@@ -25,10 +29,11 @@ Every region with `medium: raster` in the spec ships as a plate at its `plate` p
|
||||
|
||||
Per region, in the spec's order:
|
||||
|
||||
1. `.opencode/skills/impeccable/scripts/impeccable comp-spec --crop <id>` writes the reference crop under `.impeccable/build/crops/`.
|
||||
2. Choose the background from the approved region: an isolated figure, object, or line drawing on the page ground is a **transparent cutout**; a photograph, full-frame illustration, or texture stays **opaque**. Save `.opencode/skills/impeccable/scripts/impeccable comp-spec --plate-prompt <id> --background transparent` to a UTF-8 prompt file for a cutout; use `--background opaque` otherwise. The transparent prompt preserves reference placement and clear margins, white paint, fine edges, and interior holes.
|
||||
3. Produce the plate at its exact spec `plate` path. Create the output directory first and choose a supported output size matching the region's aspect, at least 1.5x its pixel dimensions. Prefer the harness-native image tool with the crop as input and the saved prompt; request a transparent PNG for cutouts, then run `.opencode/skills/impeccable/scripts/impeccable embed-prompt <plate> --prompt-file <prompt.txt>` (if you refine the prompt, save and embed the exact text sent). With the API fallback, run `.opencode/skills/impeccable/scripts/impeccable generate-image --ref <crop.png> --prompt-file <prompt.txt> --out <plate.png> --size <WxH> --quality high --background transparent` for a cutout, or `--background opaque` otherwise. The API fallback embeds the prompt and records the background in the sidecar. The output must be PNG; the fallback requests native alpha and performs no chroma-keying.
|
||||
1. `~/.omo/agent/skills/impeccable/scripts/impeccable comp-spec --crop <id>` writes the reference crop under `.impeccable/build/crops/`.
|
||||
2. Choose the background from the approved region: an isolated figure, object, or line drawing on the page ground is a **transparent cutout**; a photograph, full-frame illustration, or texture stays **opaque**. Save `~/.omo/agent/skills/impeccable/scripts/impeccable comp-spec --plate-prompt <id> --background transparent` to a UTF-8 prompt file for a cutout; use `--background opaque` otherwise. The transparent prompt preserves reference placement and clear margins, white paint, fine edges, and interior holes.
|
||||
3. Produce the plate at its exact spec `plate` path. Create the output directory first and choose a supported output size matching the region's aspect, at least 1.5x its pixel dimensions. Prefer the harness-native image tool with the crop as input and the saved prompt; request a transparent PNG for cutouts, then run `~/.omo/agent/skills/impeccable/scripts/impeccable embed-prompt <plate> --prompt-file <prompt.txt>` (if you refine the prompt, save and embed the exact text sent). With the API fallback, run `~/.omo/agent/skills/impeccable/scripts/impeccable generate-image --ref <crop.png> --prompt-file <prompt.txt> --out <plate.png> --size <WxH> --quality high --background transparent` for a cutout, or `--background opaque` otherwise. The API fallback embeds the prompt and records the background in the sidecar. The output must be PNG; the fallback requests native alpha and performs no chroma-keying.
|
||||
4. Open the plate beside the crop and compare subject, placement, scale, palette, and style. For cutouts, verify a real alpha channel and inspect composites on light and dark grounds: white paint must stay solid, interior holes must clear, and fine edges must avoid halos. Inspect glass and soft shadows carefully; partial alpha alone does not ensure convincing translucency. Never chroma-key native transparent output or flatten it before saving. If a native tool returns opaque pixels or a painted checkerboard, retry with the API fallback when available; otherwise report the transparency blocker. On a visual miss, tighten the prompt and regenerate once. Two misses on one region: keep the better plate, mark it `needs_parent_review`, and name the drift. The parent runs the plates gate after all assets exist; report `unscored` until a gate score is available.
|
||||
5. A frame plate (a window, a doorway, an arch) is a transparent cutout with an opening: generate it with a transparent background and keep the opening fully transparent. Verify the alpha inside the opening before saving: no baked view, no glow or vignette halo across it. The content seen through the opening is its own image region; produce it separately at the opening's size.
|
||||
|
||||
Do not redesign. Do not add objects, restyle, or reinterpret; the comp was approved as it is. Do not touch the page code, the spec, or the comp. Do not produce anything the spec does not list; a region the parent forgot goes back as a one-line note, not a plate.
|
||||
|
||||
+2
-2
@@ -16,10 +16,10 @@ Expect: the original request; the confirmed user answers; the artifact path(s);
|
||||
## Checks, in order
|
||||
|
||||
0. **Evidence.** Before any other check, verify the required captures exist and every capture is valid. Required: the platform's full viewport set (web: `desktop.png` and `mobile.png`; native: one capture per shipped device class), plus every capture the calling brief names as required, a reported user viewport (`user-<width>.png`) included. Valid: no black or blank regions, content matching what the filename claims (a visit capture showing the About section is invalid), the document top visible where the file claims a full page, dimensions that make sense for the named viewport. A required capture that is absent fails exactly like one that is malformed: a viewport nobody captured is a viewport nobody inspected, and it cannot ship. When any capture fails, the whole review changes shape: return `disposition: recapture` as the first line, then one section, `recapture`, listing each missing or invalid file and what a valid capture of it shows, and stop. Never build a matrix on malformed evidence; a verdict derived from a broken capture launders the breakage into an approval, and the parent owes you a full re-review on valid captures, not a scoring round.
|
||||
1. **Persistence.** PRODUCT.md exists. On a comp-led build, `.impeccable/build/state.json` exists and its `comps` (or `skipped` when a surface round locked the comp), `spec`, `plates`, and `hero` phases are `closed`; a comp-led config with no state file, or a state whose `comps` phase never closed, means the comp round was skipped and the build ran from a world description alone, a material finding that outranks craft; a phase closed with a `forced` record is disclosed as a material finding unless the user downgraded the comp in words the packet quotes; a state file whose `hero.gate.score` sits under 0.72, or a missing state file, means the reproduction ran unproven, a material finding, and `.impeccable/review/hero-repro.png` must exist either way. When DESIGN.md predates this build (an extension or redesign), it matches the built world; on a new world it is written after this review by the documenter, so its absence here is not a finding. When comp-round comps exist under `.impeccable/mocks/`, an approval record exists too: the surface brief naming the approved comp, or an `approved` flag in its sidecar. Comp-round comps with no recorded pick mean the approval point was skipped, a material finding. Files under `.impeccable/mocks/decision/` are exempt: they are the direction round's dealt hand, produced before any comp round, and imply no approval whatever the build path; a code-led build has no comp round at all.
|
||||
1. **Persistence.** PRODUCT.md exists. On a comp-led build, `.impeccable/build/state.json` exists and every phase before `review` is `closed` or explicitly `skipped`; an open or failed phase is a material finding. A comp-led config with no state file, or a state whose `comps` phase is neither `closed` nor `skipped`, means the comp round was skipped and the build ran from a world description alone, a material finding that outranks craft; a phase closed with a `forced` record is disclosed as a material finding unless the user downgraded the comp in words the packet quotes; a state file whose `hero.gate.score` sits under 0.72, or a missing state file, means the reproduction ran unproven, a material finding, and `.impeccable/review/hero-repro.png` must exist either way. When DESIGN.md predates this build (an extension or redesign), it matches the built world; on a new world it is written after this review by the documenter, so its absence here is not a finding. When comp-round comps exist under `.impeccable/mocks/`, an approval record exists too: the surface brief naming the approved comp, or an `approved` flag in its sidecar. Comp-round comps with no recorded pick mean the approval point was skipped, a material finding. Files under `.impeccable/mocks/decision/` are exempt: they are the direction round's dealt hand, produced before any comp round, and imply no approval whatever the build path; a code-led build has no comp round at all.
|
||||
2. **Fidelity.** Start from the measurement, then judge what it cannot: read `.impeccable/review/diff/final/report.json` (and hero) first; every region scored `missing` or `contradicted` is a matrix row in that state unless the paired crop under `regions/` shows the score is wrong, and you say why; a region scored `match` still gets your eye for lettering character and material, which the numbers do not measure. Then, against your own element inventory of the approved comp, never against the contract's summary of it: topology, reading order, focal scale, overlaps and z-order, density, signature geometry, the primary action's treatment (a CTA the comp physically works, dissolves, or stamps is a signature element; its plain-rectangle rendition is contradicted), navigation items and icons, headline levels and scale relationships. Classify every salient element: match, acceptable adaptation, missing, contradicted, or added without approval. Three rows are mandatory in every matrix. TYPE: the display lettering's character, compression, width, weight, contrast, terminals, against the comp's; a face of a different character is contradicted however the layout matches. MATERIAL: an element rendered as flat CSS or clean vector where the comp shows painted, textured, dimensional, or photographic material is contradicted regardless of placement; medium is part of the promise. GROUND: the page field's value and temperature against the comp's, sampled from pixels on both sides when tooling allows rather than judged from memory, and read as the net on-screen result where a texture or tile paints over the base color; a ground warmer or cooler than the comp's is contradicted however faithfully the layout matches, and drift toward the rendition prior (warm cream on light grounds, blue-black slate on dark) is the direction to hunt. With no approved comp, TYPE and MATERIAL do not lapse: judge them against the contract's OWN-WORLD and the world's real materials, and treat faked physicality (CSS bevels, embossing, stamped-metal or chalk effects imitating a material the page never renders) as contradicted on its face; imitation material is the single most reliable mark of machine-made design. GROUND narrows rather than lapses: with no comp to sample, a color OWN-WORLD names is the target and the same warmer-or-cooler judgment applies; when OWN-WORLD names none, there is no GROUND authority, and the review says so in place of a verdict, because a target the reviewer invents turns the check into taste. A critique-reference comp on such a build is provocation, not spec: no element matrix, no adaptation citations, no asset obligations; its one contribution is what the image dared that the build did not, and dares worth adopting enter material_fixes as ordinary ordered fixes. An adaptation counts as intentional only when it cites the user answer, surface brief, accessibility need, or product truth that forced it; an uncited deviation is a defect. A missing signature element, a changed topology, or content added without approval fails fidelity and outranks every craft point in material_fixes. When MATERIAL is contradicted on the focal element, or contradiction is the page rather than the exception, stop ordering repairs: make the first material fix a rebuild directive naming the comp regions to re-derive and the assets to produce; a list of patches against a rejected page launders the rejection into an approval. A fix that requires producing an asset says so explicitly ("produce: <region> as a raster asset"), never phrased as a style adjustment the parent will answer with CSS. The comp is the spec for composition, topology, element inventory, density, lettering character, and material; it is not a pixel spec for semantics, accessibility, or responsive reflow, and that allowance covers translation, never replacement.
|
||||
3. **Ceiling.** Against the QUALITY BAR card: name the world's native devices the build left unused, frame, depth, lettering treatment, ornament density, motion. The card governs commitment and finish, never composition.
|
||||
4. **Contract, promise by promise.** First verify FORM carries the seed key the concept roll printed; a contract with no seed key, or one the parent cannot corroborate, means the roll was skipped, a material fix ahead of any craft point. Then, for each of the five blocks: does the render keep the promise? Apply the memory test to the first viewport.
|
||||
4. **Contract, promise by promise.** First verify FORM carries the seed reference the concept roll printed (`seed:` and 16 hex), corroborated against the roll output the parent saw or with `impeccable concept-seed --check-seed <reference>` (exit 0 means this machine rolled it). A raw seed key in FORM is itself a material fix: the brief is committed, and the key must not be. `seed: none (unavailable)` stands only when the roll printed SEED REFERENCE unavailable, which `--check-seed none` confirms with exit 0. Any other contract with no reference, or one neither source corroborates, means the roll was skipped, a material fix ahead of any craft point. Then, for each of the five blocks: does the render keep the promise? Apply the memory test to the first viewport.
|
||||
5. **Truth.** Demonstration data authored and labeled synthetic; no invented commercial claims; unanswered claims present as marked placeholders, not omissions. Every raster region of the spec shipped as its plate (the spec names the file; the page references it; the region's diff row is not `missing`), not a gradient, an inline SVG, or a many-vertex `clip-path` standing in for it, and every produced asset visibly present in the screenshots; an asset applied at near-zero opacity or buried behind a wash is a compliance token, not a shipped material, and the detector's `buried-raster` and `organic-clip-path` findings in the packet are material fixes.
|
||||
6. **Floor.** Read the craft floor's Refuse list and hold the screenshots against it: kickers and eyebrows, hard offset shadows outside a neobrutalist world, glyph icons, system display faces, gradient text, side stripes, and the rest. A banned element is a material fix even when it matches nothing in the comp: the builder loaded the same ban before writing it, and fidelity to a comp cannot authorize what the floor refuses. The parent's hook findings cover this mechanically where hooks run; this check exists because hookless harnesses reach you with none, and the last two live sessions shipped five kickers past a reviewer that never looked.
|
||||
|
||||
+3
-3
@@ -13,7 +13,7 @@ Three kinds of drift travel under "out of date". Keep them apart:
|
||||
## Step 1: Run the pass
|
||||
|
||||
```
|
||||
.opencode/skills/impeccable/scripts/impeccable doctor --json
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable doctor --json
|
||||
```
|
||||
|
||||
Add `--target <path>` when the user named a workspace, file, or route in a monorepo. Without it the report describes the repo root, and in a monorepo that is often the wrong project.
|
||||
@@ -26,7 +26,7 @@ An empty `findings` array is the good outcome. Say so in one line and stop.
|
||||
|
||||
The severity says what should happen, not how bad it is.
|
||||
|
||||
- **`auto`** carries no decision. Run `.opencode/skills/impeccable/scripts/impeccable doctor --fix` once to apply these, then report what it moved in one line. Do not ask permission first, and do not ask about them afterward.
|
||||
- **`auto`** carries no decision. Run `~/.omo/agent/skills/impeccable/scripts/impeccable doctor --fix` once to apply these, then report what it moved in one line. Do not ask permission first, and do not ask about them afterward.
|
||||
- **`mention`** needs the user to know but not to decide anything now. State each one in a sentence with its offered fix.
|
||||
- **`route`** needs a specific command. Name the command and the gap it would close. Run it only if the user asks in this turn; `init` and `document` are conversations, not repairs you perform unattended.
|
||||
|
||||
@@ -46,7 +46,7 @@ The same restraint applies to `workspace-context-inherited`. Inheritance is a de
|
||||
|
||||
- `workspace-platform-native-evidence` is the finding that matters most here: a workspace carrying native build files while inheriting a root record that resolves to web gets web guidance for its whole life and never loads [ios.md](ios.md) or [android.md](android.md). The repair is a child PRODUCT.md in that workspace, because one inherited record cannot hold two platforms.
|
||||
- `config-project-roots-match-nothing` means every `projectRoots` glob missed, so the repo root is silently standing in as the active project. A renamed workspace directory is the usual cause. Report the patterns and ask which directories they should name.
|
||||
- `config-invalid-build-path` and `config-build-path-unset` both concern one key, `buildPath` in `.impeccable/config.json` (or the gitignored `.impeccable/config.local.json`, which wins for that developer). It holds `comp` or `code` and sets whether new surfaces are built from a generated comp or straight in code. An unread value does not fall back to the opposite path, so a project meaning `code` has been building comp-led; report the exact value. The unset finding fires only where a project has done direction work and never recorded a preference, and the offer belongs in it only when image generation exists in your tool surface. Without image generation there is nothing to choose and nothing to say.
|
||||
- `config-invalid-build-path` and `config-build-path-unset` both concern one key, `buildPath` in `.impeccable/config.json` (or the gitignored `.impeccable/config.local.json`, which wins for that developer). It holds `comp` or `code` and sets whether new Persuade and Experience surfaces are built from a generated comp or straight in code; Operate and Read surfaces are code-led whatever it holds. An unread value does not fall back to the opposite path, so a project meaning `code` has been building comp-led; report the exact value. The unset finding fires only where a project has done direction work and never recorded a preference, and the offer belongs in it only when image generation exists in your tool surface. Without image generation there is nothing to choose and nothing to say.
|
||||
- Use the `workspaces` table to show the user which apps carry their own context, which inherit, and which have none, before proposing any change.
|
||||
|
||||
## Opting out of the boot check
|
||||
+6
-6
@@ -46,7 +46,7 @@ Done when you hold an action from the vocabulary (asked for, when the request na
|
||||
- **No browser tool** (Codex, others): run the start command with `--open --wait-for-browser 120000`; it opens the system browser, and the longer wait covers the user finding the tab. **`browser_open_failed` back**: tell the user the `url` in one line and rerun with `--wait-for-browser 120000`.
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable live-generate --target src/App.jsx --dev-url http://127.0.0.1:5173/ --selector ".pricing-grid" --action bolder --count 3 --boot --wait-for-browser 60000
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable live-generate --target src/App.jsx --dev-url http://127.0.0.1:5173/ --selector ".pricing-grid" --action bolder --count 3 --boot --wait-for-browser 60000
|
||||
```
|
||||
|
||||
Run it in the foreground in Cursor and Claude Code (it returns within the wait); on Codex, in an exec you yield from, the way Step 3 runs the poll.
|
||||
@@ -63,7 +63,7 @@ Read the output in this order: `boot` (or `boot.contextMissing` with `boot.conte
|
||||
- **`dev_server_gone`**: the dev server stopped answering while the command waited for the page (on Cursor, a server another chat started dies with that chat). Start it the way the verdict says, then rerun with `--dev-url <url>`.
|
||||
- **`no_match`**: the tab is on a route that does not render the element (navigate to the right route, rerun), or the selector is wrong (derive a better one from the source, or add `--text`).
|
||||
- **`config_missing` / `config_invalid`** under `bootError`: follow [live-setup.md](live-setup.md) first, then rerun.
|
||||
- **`event: null`** with `ok: true`: the event was slower than the wait; run `.opencode/skills/impeccable/scripts/impeccable live-poll` once to collect it, then continue.
|
||||
- **`event: null`** with `ok: true`: the event was slower than the wait; run `~/.omo/agent/skills/impeccable/scripts/impeccable live-poll` once to collect it, then continue.
|
||||
|
||||
Done when the output shows `ok: true`, a `sessionId`, and an `event`, reached with at most one server started and one tab opened by you.
|
||||
|
||||
@@ -74,7 +74,7 @@ The event is a standard `generate` event: the picked element's context, a prefli
|
||||
**Reply and wait in one call**, with the file you wrote:
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable live-poll --reply EVENT_ID done --file src/App.jsx --then-poll
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable live-poll --reply EVENT_ID done --file src/App.jsx --then-poll
|
||||
```
|
||||
|
||||
This replies done (the browser mounts the variants) and then blocks until the user's choice arrives, so run it the way your harness runs a long wait: **Claude Code** in the foreground with your tool's longest timeout (600000 ms), so you are paused until the choice arrives; **Codex** in a yielded foreground exec; **Cursor** in a background terminal with notify on `"type":"(accept|discard|variant_mount_failed|exit)"`. Never pass a short `--timeout=`. While it runs there is nothing else to do: never sleep and never poll its output on a timer; a harness that backgrounds it wakes you when it returns. `{"type":"timeout"}` means the user has not chosen yet: run `live-poll` again and keep waiting. If the edit fails after the browser flipped to GENERATING, `--reply EVENT_ID error "Short reason"` (without `--then-poll`) so the bar resets.
|
||||
@@ -85,17 +85,17 @@ Outside the replace path, read the matching live.md section before acting: `scaf
|
||||
|
||||
## Step 4: Accept and close
|
||||
|
||||
The call from Step 3 returns the user's choice. **`discard`**: nothing to do. **`accept`**: `_acceptResult.carbonize: true` is the normal case, and the cleanup is live.md's **Required after accept**, unchanged: move the accepted variant's rules into the stylesheet that already owns the element with real selectors, bake the chosen knob values in, unwrap the element and drop every `data-impeccable-*` attribute, delete the inline `<style>` block and both `impeccable-carbonize` markers, then `.opencode/skills/impeccable/scripts/impeccable live-complete --id SESSION_ID` and confirm `phase: "completed"`. (`baked: true` appears only when the accept was run with `--bake`; then the helper already made the variant permanent and no `live-complete` is owed.)
|
||||
The call from Step 3 returns the user's choice. **`discard`**: nothing to do. **`accept`**: `_acceptResult.carbonize: true` is the normal case, and the cleanup is live.md's **Required after accept**, unchanged: move the accepted variant's rules into the stylesheet that already owns the element with real selectors, bake the chosen knob values in, unwrap the element and drop every `data-impeccable-*` attribute, delete the inline `<style>` block and both `impeccable-carbonize` markers, then `~/.omo/agent/skills/impeccable/scripts/impeccable live-complete --id SESSION_ID` and confirm `phase: "completed"`. (`baked: true` appears only when the accept was run with `--bake`; then the helper already made the variant permanent and no `live-complete` is owed.)
|
||||
|
||||
Close without being asked, the moment the choice is handled:
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable live-server stop
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable live-server stop
|
||||
```
|
||||
|
||||
Stopping removes the injected script and reloads the page once: the user sees the accepted design with no overlay chrome, still served by their dev server. **Never kill or restart the dev server**, including one you started in Step 2.
|
||||
|
||||
- **The user asks for more variants before you closed**: skip the close, run Step 2 again for the next element (the helper is reused), and close after the last choice.
|
||||
- **Interrupted or unsure of the state**: `.opencode/skills/impeccable/scripts/impeccable live-status`, then `live-resume`; the journal under `.impeccable/live/sessions/` is canonical.
|
||||
- **Interrupted or unsure of the state**: `~/.omo/agent/skills/impeccable/scripts/impeccable live-status`, then `live-resume`; the journal under `.impeccable/live/sessions/` is canonical.
|
||||
|
||||
Done when the helper is stopped and the dev site still answers with the accepted design.
|
||||
+11
-9
@@ -4,7 +4,7 @@ Manage the **design detector hook** for the current project.
|
||||
|
||||
The hook runs the impeccable design detector on direct file edits to design-relevant files (`.tsx`, `.jsx`, `.html`, `.vue`, `.svelte`, `.astro`, `.css`, `.scss`, `.sass`, `.less`, `.ts`, `.js`). Claude Code, Codex, and GitHub Copilot use a post-tool-use hook and push a short system reminder into the agent's context after the edit; findings get a correction prompt, pending issues get a re-nudge, and clean UI-ish files get a short ack unless quiet mode is on (`hook.quiet` in config). Plain `.ts` and `.js` files are still scanned, but stay quiet unless the detector finds something. Cursor uses `preToolUse` to block bad proposed writes before they land and stays silent when it allows a clean write. Grok Build fires the same PostToolUse scan to mark touched files, then surfaces findings on Stop `additionalContext`. Do not expect a Grok per-edit reminder: Grok discards that stdout.
|
||||
|
||||
The detector rules run in two tiers. The per-edit hook surfaces only the immediate tier: mechanical, unambiguous problems worth interrupting an edit for, such as broken images, overflowing or clipped content, contrast and legibility failures, gradient text, glow shadows, and design-system drift. Everything else (copy cadence, palette and typography taste, layout rhythm) is deferred to a deep pass on the `Stop` hook event, which runs the full rule set over every UI file touched in the session and surfaces the remaining findings once, deduplicated against what the per-edit pass already reported. A session with nothing left to report stops silently. Set `hook.perEditRules` to `"all"` in `.impeccable/config.json` to restore the full rule set on every edit. The Stop deep pass is wired for Claude Code, Codex, and Grok Build, which dispatch a native `Stop` hook event. Cursor does not get one (its stop hook is not consistently dispatched; the pre-write gate covers it), and GitHub Copilot's stop-style events do not feed context back to the model, so they keep the full detector per edit. Grok also fires an observe-only Stop with `reason: "shutdown"` after `end_turn`; skip that one, scan only `end_turn`.
|
||||
The detector rules run in two tiers. The per-edit hook surfaces only the immediate tier: mechanical, unambiguous problems worth interrupting an edit for, such as broken images, overflowing content, contrast and legibility failures, gradient text, glow shadows, and design-system drift. Everything else (copy cadence, palette and typography taste, layout rhythm) is deferred to a deep pass on the `Stop` hook event, which runs the full rule set over every UI file touched in the session and surfaces the remaining findings once, deduplicated against what the per-edit pass already reported. A session with nothing left to report stops silently. Set `hook.perEditRules` to `"all"` in `.impeccable/config.json` to restore the full rule set on every edit. The Stop deep pass is wired for Claude Code, Codex, and Grok Build, which dispatch a native `Stop` hook event. Cursor does not get one (its stop hook is not consistently dispatched; the pre-write gate covers it), and GitHub Copilot's stop-style events do not feed context back to the model, so they keep the full detector per edit. Grok also fires an observe-only Stop with `reason: "shutdown"` after `end_turn`; skip that one, scan only `end_turn`.
|
||||
|
||||
Every hook is a mechanical pass. The reflexes no scanner catches live in [craft-floor.md](craft-floor.md), which the skill loads before it edits UI, so they apply whether or not a hook is wired. A session with no automatic hook gets one `MANUAL_DETECTOR_REQUIRED` directive from `impeccable context` asking for a single detector run at the end.
|
||||
|
||||
@@ -14,10 +14,12 @@ Declare server-side template extensions under **`detector.extensions`** when the
|
||||
|
||||
Manual `npx impeccable detect` scans use the same project filter config by default: `detector.ignoreRules`, `detector.ignoreFiles`, `detector.ignoreValues`, and `detector.designSystem.enabled`. `hook.enabled` only controls automatic hook execution, not manual CLI scans. Use `npx impeccable detect --no-config ...` for a raw detector run that ignores project config/context. Use `npx impeccable ignores ...` for direct CLI CRUD on the same detector ignores.
|
||||
|
||||
Supported harnesses: Claude Code (`.claude/settings.local.json` in the project, which is gitignored so the hook stays machine-local; a hook you move into the shared `settings.json` is honored in place too), Codex (`.codex/hooks.json` in the project), Cursor (`.cursor/hooks.json` in the project), Grok Build (`.grok/hooks/impeccable.json` in the project; requires `/hooks-trust` or `--trust`), and GitHub Copilot (`.github/hooks/impeccable.json` in the project, a team-shared committed file that both the Copilot CLI and the cloud agent read). For the Copilot CLI, repo-level hooks fire once `.github/hooks/impeccable.json` is committed to the repository's default branch.
|
||||
Supported harnesses: Claude Code (`.claude/settings.local.json` for a project-scope install; `~/.claude/settings.json` for a user-scope install; a project hook moved into shared `.claude/settings.json` is honored in place too), Codex (`.codex/hooks.json` in the project), Cursor (`.cursor/hooks.json` in the project), Grok Build (`.grok/hooks/impeccable.json` in the project; requires `/hooks-trust` or `--trust`), and GitHub Copilot (`.github/hooks/impeccable.json` in the project, a team-shared committed file that both the Copilot CLI and the cloud agent read). For the Copilot CLI, repo-level hooks fire once `.github/hooks/impeccable.json` is committed to the repository's default branch.
|
||||
|
||||
On **Cursor**, `preToolUse` checks proposed Write/Edit/Shell write content and denies only when the real detector finds an issue. The denial message is visible to the agent as the tool error, so the agent can reconsider before the bad write lands.
|
||||
|
||||
Gemini installs session and completion hooks in `.gemini/settings.json`, merged into the settings already there (comments are tolerated; a commented file is backed up to `settings.json.bak` before the rewrite, and a file that is not valid JSON is left alone). It does not install a per-edit detector hook. The `BeforeTool` hook only rewrites shell commands that run `build-phase`, and only on macOS and Linux; on Windows (where Gemini runs hooks through PowerShell) no session id reaches the shell, so a comp build is not tied to the session and the completion reminder stays silent.
|
||||
|
||||
## Routing
|
||||
|
||||
The first argument is the action. Defaults to `status`.
|
||||
@@ -40,7 +42,7 @@ The first argument is the action. Defaults to `status`.
|
||||
2. Invoke the admin script and pass the user's output through verbatim:
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable hooks <action> [args...]
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable hooks <action> [args...]
|
||||
```
|
||||
|
||||
3. If `<action>` is `off`, follow up with a one-line note: "Done. New edits will not trigger the design hook in this project until you run `/impeccable hooks on`."
|
||||
@@ -70,32 +72,32 @@ Prefer the narrowest exception:
|
||||
Example value-specific exception:
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable hooks ignore-value overused-font Inter --shared --reason "User confirmed Inter is intentional"
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable hooks ignore-value overused-font Inter --shared --reason "User confirmed Inter is intentional"
|
||||
```
|
||||
|
||||
Example self-served exception, with the evidence named:
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable hooks ignore-value bounce-easing bounce-ball --shared --reason "Agent: literal ball-bounce animation, bounce easing is the subject"
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable hooks ignore-value bounce-easing bounce-ball --shared --reason "Agent: literal ball-bounce animation, bounce easing is the subject"
|
||||
```
|
||||
|
||||
Example whole-rule font exception:
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable hooks ignore-rule overused-font --all-values --reason "User asked to ignore overused fonts generally"
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable hooks ignore-rule overused-font --all-values --reason "User asked to ignore overused fonts generally"
|
||||
```
|
||||
|
||||
Example one-rule-in-one-file exception, for a file that is still worth reviewing
|
||||
for everything else:
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable hooks ignore-value design-system-font-size "*" --file "src/overlay/widget.js" --reason "Injected widget builds its own type scale; DESIGN.md's ramp describes the site"
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable hooks ignore-value design-system-font-size "*" --file "src/overlay/widget.js" --reason "Injected widget builds its own type scale; DESIGN.md's ramp describes the site"
|
||||
```
|
||||
|
||||
Example whole-file exception, for a file that is out of scope entirely:
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable hooks ignore-file "src/legacy/Card.tsx"
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable hooks ignore-file "src/legacy/Card.tsx"
|
||||
```
|
||||
|
||||
## Constraints
|
||||
@@ -103,7 +105,7 @@ Example whole-file exception, for a file that is out of scope entirely:
|
||||
- Never modify `.impeccable/config.json` or `.impeccable/config.local.json` by hand from this command. Always go through `impeccable hooks` so writes stay validated and the file shape stays consistent. One exception: `detector.extensions` has no admin action, so when the user asks to cover a template stack, edit that one field in `.impeccable/config.json` directly and leave the rest of the file untouched.
|
||||
- Do not edit the launcher or the binary behind `impeccable hook` and `impeccable hook-before-edit` from this flow. Those are skill plumbing.
|
||||
- Cursor can block a proposed write when the detector finds a real issue. Claude Code, Codex, and GitHub Copilot do not block the edit; they emit a post-edit reminder instead. Disabling stops both blocking and reminders.
|
||||
- The hook is bundled with the Impeccable skill and installed through project-local manifests: `.claude/settings.local.json`, `.codex/hooks.json`, `.cursor/hooks.json`, and `.github/hooks/impeccable.json`. On Codex, the user must approve the hook via `/hooks` the first time. On Cursor, confirm hooks are enabled under Settings -> Hooks. On GitHub Copilot, the CLI loads `.github/hooks/impeccable.json` once it is committed to the repository's default branch, and the cloud agent reads it from the repo directly.
|
||||
- The hook is bundled with the Impeccable skill. Project installs use `.claude/settings.local.json`, `.codex/hooks.json`, `.cursor/hooks.json`, `.github/hooks/impeccable.json`, and `.gemini/settings.json`; a user-scope Claude install uses `~/.claude/settings.json`. On Codex, the user must approve the hook via `/hooks` the first time. On Cursor, confirm hooks are enabled under Settings -> Hooks. On GitHub Copilot, the CLI loads `.github/hooks/impeccable.json` once it is committed to the repository's default branch, and the cloud agent reads it from the repo directly.
|
||||
|
||||
## Failure modes
|
||||
|
||||
+2
-2
@@ -109,9 +109,9 @@ Before loading new-work or resuming shape/build, verify that PRODUCT.md exists a
|
||||
|
||||
## Step 5: Record workflow defaults
|
||||
|
||||
When image generation is available and no `buildPath` is recorded yet, ask once how new surfaces should be built. Availability means a harness-native image tool or the API fallback that `impeccable context` reports as `IMAGE_GEN_AVAILABLE`, and the first of those leaves no trace in the boot output: `impeccable context` only sees the key, so a silent boot on a harness that generates images is not evidence there is nothing to ask about. This is its own question, never a clause riding inside another one. The stack round asks what to build with; this asks how the building starts, and an answer to the first carries no consent about the second. State the trade in the question the user actually reads, because the two names mean nothing to someone meeting them for the first time: **comp-first** (an image sets the bar before any code; bolder composition, slower, and the build must match the image) or **code-first** (build directly; the ambition is written into the direction contract and audited at the finish; leaner, faster).
|
||||
When image generation is available and no `buildPath` is recorded yet, ask once how new surfaces should be built. Availability means a harness-native image tool or the API fallback that `impeccable context` reports as `IMAGE_GEN_AVAILABLE`, and the first of those leaves no trace in the boot output: `impeccable context` only sees the key, so a silent boot on a harness that generates images is not evidence there is nothing to ask about. This is its own question, never a clause riding inside another one. The stack round asks what to build with; this asks how the building starts, and an answer to the first carries no consent about the second. State the trade in the question the user actually reads, because the two names mean nothing to someone meeting them for the first time: **comp-first** (an image sets the bar before any code; bolder composition, slower, and the build must match the image) or **code-first** (build directly; the ambition is written into the direction contract and audited at the finish; leaner, faster). Say in the same question what the choice covers: landing pages and showcase surfaces. App screens and documents are built code-first either way.
|
||||
|
||||
Write the answer to `.impeccable/config.json` as `"buildPath": "comp"` or `"buildPath": "code"`, merging with the keys already there. Write only the value the user chose. A recommendation you made is not an answer you received, and a value taken from silence is a standing default nobody set: it then rides every future round in the project, which is the opposite of asking once. When the question goes unanswered, record nothing and say in one line which path this session is taking and that it is not stored. That path is comp-first, the default new-work applies wherever image generation exists and nothing is recorded; name it rather than choosing a quieter one, because a silent default invented here is the same failure as a value written without an answer. Unset is a working state, not a gap: the decision page's toggle governs each session, and new-work's one-time offer records the answer the first time the user flips it. The config is the only place this lives. It is a workflow setting, not product truth, so it never joins `## Stack` or any other PRODUCT.md section, where a second copy would outlive the setting and steer rounds nobody could trace back to it.
|
||||
Write the answer to `.impeccable/config.json` as `"buildPath": "comp"` or `"buildPath": "code"`, merging with the keys already there. Write only the value the user chose. A recommendation you made is not an answer you received, and a value taken from silence is a standing default nobody set: it then rides every future round in the project, which is the opposite of asking once. When the question goes unanswered, record nothing and say in one line which path this session is taking and that it is not stored. That path is comp-first on a landing page or showcase surface, the default new-work applies wherever image generation exists and nothing is recorded, and code-first on an app screen or document; name it rather than choosing a quieter one, because a silent default invented here is the same failure as a value written without an answer. Unset is a working state, not a gap: the decision page's toggle governs each session, and new-work's one-time offer records the answer the first time the user flips it. The config is the only place this lives. It is a workflow setting, not product truth, so it never joins `## Stack` or any other PRODUCT.md section, where a second copy would outlive the setting and steer rounds nobody could trace back to it.
|
||||
|
||||
A value already recorded in `.impeccable/config.json` or the gitignored `.impeccable/config.local.json` is a confirmed answer: on a re-run, honor it in silence rather than asking again. This is a default, not a lock: the decision page renders a toggle whose flip binds a single session and is never written back. Without image generation there is no choice to record; code-first is the only path.
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ When a sub-agent tool is available and permitted, run these independently; other
|
||||
2. **Mechanical scan:** run:
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable detect --json --scope layout [target files or dirs]
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable detect --json --scope layout [target files or dirs]
|
||||
```
|
||||
|
||||
Also inspect arbitrary spacing, overflow, stacking, and container behavior the detector cannot resolve. Keep mechanical evidence out of the first assessment, then synthesize both passes before editing. A clean scan cannot prove hierarchy or rhythm.
|
||||
+1
-1
@@ -47,7 +47,7 @@ Keep all allowances below development-only, including manual middleware and meta
|
||||
If `config.cspChecked === true`, skip this whole section; the user was already asked once.
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable detect-csp
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable detect-csp
|
||||
```
|
||||
|
||||
Output `{ shape, signals }`; the shape names the *patch mechanism*, so one template covers many frameworks:
|
||||
+14
-14
@@ -4,13 +4,13 @@ Interactive live variant mode: select elements in the browser, pick a design act
|
||||
|
||||
A running dev server with HMR (Vite, Next.js, Bun, etc.), OR a static HTML file open in the browser. If the dev server's default port is busy, the app is very likely ALREADY running; probe the default URL before spawning a second server.
|
||||
|
||||
Live editing requires a local checkout; injection into deployed production sites (including HTTPS) is unsupported. For production inspection, use `.opencode/skills/impeccable/scripts/impeccable detect <url>` or the browser extension, not the live helper. Do not disable browser security or weaken production CSP to enable live mode.
|
||||
Live editing requires a local checkout; injection into deployed production sites (including HTTPS) is unsupported. For production inspection, use `~/.omo/agent/skills/impeccable/scripts/impeccable detect <url>` or the browser extension, not the live helper. Do not disable browser security or weaken production CSP to enable live mode.
|
||||
|
||||
## The contract (read once)
|
||||
|
||||
Execute in order. No step skipped, no step reordered. Every tool output in live mode may carry an `_instructions` field: it is the authoritative next step for that exact situation, with real ids and paths substituted; when it conflicts with your recollection of this document, `_instructions` wins.
|
||||
|
||||
1. `impeccable live`: boot. If the request names or implies a file, route, or app inside a monorepo, infer the concrete path and run `.opencode/skills/impeccable/scripts/impeccable live --target <path>` instead; then run the rest of this live session from the returned `projectRoot`. The boot resolves the app root from dev-server config files and persists it in `.impeccable/live/roots.json`; every helper re-anchors to that manifest at startup (a wrong cwd cannot fork session state), PRODUCT.md / DESIGN.md are discovered upward to the git root, and relative helper args like `--file` resolve against the app root.
|
||||
1. `impeccable live`: boot. If the request names or implies a file, route, or app inside a monorepo, infer the concrete path and run `~/.omo/agent/skills/impeccable/scripts/impeccable live --target <path>` instead; then run the rest of this live session from the returned `projectRoot`. The boot resolves the app root from dev-server config files and persists it in `.impeccable/live/roots.json`; every helper re-anchors to that manifest at startup (a wrong cwd cannot fork session state), PRODUCT.md / DESIGN.md are discovered upward to the git root, and relative helper args like `--file` resolve against the app root.
|
||||
2. Open the app URL that serves `pageFile` (infer from `package.json`, docs, terminal output, or an open tab). Never use `serverPort`; it's the helper, not the app. **Cursor:** `browser_navigate` to that URL before polling; do not skip. **Other harnesses:** use the available browser tool; if the URL is uncertain, ask the user once.
|
||||
3. Poll loop with the default long timeout (600000 ms). Run `impeccable live-poll` again immediately after every event or `--reply`; Codex runs this one-shot poll in the foreground. Never pass a short `--timeout=`. The global bar's **Impeccable mark** dims with a pulsing amber dot when nothing is polling `/poll`; restart `impeccable live-poll` to reconnect.
|
||||
4. On `generate`: reuse `event.scaffold` when present; read the screenshot if present; load the action's reference; deliver variants; `--reply done`; poll again. Generate in this thread: you already hold the project's tokens and layout. The overlay preview IS the verification channel; do not screenshot, re-render, or QA variants between generate and accept. Apply craft-floor's contrast, spacing, and type floors by construction as you write; full verification runs once at accept on the chosen variant.
|
||||
@@ -33,7 +33,7 @@ Chat is overhead. No recap, no tutorial output, no pasting PRODUCT / DESIGN bodi
|
||||
|
||||
```
|
||||
LOOP:
|
||||
.opencode/skills/impeccable/scripts/impeccable live-poll # default long timeout; no --timeout=
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable live-poll # default long timeout; no --timeout=
|
||||
Read JSON; dispatch on "type"
|
||||
|
||||
"generate" → Handle Generate; reply done; LOOP
|
||||
@@ -54,7 +54,7 @@ LOOP:
|
||||
## Start
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable live
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable live
|
||||
```
|
||||
|
||||
Output JSON: `{ ok, serverPort, serverToken, pageFiles, roots, hasProduct, product, productPath, hasDesign, design, designPath, hasSurfaceBrief, surfaceBrief }`. `roots` is the resolved root manifest; `projectRoot` mirrors `roots.appRoot`. The surface brief rides along; do not shell out to `impeccable surface-brief` separately. Precedence for generation: **DESIGN.md wins on visual decisions; PRODUCT.md wins on durable product and voice decisions; the surface brief wins on this surface's strategy.** When DESIGN.md is missing, identity is **not** absent; extract it from CSS variables, computed styles, and sibling components (Step 4 Phase A). Identity preservation is the default; departure requires the user's explicit redesign intent.
|
||||
@@ -68,9 +68,9 @@ If output is `{ ok: false, error: "config_missing" | "config_invalid", path }`,
|
||||
The append-only journal under `.impeccable/live/sessions/` is canonical durable state (not project source). When the chat was interrupted, polling was missed, the helper restarted, or the browser reloaded:
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable live-status # helper state, active sessions, queued events; works with the helper down
|
||||
.opencode/skills/impeccable/scripts/impeccable live-resume --id SESSION_ID # active snapshot, pending event, next safe action
|
||||
.opencode/skills/impeccable/scripts/impeccable live-complete --id SESSION_ID # canonical manual final acknowledgement after verified cleanup
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable live-status # helper state, active sessions, queued events; works with the helper down
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable live-resume --id SESSION_ID # active snapshot, pending event, next safe action
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable live-complete --id SESSION_ID # canonical manual final acknowledgement after verified cleanup
|
||||
```
|
||||
|
||||
Server restart rule: start `impeccable live-server` again, then poll; startup requeues unacknowledged events, so never ask the user to click Go again unless `impeccable live-resume` says no active session exists.
|
||||
@@ -89,7 +89,7 @@ Speed matters; the user is watching the selected element. Reuse preflight metada
|
||||
2. If `event.scaffold` is present, use it and do **not** run the helper again. Otherwise:
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable live-insert --id EVENT_ID --count EVENT_COUNT --position after \
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable live-insert --id EVENT_ID --count EVENT_COUNT --position after \
|
||||
--element-id "ANCHOR_ID" --classes "class1,class2" --tag "section" --text "ANCHOR_TEXT"
|
||||
```
|
||||
|
||||
@@ -110,7 +110,7 @@ When `event.scaffold` is present, the helper already found the source and comput
|
||||
**On source-preview targets `event.scaffold` carries `sourceWritten: false`.** The helper did NOT write the wrapper; it hands you `scaffold.wrapperBlock` plus the picked element's source range (`replaceStartLine`, `replaceEndLine`, 1-indexed). Write the wrapper **and** all variants in ONE edit: splice your variants into `wrapperBlock` at the "Variants: insert below this line" marker, then replace lines `[replaceStartLine, replaceEndLine]` with the result. A separate scaffold write reloads the framework before your variant write lands and strands the browser at 0/N. (`replaceEndLine < replaceStartLine` means insert mode: insert, remove nothing.) The `svelte-component` path never sets `sourceWritten`.
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable live-wrap --id EVENT_ID --count EVENT_COUNT --element-id "ELEMENT_ID" --classes "class1,class2" --tag "div" --text "TEXT_SNIPPET"
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable live-wrap --id EVENT_ID --count EVENT_COUNT --element-id "ELEMENT_ID" --classes "class1,class2" --tag "div" --text "TEXT_SNIPPET"
|
||||
```
|
||||
|
||||
Flag mapping (keep separate, never collapse into `--query`): `--element-id` ← `event.element.id`; `--classes` ← classes joined with commas; `--tag` ← tagName; `--text` ← first ~80 chars of textContent, **every call**: it disambiguates repeated sibling components, without it wrap lands on the first match. If `event.pageUrl` implies the file, pass `--file PATH`. If `--text` still matches several candidates, wrap exits `{ error: "element_ambiguous", candidates, fallback: "agent-driven" }`: pick the right range from page context and write the wrapper manually per the fallback flow.
|
||||
@@ -242,14 +242,14 @@ Three kinds: `range` (slider; drives `--p-<id>`; author `var(--p-color-amount, 0
|
||||
### 8. Signal done
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable live-poll --reply EVENT_ID done --file RELATIVE_PATH
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable live-poll --reply EVENT_ID done --file RELATIVE_PATH
|
||||
```
|
||||
|
||||
`RELATIVE_PATH` is relative to project root; the browser fetches source directly if the dev server lacks HMR. Then poll again immediately.
|
||||
|
||||
### Aborting an in-flight session
|
||||
|
||||
If wrap or generation fails after the browser flipped to GENERATING, tell the **browser** so its bar resets: `.opencode/skills/impeccable/scripts/impeccable live-poll --reply EVENT_ID error "Short reason"`. Never use `live-accept --discard` for this (pure file mutator, browser never sees it, bar sticks on dots); `--discard` is only source-side cleanup for a discard the browser itself initiated.
|
||||
If wrap or generation fails after the browser flipped to GENERATING, tell the **browser** so its bar resets: `~/.omo/agent/skills/impeccable/scripts/impeccable live-poll --reply EVENT_ID error "Short reason"`. Never use `live-accept --discard` for this (pure file mutator, browser never sees it, bar sticks on dots); `--discard` is only source-side cleanup for a discard the browser itself initiated.
|
||||
|
||||
## Handle fallback
|
||||
|
||||
@@ -290,7 +290,7 @@ Event: `{id, _acceptResult, _completionAck}`. The poll script already restored t
|
||||
|
||||
## Handle `steer`
|
||||
|
||||
Event: `{id, message, pageUrl}`: page-level direction from the global bar's Steer control (typed or spoken), no element context, no variant cycling. Read `message`, inspect the page or files as needed, make edits or answer in prose. Reply `.opencode/skills/impeccable/scripts/impeccable live-poll --reply EVENT_ID steer_done ["Optional short toast"]`, or on failure `--reply EVENT_ID error "Short reason"`, then poll immediately. No separate pickup reply; the Steer bar unlocks on `steer_done` or `error`.
|
||||
Event: `{id, message, pageUrl}`: page-level direction from the global bar's Steer control (typed or spoken), no element context, no variant cycling. Read `message`, inspect the page or files as needed, make edits or answer in prose. Reply `~/.omo/agent/skills/impeccable/scripts/impeccable live-poll --reply EVENT_ID steer_done ["Optional short toast"]`, or on failure `--reply EVENT_ID error "Short reason"`, then poll immediately. No separate pickup reply; the Steer bar unlocks on `steer_done` or `error`.
|
||||
|
||||
## Handle `prefetch`
|
||||
|
||||
@@ -306,7 +306,7 @@ When native subagents are available, delegate source edits to `impeccable_manual
|
||||
|
||||
If `repair` is present, the previous Apply changed source but final validation failed. Fix the current source and return the same canonical JSON result; do not roll files back yourself. The browser will ask the user before any rollback.
|
||||
|
||||
After source edits finish, reply exactly once with `.opencode/skills/impeccable/scripts/impeccable live-poll --reply EVENT_ID done --data '{"status":"done","appliedEntryIds":["8hexid"],"failed":[],"files":["src/page.html"],"notes":[]}'`. Use `status:"partial"` or `status:"error"` with `failed[]` when not every entry applied. Then poll again. Never reply without the event id; `--reply done --file ...` is invalid for manual Apply.
|
||||
After source edits finish, reply exactly once with `~/.omo/agent/skills/impeccable/scripts/impeccable live-poll --reply EVENT_ID done --data '{"status":"done","appliedEntryIds":["8hexid"],"failed":[],"files":["src/page.html"],"notes":[]}'`. Use `status:"partial"` or `status:"error"` with `failed[]` when not every entry applied. Then poll again. Never reply without the event id; `--reply done --file ...` is invalid for manual Apply.
|
||||
|
||||
## Exit
|
||||
|
||||
@@ -315,7 +315,7 @@ The user stops live mode by saying so in chat, closing the tab (SSE drops; poll
|
||||
## Cleanup
|
||||
|
||||
```bash
|
||||
.opencode/skills/impeccable/scripts/impeccable live-server stop
|
||||
~/.omo/agent/skills/impeccable/scripts/impeccable live-server stop
|
||||
```
|
||||
|
||||
Stops the helper and runs `impeccable live-inject --remove` to strip the injected script (use `stop --keep-inject` to keep it for a quick restart; `.impeccable/live/config.json` persists as project config). Then search for and remove any leftover `impeccable-variants-start` wrappers and `impeccable-carbonize-start` blocks.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user