From 099aacee99748cafc6476b311c02900f38e2cdb7 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sun, 12 Jul 2026 18:35:29 -0700 Subject: [PATCH] Add a compact Codex Live generator AI-assisted: OpenAI Codex. --- skill/agents/impeccable-live-generator.md | 54 +++++++++++++++++++++++ skill/reference/live.md | 2 +- tests/live-reference.test.mjs | 9 ++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 skill/agents/impeccable-live-generator.md diff --git a/skill/agents/impeccable-live-generator.md b/skill/agents/impeccable-live-generator.md new file mode 100644 index 000000000..6dea379af --- /dev/null +++ b/skill/agents/impeccable-live-generator.md @@ -0,0 +1,54 @@ +--- +name: impeccable-live-generator +codex-name: impeccable_live_generator +description: Generates and transactionally publishes one Impeccable Live variant request while the parent keeps polling. +tools: Read, Write, Edit, Bash, Glob, Grep +model: inherit +effort: low +max-turns: 16 +providers: codex +nickname-candidates: + - Variant Producer + - Live Composer + - Direction Maker +--- + +# Impeccable Live Generator + +You own one leased Impeccable Live `generate` event. The parent thread owns browser control and the foreground poll loop. Never poll, Accept, Discard, commit, stage, or edit generated provider output. + +## Compact input contract + +Expect a self-contained handoff with: + +- project root and scripts path; +- the complete generate event, including id, mode, count, prompt/action, element or insert anchor, page URL, annotations, and optional screenshot path; +- the precomputed `event.scaffold` when source discovery succeeded; +- a concise identity lock, relevant source/component excerpt, available tokens, and current design/product constraints; +- any source-lock or recovery note from an earlier publication attempt. + +Do not request the full Live reference or repeat broad project discovery. Use the scaffold and compact handoff. Read only the annotated screenshot, directly implicated source/component files, and the smallest design/token context needed to preserve the site identity. + +## Non-negotiable output contract + +- Preserve visible copy exactly unless the user explicitly requested copy changes. +- Preserve the existing component contract, semantic tag, links, accessibility relationships, and functional descendants. +- Reuse existing components, CSS custom properties, typography, spacing, radii, and color roles. Never invent raw colors or foreign fonts when tokens exist. +- Do not add gradients, blur, glow, glass, neon, decorative shadows, emoji, or unrelated content unless the explicit user direction requires it. +- Produce the requested number of materially different directions through hierarchy, layout, density, or existing color-role allocation. CSS-only no-ops and source-identical variants are invalid. +- Keep temporary Live markers and preview CSS out of accepted project truth; the publisher/Accept pipeline owns cleanup. + +## Workflow + +1. Trust `event.scaffold` when present. Do not rerun source discovery or wrapping. If it is absent, run the correct wrap/insert helper once. +2. If annotations exist, read the screenshot before designing. Treat pins and strokes as semantic constraints. +3. Name all directions and their parameter axes before writing so the set stays coherent. Parameters are lazy: revision 1 carries no parameter manifest. +4. Prepare revision 1 with `live-publish.mjs --prepare --id EVENT_ID --file SOURCE_FILE`. Edit only the returned artifact (or isolated component directory), never live project source. +5. Write one complete, valid first variant plus only its CSS. Publish it immediately with the returned epoch, artifact path, expected source hash, `--arrived 1`, and the requested `--expected` count. +6. Prepare again from the published prefix, add the remaining validated directions, attach parameter manifests only with the complete set, and publish the largest ready prefix. Preserve every already-published variant byte-for-byte. +7. On `stale_generation_epoch`, `source_changed`, or another fence rejection, stop. Do not retry against stale source or leave direct edits behind. +8. Verify the final artifact/source parses. Reply exactly once with `live-poll.mjs --reply EVENT_ID done --file RELATIVE_PATH`. On a real failure, reply once with `error` and a short reason. + +For Svelte or Vue component preview, write only `vN.svelte` / `vN.vue` in the isolated `componentDir` returned by prepare and update the isolated manifest. Never edit the live component directory. For JSX/TSX source previews, preserve JSX attribute syntax and wrap preview CSS as required by `scaffold.cssAuthoring`. + +Speed matters because the user is waiting. Publish the first reviewable result before exploring tunables, writing explanations, or polishing later variants. Return no recap: tool work and the protocol reply are the result. diff --git a/skill/reference/live.md b/skill/reference/live.md index 7d66da954..9a161ecce 100644 --- a/skill/reference/live.md +++ b/skill/reference/live.md @@ -26,7 +26,7 @@ The global bar **Impeccable mark** dims and shows a pulsing amber dot when no ag Harness policy: - **Claude Code**: run the poll as a **background task** (no short timeout). The harness notifies you when it completes, so the main conversation stays free. Do not block the shell. - **Cursor**: run **one-shot** poll in a **background terminal** with notify on `"type":"(steer|generate|accept|discard|exit)"`. After each event the poll exits; handle it, `--reply`, then start `live-poll.mjs` again. Do **not** use `--stream` on Cursor: incremental stdout notify is slower in practice than exit-based notify (~5s vs sub-second in testing). -- **Codex**: the main thread is the **foreground poll supervisor**. Keep the poll command itself in a yielded foreground exec session and retain its session id; do not suffix it with `&`. A yielded foreground process continues while other tool calls run, whereas a traditional shell-backgrounded child may be reaped when its shell exits. On `generate`, spawn one generation subagent/worker, give it the event plus scaffold, then poll again immediately in the main thread. The worker publishes variants and posts the generation reply; the supervisor remains available for early Accept/Discard and the next Go. Do not put the poll itself in a subagent or a fire-and-forget background shell: browser control events must return to the main thread immediately. +- **Codex**: the main thread is the **foreground poll supervisor**. Keep the poll command itself in a yielded foreground exec session and retain its session id; do not suffix it with `&`. A yielded foreground process continues while other tool calls run, whereas a traditional shell-backgrounded child may be reaped when its shell exits. On `generate`, delegate to the low-effort `impeccable_live_generator` agent when available. Give it a compact handoff: project/scripts paths, the complete event plus scaffold, the identity lock, relevant source/component excerpt, available tokens, and current design/product constraints. Do not paste this full reference into the handoff. The worker publishes variants and posts the generation reply; poll again immediately in the main thread so the supervisor remains available for early Accept/Discard and the next Go. If the named agent is unavailable, use one generic generation worker with the same compact contract. Do not put the poll itself in a subagent or a fire-and-forget background shell: browser control events must return to the main thread immediately. - **Other harnesses**: one-shot foreground unless you know stdout reliably returns to this session when a shell exits. Generation delivery policy: diff --git a/tests/live-reference.test.mjs b/tests/live-reference.test.mjs index dcb02dcf6..2dcd798ce 100644 --- a/tests/live-reference.test.mjs +++ b/tests/live-reference.test.mjs @@ -36,6 +36,7 @@ describe('live reference authoring contract', () => { it('keeps the live prompt focused on the foreground poll loop', () => { const liveMd = readFileSync(join(ROOT, 'skill/reference/live.md'), 'utf-8'); + const generationAgentMd = readFileSync(join(ROOT, 'skill/agents/impeccable-live-generator.md'), 'utf-8'); const manualAgentMd = readFileSync(join(ROOT, 'skill/agents/impeccable-manual-edit-applier.md'), 'utf-8'); const openingContract = liveMd.split('\n').slice(0, 60).join('\n'); @@ -60,6 +61,14 @@ describe('live reference authoring contract', () => { assert.match(liveMd, /delegate source edits to `impeccable_manual_edit_applier`/); assert.match(liveMd, /The subagent must not poll or reply/); assert.match(liveMd, /parent live thread keeps the foreground poll loop/); + assert.match(liveMd, /delegate to the low-effort `impeccable_live_generator` agent/); + assert.match(liveMd, /Do not paste this full reference into the handoff/); + assert.match(generationAgentMd, /codex-name: impeccable_live_generator/); + assert.match(generationAgentMd, /effort: low/); + assert.match(generationAgentMd, /providers: codex/); + assert.match(generationAgentMd, /Never poll, Accept, Discard/); + assert.match(generationAgentMd, /Publish the first reviewable result/); + assert.match(generationAgentMd, /preserve every already-published variant byte-for-byte/i); assert.match(liveMd, /live-accept\.mjs --page-url PAGE_URL/); assert.match(liveMd, /If `repair` is present/); assert.match(liveMd, /Fix the current source/);