diff --git a/scripts/benchmark-live.mjs b/scripts/benchmark-live.mjs
index 5e6755622..126626363 100644
--- a/scripts/benchmark-live.mjs
+++ b/scripts/benchmark-live.mjs
@@ -15,7 +15,7 @@ import {
waitForCycling,
waitForHandshake,
} from '../tests/live-e2e/ui.mjs';
-import { boolFlag, parseArgs, positiveIntFlag } from './lib/cli-args.mjs';
+import { boolFlag, parseArgs, positiveIntFlag, resolveEnum } from './lib/cli-args.mjs';
import {
buildInteractionRun,
assembleSplitProgressiveOutput,
@@ -28,9 +28,9 @@ const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const args = parseArgs(process.argv.slice(2));
const fixtureName = String(args.fixture || 'vite8-react-plain');
const iterations = positiveIntFlag(args.iterations, 5);
-const agentMode = args.agent === 'llm' ? 'llm' : 'fake';
-const scenario = args.scenario === 'annotated' ? 'annotated' : 'plain';
-const delivery = args.delivery === 'progressive' ? 'progressive' : 'atomic';
+const agentMode = resolveEnum(args.agent, ['fake', 'llm'], 'fake', '--agent');
+const scenario = resolveEnum(args.scenario, ['plain', 'annotated'], 'plain', '--scenario');
+const delivery = resolveEnum(args.delivery, ['atomic', 'progressive'], 'atomic', '--delivery');
const simulatedTailMs = positiveIntFlag(args.simulatedTailMs, 0);
const quiet = boolFlag(args.quiet);
const outputPath = args.output ? resolve(ROOT, String(args.output)) : null;
diff --git a/scripts/lib/cli-args.mjs b/scripts/lib/cli-args.mjs
index 3356d6b30..8e0a58efd 100644
--- a/scripts/lib/cli-args.mjs
+++ b/scripts/lib/cli-args.mjs
@@ -69,3 +69,19 @@ export function positiveIntFlag(value, fallback) {
}
return parsed;
}
+
+/**
+ * Resolve a flag that must be one of a fixed set.
+ *
+ * A silent `x === 'known' ? 'known' : fallback` is the trap this replaces: the
+ * private evals Live runner passes `--agent=codex`, which fell through to the
+ * canned fake agent and produced a clean-looking report of a deterministic stub
+ * labelled as a real harness run. An unrecognized value is a mistake, not a
+ * request for the default.
+ */
+export function resolveEnum(value, allowed, fallback, flagName) {
+ if (value === undefined || value === true) return fallback;
+ const normalized = String(value).trim().toLowerCase();
+ if (allowed.includes(normalized)) return normalized;
+ throw new Error(`${flagName} must be one of ${allowed.join(', ')}; got: ${value}`);
+}
diff --git a/scripts/lib/transformers/providers.js b/scripts/lib/transformers/providers.js
index 8351c4b22..009042d5f 100644
--- a/scripts/lib/transformers/providers.js
+++ b/scripts/lib/transformers/providers.js
@@ -22,7 +22,10 @@ export const PROVIDERS = {
},
'claude-code': {
provider: 'claude-code',
- providerTags: ['claude-code', 'claude'],
+ // live-progressive: Live delivers variant 1 as soon as it validates instead of
+ // one atomic edit. Claude Code polls in a background task, so the extra
+ // publish calls do not stall its control lane.
+ providerTags: ['claude-code', 'claude', 'live-progressive'],
configDir: '.claude',
displayName: 'Claude Code',
frontmatterFields: ['user-invocable', 'argument-hint', 'license', 'compatibility', 'metadata', 'allowed-tools'],
@@ -40,7 +43,7 @@ export const PROVIDERS = {
},
codex: {
provider: 'codex',
- providerTags: ['codex'],
+ providerTags: ['codex', 'live-progressive'],
configDir: '.codex',
displayName: 'Codex',
frontmatterFields: [],
@@ -54,7 +57,7 @@ export const PROVIDERS = {
},
agents: {
provider: 'agents',
- providerTags: ['agents', 'codex'],
+ providerTags: ['agents', 'codex', 'live-progressive'],
configDir: '.agents',
displayName: 'Codex Repo Skills',
placeholderProvider: 'codex',
diff --git a/scripts/lib/utils.js b/scripts/lib/utils.js
index 48a4c2c27..ca2954334 100644
--- a/scripts/lib/utils.js
+++ b/scripts/lib/utils.js
@@ -645,6 +645,11 @@ export const PROVIDER_BLOCK_TAGS = new Set([
'rovo-dev',
'trae',
'trae-cn',
+ // Capability tags. Not harness names: they mark instructions that belong to a
+ // shared capability several harnesses opt into. Listing the harnesses instead
+ // would mean duplicating the block body per provider tag, since a block takes
+ // one tag. Opt a provider in by adding the tag to its providerTags.
+ 'live-progressive',
]);
/**
diff --git a/skill/agents/impeccable-live-generator.md b/skill/agents/impeccable-live-generator.md
index 2935c9746..38cbf30ff 100644
--- a/skill/agents/impeccable-live-generator.md
+++ b/skill/agents/impeccable-live-generator.md
@@ -6,7 +6,6 @@ tools: Read, Write, Edit, Bash, Glob, Grep
model: inherit
effort: low
max-turns: 16
-providers: codex
nickname-candidates:
- Variant Producer
- Live Composer
@@ -15,7 +14,7 @@ nickname-candidates:
# 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.
+You own one leased Impeccable Live `generate` event. The parent thread owns browser control and the poll loop. Never poll, Accept, Discard, commit, stage, or edit generated provider output.
## Compact input contract
diff --git a/skill/reference/live.md b/skill/reference/live.md
index 4c939757c..560e2e685 100644
--- a/skill/reference/live.md
+++ b/skill/reference/live.md
@@ -17,24 +17,24 @@ Execute in order. No step skipped, no step reordered.
3. Poll loop with the default long timeout (600000 ms). Run `live-poll.mjs` again immediately after every event or `--reply`; Codex runs this one-shot poll in the foreground. Never pass a short `--timeout=`.
The global bar **Impeccable mark** dims and shows a pulsing amber dot when no agent is long-polling `/poll`. Hover the mark for the hint; restart `live-poll.mjs` to reconnect.
-4. On `generate`: reuse `event.scaffold` when present; read the screenshot if present; load the action's reference; deliver variants using the harness policy below; `--reply done`; poll again. In Codex, delegate the complete event to `impeccable_live_generator` and resume the foreground poll immediately; the generator owns publication and the reply.
+4. On `generate`: reuse `event.scaffold` when present; read the screenshot if present; load the action's reference; deliver variants using the harness policy below; `--reply done`; poll again. In Codex and Claude Code, delegate the complete event to `impeccable_live_generator` / `impeccable-live-generator` and resume polling immediately; the generator owns publication and the reply.
5. On `steer`: read the message and `pageUrl`; do the work (page edits, navigation help, or a short reply in the `--reply` message); `--reply steer_done`; poll again. No pickup ack. The Steer bar unlocks when `steer_done` arrives over SSE.
6. On `accept` / `discard`: the poll script runs `live-accept.mjs`, acknowledges the delivered event, and prints `_completionAck`. Plain accepts/discards are terminal immediately. Carbonize accepts remain recoverable until the foreground task runs `live-complete.mjs --id EVENT_ID`; finish that cleanup before polling again.
7. If interrupted, run `live-status.mjs` or `live-resume.mjs` before guessing. The durable journal replays unacknowledged work after helper restart.
8. On `exit`: run the cleanup at the bottom.
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.
+- **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. When `generate` arrives and native subagents are available, delegate the complete event to `impeccable-live-generator` with a compact handoff, then start the next poll immediately while that subagent publishes and replies; if unavailable, generate inline with the same contract. Do not paste this full reference into the handoff. The subagent's context is separate from yours, which is the point: a long session's screenshots, references, and variant CSS stay out of the main conversation. Handle Steer, Accept/Discard, manual Apply, carbonize, and Exit in the main conversation.
- **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**: run the default one-shot poll in a **yielded foreground exec session**. Do not suffix it with `&`, use `--stream`, or leave Live without an active foreground poll. When `generate` arrives, delegate to the low-effort `impeccable_live_generator` agent with a compact handoff, then immediately start the next foreground poll while that agent publishes and replies. Do not paste this full reference into the handoff. Handle Steer, Accept/Discard, manual Apply, carbonize, and Exit in the main task; after each handler/reply, restart the foreground poll.
- **Other harnesses**: one-shot foreground unless you know stdout reliably returns to this session when a shell exits.
Generation delivery policy:
-- **Default (Claude Code, Cursor, and other harnesses):** keep the established atomic single-edit delivery unless that harness has independently demonstrated that progressive tool calls are faster and reliable. This avoids trading model latency for extra tool-call latency on harnesses with different streaming behavior.
+- **Default (Cursor and other harnesses):** keep the established atomic single-edit delivery. Do not switch a harness to progressive until its poll loop is known not to block on the extra publish calls. This avoids trading model latency for extra tool-call latency on harnesses with different streaming behavior.
-
-- **Codex progressive override:** deliver progressively through `live-publish.mjs`, never by editing project source directly. Publish variant 1 as soon as it is complete, then publish each additional validated variant (or the largest ready prefix) without waiting for later siblings. Attach parameter CSS/manifests only with the complete set. The browser makes every arrived variant immediately reviewable and acceptable; Accept/Discard durably cancel unfinished revisions.
-
+
+- **Progressive delivery (Codex, Claude Code):** deliver progressively through `live-publish.mjs`, never by editing project source directly. Publish variant 1 as soon as it is complete, then publish each additional validated variant (or the largest ready prefix) without waiting for later siblings. Attach parameter CSS/manifests only with the complete set. The browser makes every arrived variant immediately reviewable and acceptable; Accept/Discard durably cancel unfinished revisions. The user reviews the first direction while the rest are still being written, so time-to-first-variant is what matters, not total time.
+
Chat is overhead. No recap, no tutorial output, no pasting PRODUCT / DESIGN bodies. Spend tokens on tools and edits; on failure, one or two short sentences.
@@ -314,14 +314,14 @@ Colocate preview CSS as a `