Skill Tracer
Skills › Compound Engineering › ce-doc-review › cross-model-review.md

cross-model-review.md

207 lines · skills/ce-doc-review/references/cross-model-review.md at 3449230

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Cross-Model Judgment Pass
2
3Runs ce-doc-review's **conditional judgment lenses** through one separately routed model target in read-only, least-privilege processes. Each peer gets the **same** persona brief the in-process reviewer uses, returns the same `findings-schema.json` shape, and folds into synthesis as reviewer `<reviewer-name>-<provider>`. It counts as independent corroboration and can promote agreement only when its result file records `independence_verified: true`; otherwise it remains attributed review evidence without a promotion bonus.
4
5The trio is the three **conditional** judgment lenses whose output diverges most across model families: `adversarial-document-reviewer`, `product-lens-reviewer`, `security-lens-reviewer`. The convergent lenses (`coherence`, `scope-guardian`) and the always-on `feasibility` lens do **not** run cross-model. Feasibility is excluded specifically so the pass stays conditional and does not spawn on every review.
6
7The host resolves and approves one concrete route before any document content leaves the machine (this reference calls that egress). The bundled **`scripts/cross-model-doc-review.sh`** enforces that fixed route, composes the prompt, applies least privilege, captures schema-shaped JSON, and normalizes the model-identity records it returns. The pass is non-blocking: a failed route writes no fold-in artifact and never switches recipients internally.
8

Cross-Model Judgment Pass

Runs ce-doc-review's conditional judgment lenses through one separately routed model target in read-only, least-privilege processes. Each peer gets the same persona brief the in-process reviewer uses, returns the same findings-schema.json shape, and folds into synthesis as reviewer <reviewer-name>-<provider>. It counts as independent corroboration and can promote agreement only when its result file records independence_verified: true; otherwise it remains attributed review evidence without a promotion bonus.

The trio is the three conditional judgment lenses whose output diverges most across model families: adversarial-document-reviewer, product-lens-reviewer, security-lens-reviewer. The convergent lenses (coherence, scope-guardian) and the always-on feasibility lens do not run cross-model. Feasibility is excluded specifically so the pass stays conditional and does not spawn on every review.

The host resolves and approves one concrete route before any document content leaves the machine (this reference calls that egress). The bundled **scripts/cross-model-doc-review.sh** enforces that fixed route, composes the prompt, applies least privilege, captures schema-shaped JSON, and normalizes the model-identity records it returns. The pass is non-blocking: a failed route writes no fold-in artifact and never switches recipients internally.

Raw lines 1 to 8
Starts an agent spawn :5
Runs code scripts/cross-model-doc-review.sh :7
9## Condition — run only when this holds
11Run the cross-model pass for a given trio lens **only when that lens was activated** for this document by the normal Phase 1 persona-selection logic. No new activation triggers are introduced: a routine plan with validated upstream provenance and no high-stakes domain activates none of the trio, so it gets no cross-model pass. Phase 1's missing-document check already guarantees the document is readable on disk. There is no diff and no remote-scope concern, so no additional scope check is needed.

Condition — run only when this holds

Run the cross-model pass for a given trio lens only when that lens was activated for this document by the normal Phase 1 persona-selection logic. No new activation triggers are introduced: a routine plan with validated upstream provenance and no high-stakes domain activates none of the trio, so it gets no cross-model pass. Phase 1's missing-document check already guarantees the document is readable on disk. There is no diff and no remote-scope concern, so no additional scope check is needed.

Raw lines 9 to 12
13## Step 1 — Attest host identity, then approve one fixed route
15Keep four identities separate: requested **target**, CLI **harness/intermediary**, serving **family/provider**, and served model. `cursor` means `cursor-agent` with its configured default/Auto model and therefore has no `--model` flag. `composer` means an explicit Composer-family model through `cursor-agent`. `grok` prefers the native Grok CLI; Grok through Cursor is a different route and recipient even though the requested target remains Grok. `antigravity` means a Gemini model through Google's Antigravity ACP runtime; a request for a Gemini peer binds target `antigravity`.
17Attest both the host harness and its serving family:
19```bash
20XHOST_SEEN=;
21if [ "${CLAUDECODE:-}" = "1" ]; then XHOST_SEEN="$XHOST_SEEN claude"; fi;
22if [ -n "${CODEX_SANDBOX:-}${CODEX_SANDBOX_NETWORK_DISABLED:-}${CODEX_SESSION_ID:-}${CODEX_THREAD_ID:-}${CODEX_CI:-}" ]; then XHOST_SEEN="$XHOST_SEEN codex"; fi;
23if [ "${GROK_AGENT:-}" = "1" ] || [ -n "${GROK_SESSION_ID:-}" ]; then XHOST_SEEN="$XHOST_SEEN grok"; fi;
24if [ -n "${OMPCODE:-}" ]; then XHOST_HARNESS=omp; XHOST_FAMILY=unknown;
25elif [ "$XHOST_SEEN" = " claude" ] || [ "$XHOST_SEEN" = " codex" ] || [ "$XHOST_SEEN" = " grok" ]; then XHOST_HARNESS="${XHOST_SEEN# }"; XHOST_FAMILY="$XHOST_HARNESS";
26elif [ -n "$XHOST_SEEN" ]; then XHOST_HARNESS=unknown; XHOST_FAMILY=unknown;
27elif [ -n "${CURSOR_AGENT:-}${CURSOR_CONVERSATION_ID:-}" ]; then XHOST_HARNESS=cursor; XHOST_FAMILY=unknown;
28elif [ -n "${OPENCODE_TERMINAL:-}" ]; then XHOST_HARNESS=opencode; XHOST_FAMILY=unknown;
29else XHOST_HARNESS=unknown; XHOST_FAMILY=unknown; fi
30```
32Pass `XHOST_HARNESS` as `CROSS_MODEL_HOST_HARNESS`; pass `XHOST_FAMILY` as the first worker argument. The snippet is evidence, not the verdict: it resolves the harnesses whose environment markers it already names, and where it yields `unknown` on a harness you can identify from your own runtime, attest what you know instead. A harness the snippet does not name needs no new branch here. Both tokens come from the peer-key vocabulary the worker accepts, never a provider's corporate name: family `codex`, `claude`, `grok`, `composer`, `gemini`, or `unknown`; harness `codex`, `claude`, `grok`, `cursor`, `opencode`, `antigravity`, `omp`, or `unknown`. A name such as `anthropic`, `openai`, or `xai` in either slot makes the worker stop with no artifact.
34Claude Code, Codex, and Grok each serve their own model family, so the snippet takes the family from that harness's marker when it is the only such marker present. Another harness can copy one of those markers (oh-my-pi sets `CLAUDECODE=1` whatever model serves it), and a session started from inside another harness inherits that harness's marker. So the snippet leaves family `unknown` under `OMPCODE` or when more than one of those markers is present. Pass a family the snippet names. Where it leaves family `unknown`, set it only from a model id the runtime publishes as the model serving this session, and only when that id maps to `codex`, `claude`, `grok`, `composer`, or `gemini`. A requested model, the model's own claim, and the product name are not that id. Never infer serving family from the Cursor brand. An unknown host family cannot satisfy automatic same-family exclusion, so skip the automatic cross-model pass.
36<!-- ce-config-layers:start -->
37**Resolve ordinary CE yaml keys from the two repo files.**
39- **Read** `<repo-root>/.compound-engineering/config.local.yaml`, then `config.yaml` (`<repo-root>` = `git rev-parse --show-toplevel`). Missing files are skipped. Gitignore does not change resolution.
40- **Win** with the first active (non-commented) value. For scalars, empty is unset; an invalid value continues to the next layer, then the skill default. For lists and maps, a present key — including an empty list or map — replaces the whole key.
41- **Do not** use this rule for `docs_root` — that key is `config.yaml` only.
42<!-- ce-config-layers:end -->
44**Checkout egress policy — evaluate this first.** Read `cross_model_review_mode:` from the same two repo CE config files under the ordinary-key rule. Valid values are `auto` (default) and `off`; anything else is invalid and continues to the next layer, then `auto`. When it resolves to `off`, skip the automatic cross-model pass here, before peer resolution, disclosure, or any job start, unless the user explicitly asked for a cross-model peer for this run in conversation (a `cross_model_peer` value or a project-instruction preference is not that opt-in). Record the skip reason as **disabled by checkout config**, distinct from an un-attestable host or an unavailable or non-independent route; each trio lens keeps its in-process twin exactly as it does for any peer that never started, and the whole-document sweep does not run. A live user prohibition still overrides `auto`.
46Resolve the preference in this order:
481. A preference the user **states in conversation** (e.g. "use grok for the cross-model pass").
492. `cross_model_peer:` from the two repo CE config files (`config.local.yaml` then `config.yaml`). Apply the ordinary-key rule: first active supported target wins; an invalid value continues to the next layer, then step 3.
503. A preference already in your **project instructions** (the active instructions in your context), taken from context and **never** read from a named file.
514. **Default:** first available attested-different target in `codex → claude → grok → antigravity`. Cursor default and Composer run only when one of steps 1-3 names them.
53Before any content is sent, resolve each selected target to one concrete installed route, announce it, and pass it as `CROSS_MODEL_FIXED_ROUTE`. `CROSS_MODEL_PEERS` is an optional egress restriction, not a required approval: when it is set, every recipient (target and intermediary) must be sanctioned by it under the alias rule below, and an unsanctioned recipient is a named skip; when it is unset or empty, no recipient is filtered and the pass proceeds. In that case this skill invocation plus the pre-egress disclosure is the sanction (in non-interactive mode the invoking skill's request is that sanction and the stderr audit log is the disclosure). Do not inspect the worker source to rediscover this; it implements exactly this contract. `CROSS_MODEL_FIXED_ROUTE` accepts exactly these tokens; the worker stops on anything else (including route-shaped guesses like `codex-cli`):
55| Target | Route token(s) |
56|--------|----------------|
57| `codex` | `codex` |
58| `claude` | `claude` |
59| `grok` | `grok-cli` (native CLI) or `grok-cursor` (via Cursor intermediary) |
60| `cursor` | `cursor` |
61| `composer` | `composer` |
62| `opencode` | `opencode` |
63| `antigravity` | `antigravity` |
65The host harness does not choose the Grok route. Target `grok` binds `grok-cli` when that CLI is installed. Bind `grok-cursor` only when the user asked for Grok through Cursor, or when the grok CLI is absent and Cursor is a sanctioned recipient.
67A failed dispatched route returns no artifact; it never changes provider or intermediary internally. Retrying the same resolved route retains its existing sanction and disclosure; changing the route or any recipient requires a new resolution, sanction, and disclosure before dispatch. The worker may repeat that same route once only after the route's adapter reports a provider overload (HTTP 529) as the prompt's error kind `overloaded`; it keeps the recipient, model, scope, and shared peer deadline fixed. Today only the Claude adapter reports that form; the other adapters retry overloads internally, so an overload that reaches the worker from them ends as an ordinary failure. For backward compatibility, either `cursor` or `composer` in `CROSS_MODEL_PEERS` sanctions Cursor as an intermediary, but selecting a Cursor-default voice itself requires target `cursor`; `grok` alone never sanctions Grok-via-Cursor. The Antigravity route is sanctioned only by the literal `antigravity`; `gemini` in `CROSS_MODEL_PEERS` admits nothing.
69**Checkout-configured model and effort.** After the target is resolved, read `cross_model_model:` and `cross_model_effort:` from the same two repo CE config files under the ordinary-key rule. When `cross_model_model` is set, pass `CROSS_MODEL_MODEL_OVERRIDE_TARGET=<resolved-target>` and `CROSS_MODEL_MODEL_OVERRIDE=<value>`; when `cross_model_effort` is set, pass `CROSS_MODEL_EFFORT_OVERRIDE=<value>`. Both ride the `env` prefix of the start invocation below. The worker validates each against the route it actually runs. A model must be the resolved target's own family (an alias such as `fable` or a full id such as `claude-opus-5-5` for `claude`; `gpt-*` for `codex`, optionally namespace-qualified such as `openai.gpt-6.1-sol` when that CLI routes through a non-default `model_provider`; `gemini-*` for `antigravity`); an effort must be a level the route's adapter offers, which for `antigravity` is its thinking level, `low`, `medium`, or `high`, and for `opencode` (2.x) is `none` through `max` as the model lists them; and cursor-agent routes accept no effort override. An incompatible value stops the pass with a named skip reason rather than substituting. Unset keys leave the script's editorial mapping unchanged. Announce the configured model and effort in the Step 3 line exactly as requested. A model or effort the user states in conversation outranks the config keys.
71Preferred model mappings run first. Only after the preferred ID is observed unavailable, obsolete, or incompatible may the host inspect current CLI capabilities and choose the closest compatible **same-target/same-family** replacement. Bind it with both `CROSS_MODEL_MODEL_OVERRIDE_TARGET=<target>` and `CROSS_MODEL_MODEL_OVERRIDE=<model-id>`. Never substitute across families, apply one target's override to another route, silently change an explicit model, or add a recipient.
73Target `antigravity` never takes a host-chosen replacement. Its worker requests Gemini 4 Argon and, when the account does not offer Argon, falls back once to Gemini Flash before any prompt is sent; the run log names the model used. A configured `antigravity` model runs exactly or the pass skips.

Step 1 — Attest host identity, then approve one fixed route

Keep four identities separate: requested target, CLI harness/intermediary, serving family/provider, and served model. cursor means cursor-agent with its configured default/Auto model and therefore has no --model flag. composer means an explicit Composer-family model through cursor-agent. grok prefers the native Grok CLI; Grok through Cursor is a different route and recipient even though the requested target remains Grok. antigravity means a Gemini model through Google's Antigravity ACP runtime; a request for a Gemini peer binds target antigravity.

Attest both the host harness and its serving family:

XHOST_SEEN=;
if [ "${CLAUDECODE:-}" = "1" ]; then XHOST_SEEN="$XHOST_SEEN claude"; fi;
if [ -n "${CODEX_SANDBOX:-}${CODEX_SANDBOX_NETWORK_DISABLED:-}${CODEX_SESSION_ID:-}${CODEX_THREAD_ID:-}${CODEX_CI:-}" ]; then XHOST_SEEN="$XHOST_SEEN codex"; fi;
if [ "${GROK_AGENT:-}" = "1" ] || [ -n "${GROK_SESSION_ID:-}" ]; then XHOST_SEEN="$XHOST_SEEN grok"; fi;
if [ -n "${OMPCODE:-}" ]; then XHOST_HARNESS=omp; XHOST_FAMILY=unknown;
elif [ "$XHOST_SEEN" = " claude" ] || [ "$XHOST_SEEN" = " codex" ] || [ "$XHOST_SEEN" = " grok" ]; then XHOST_HARNESS="${XHOST_SEEN# }"; XHOST_FAMILY="$XHOST_HARNESS";
elif [ -n "$XHOST_SEEN" ]; then XHOST_HARNESS=unknown; XHOST_FAMILY=unknown;
elif [ -n "${CURSOR_AGENT:-}${CURSOR_CONVERSATION_ID:-}" ]; then XHOST_HARNESS=cursor; XHOST_FAMILY=unknown;
elif [ -n "${OPENCODE_TERMINAL:-}" ]; then XHOST_HARNESS=opencode; XHOST_FAMILY=unknown;
else XHOST_HARNESS=unknown; XHOST_FAMILY=unknown; fi

Pass XHOST_HARNESS as CROSS_MODEL_HOST_HARNESS; pass XHOST_FAMILY as the first worker argument. The snippet is evidence, not the verdict: it resolves the harnesses whose environment markers it already names, and where it yields unknown on a harness you can identify from your own runtime, attest what you know instead. A harness the snippet does not name needs no new branch here. Both tokens come from the peer-key vocabulary the worker accepts, never a provider's corporate name: family codex, claude, grok, composer, gemini, or unknown; harness codex, claude, grok, cursor, opencode, antigravity, omp, or unknown. A name such as anthropic, openai, or xai in either slot makes the worker stop with no artifact.

Claude Code, Codex, and Grok each serve their own model family, so the snippet takes the family from that harness's marker when it is the only such marker present. Another harness can copy one of those markers (oh-my-pi sets CLAUDECODE=1 whatever model serves it), and a session started from inside another harness inherits that harness's marker. So the snippet leaves family unknown under OMPCODE or when more than one of those markers is present. Pass a family the snippet names. Where it leaves family unknown, set it only from a model id the runtime publishes as the model serving this session, and only when that id maps to codex, claude, grok, composer, or gemini. A requested model, the model's own claim, and the product name are not that id. Never infer serving family from the Cursor brand. An unknown host family cannot satisfy automatic same-family exclusion, so skip the automatic cross-model pass.

<!-- ce-config-layers:start --> Resolve ordinary CE yaml keys from the two repo files.

  • Read <repo-root>/.compound-engineering/config.local.yaml, then config.yaml (<repo-root> = git rev-parse --show-toplevel). Missing files are skipped. Gitignore does not change resolution.
  • Win with the first active (non-commented) value. For scalars, empty is unset; an invalid value continues to the next layer, then the skill default. For lists and maps, a present key — including an empty list or map — replaces the whole key.
  • Do not use this rule for docs_root — that key is config.yaml only.

<!-- ce-config-layers:end -->

Checkout egress policy — evaluate this first. Read cross_model_review_mode: from the same two repo CE config files under the ordinary-key rule. Valid values are auto (default) and off; anything else is invalid and continues to the next layer, then auto. When it resolves to off, skip the automatic cross-model pass here, before peer resolution, disclosure, or any job start, unless the user explicitly asked for a cross-model peer for this run in conversation (a cross_model_peer value or a project-instruction preference is not that opt-in). Record the skip reason as disabled by checkout config, distinct from an un-attestable host or an unavailable or non-independent route; each trio lens keeps its in-process twin exactly as it does for any peer that never started, and the whole-document sweep does not run. A live user prohibition still overrides auto.

Resolve the preference in this order:

  1. A preference the user states in conversation (e.g. "use grok for the cross-model pass").
  2. cross_model_peer: from the two repo CE config files (config.local.yaml then config.yaml). Apply the ordinary-key rule: first active supported target wins; an invalid value continues to the next layer, then step 3.
  3. A preference already in your project instructions (the active instructions in your context), taken from context and never read from a named file.
  4. Default: first available attested-different target in codex → claude → grok → antigravity. Cursor default and Composer run only when one of steps 1-3 names them.

Before any content is sent, resolve each selected target to one concrete installed route, announce it, and pass it as CROSS_MODEL_FIXED_ROUTE. CROSS_MODEL_PEERS is an optional egress restriction, not a required approval: when it is set, every recipient (target and intermediary) must be sanctioned by it under the alias rule below, and an unsanctioned recipient is a named skip; when it is unset or empty, no recipient is filtered and the pass proceeds. In that case this skill invocation plus the pre-egress disclosure is the sanction (in non-interactive mode the invoking skill's request is that sanction and the stderr audit log is the disclosure). Do not inspect the worker source to rediscover this; it implements exactly this contract. CROSS_MODEL_FIXED_ROUTE accepts exactly these tokens; the worker stops on anything else (including route-shaped guesses like codex-cli):

TargetRoute token(s)
codexcodex
claudeclaude
grokgrok-cli (native CLI) or grok-cursor (via Cursor intermediary)
cursorcursor
composercomposer
opencodeopencode
antigravityantigravity

The host harness does not choose the Grok route. Target grok binds grok-cli when that CLI is installed. Bind grok-cursor only when the user asked for Grok through Cursor, or when the grok CLI is absent and Cursor is a sanctioned recipient.

A failed dispatched route returns no artifact; it never changes provider or intermediary internally. Retrying the same resolved route retains its existing sanction and disclosure; changing the route or any recipient requires a new resolution, sanction, and disclosure before dispatch. The worker may repeat that same route once only after the route's adapter reports a provider overload (HTTP 529) as the prompt's error kind overloaded; it keeps the recipient, model, scope, and shared peer deadline fixed. Today only the Claude adapter reports that form; the other adapters retry overloads internally, so an overload that reaches the worker from them ends as an ordinary failure. For backward compatibility, either cursor or composer in CROSS_MODEL_PEERS sanctions Cursor as an intermediary, but selecting a Cursor-default voice itself requires target cursor; grok alone never sanctions Grok-via-Cursor. The Antigravity route is sanctioned only by the literal antigravity; gemini in CROSS_MODEL_PEERS admits nothing.

Checkout-configured model and effort. After the target is resolved, read cross_model_model: and cross_model_effort: from the same two repo CE config files under the ordinary-key rule. When cross_model_model is set, pass CROSS_MODEL_MODEL_OVERRIDE_TARGET=<resolved-target> and CROSS_MODEL_MODEL_OVERRIDE=<value>; when cross_model_effort is set, pass CROSS_MODEL_EFFORT_OVERRIDE=<value>. Both ride the env prefix of the start invocation below. The worker validates each against the route it actually runs. A model must be the resolved target's own family (an alias such as fable or a full id such as claude-opus-5-5 for claude; gpt-* for codex, optionally namespace-qualified such as openai.gpt-6.1-sol when that CLI routes through a non-default model_provider; gemini-* for antigravity); an effort must be a level the route's adapter offers, which for antigravity is its thinking level, low, medium, or high, and for opencode (2.x) is none through max as the model lists them; and cursor-agent routes accept no effort override. An incompatible value stops the pass with a named skip reason rather than substituting. Unset keys leave the script's editorial mapping unchanged. Announce the configured model and effort in the Step 3 line exactly as requested. A model or effort the user states in conversation outranks the config keys.

Preferred model mappings run first. Only after the preferred ID is observed unavailable, obsolete, or incompatible may the host inspect current CLI capabilities and choose the closest compatible same-target/same-family replacement. Bind it with both CROSS_MODEL_MODEL_OVERRIDE_TARGET=<target> and CROSS_MODEL_MODEL_OVERRIDE=<model-id>. Never substitute across families, apply one target's override to another route, silently change an explicit model, or add a recipient.

Target antigravity never takes a host-chosen replacement. Its worker requests Gemini 4 Argon and, when the account does not offer Argon, falls back once to Gemini Flash before any prompt is sent; the run log names the model used. A configured antigravity model runs exactly or the pass skips.

Raw lines 13 to 74
Starts an agent dispatched :67
Starts an agent dispatch :67
75## Step 2 — Provider model + reasoning tier (defined in the script)
77All activated lenses run on **one model per provider at high reasoning, except Codex and native Grok on extra-high**. The cursor-agent Grok route uses Cursor's high/fast preset, because Cursor offers one preset per model; composer's fast tier is its ceiling, an accepted exception. The concrete model IDs and per-route reasoning flags live in a **single mapping in the script** (`scripts/cross-model-doc-review.sh`, the `M_CODEX`/`M_CLAUDE`/`M_GROK`/`M_GROK_CURSOR`/`M_COMPOSER`/`M_ANTIGRAVITY` constants and the `adapter_argv` builder). A checkout may pin the resolved target's model and effort through `cross_model_model` / `cross_model_effort` (Step 1); the script validates and never substitutes. This reference deliberately does **not** restate the IDs; one source of truth prevents the reference and script from drifting. The IDs are the current choice under the tier rule (a single maintenance point), not the contract.
79The **persona file** basename and the **reviewer name** are distinct: the script reads the brief from `references/personas/<persona-file>.md` but forces the fold-in `reviewer` field to `<reviewer-name>-<provider>` so agreement matches the in-process persona's short name. The script derives the persona file from the allowlisted reviewer name. It is **not** a caller argument, so no caller value reaches the brief-read path.

Step 2 — Provider model + reasoning tier (defined in the script)

All activated lenses run on one model per provider at high reasoning, except Codex and native Grok on extra-high. The cursor-agent Grok route uses Cursor's high/fast preset, because Cursor offers one preset per model; composer's fast tier is its ceiling, an accepted exception. The concrete model IDs and per-route reasoning flags live in a single mapping in the script (scripts/cross-model-doc-review.sh, the M_CODEX/M_CLAUDE/M_GROK/M_GROK_CURSOR/M_COMPOSER/M_ANTIGRAVITY constants and the adapter_argv builder). A checkout may pin the resolved target's model and effort through cross_model_model / cross_model_effort (Step 1); the script validates and never substitutes. This reference deliberately does not restate the IDs; one source of truth prevents the reference and script from drifting. The IDs are the current choice under the tier rule (a single maintenance point), not the contract.

The persona file basename and the reviewer name are distinct: the script reads the brief from references/personas/<persona-file>.md but forces the fold-in reviewer field to <reviewer-name>-<provider> so agreement matches the in-process persona's short name. The script derives the persona file from the allowlisted reviewer name. It is not a caller argument, so no caller value reaches the brief-read path.

Raw lines 75 to 80
Runs code scripts/cross-model-doc-review.sh :77
81## Step 3 — Announce
83Pre-dispatch eligibility is based on installed route presence and sanction, not credential state. Do not run authentication probes before the provider-capable launch; authentication is authoritative only after provider-capable dispatch.
85- **Interactive host, default interactive mode:** show a **prominent standalone line** that frames it as an **independent cross-model review** of the judgment lenses (say "cross-model" / "independent model", not the internal "peer" jargon). The line names the concrete **model and reasoning level** from the in-script mapping (e.g. GPT-6-luna at extra-high reasoning, Opus at high, Grok 4.7 at extra-high, Composer 2.5-fast). Because two different models can arrive over the *same* `cursor-agent` CLI, it names **the route as well as the model** for cursor-agent routes so Grok-4.7-via-cursor-agent, Composer-via-cursor-agent, and Grok-4.7-via-the-grok-CLI are unambiguous. **It states that full document content is sent to that provider** (third-party egress; for cursor-agent routes the content goes to Cursor *plus* the serving provider). **One disclosure condition governs the announce and every later mention of the peer:** name it by target and requested model, as a request ("requested <model>"), never as a claim that this model served. Add a serving caveat only when a served-model record disagrees with the request, or when the route requested no model (Cursor default/Auto says "serving model unverified"). A receipt-less route with a requested model gets no caveat: `model_actual: unverified` means no record, not an unknown model. Place it with the Phase 2 team announce, not buried after it. Wording is yours; the checkable requirements are: prominent, reads as a **cross-model reviewer** (not a generic persona), names the requested model as requested, names the route when it is cursor-agent, names the egress. Example: `🔀 Cross-model pass — the judgment lenses are also being reviewed by an independent model: requested **Grok 4.7 (high reasoning), via cursor-agent**. Full document content is sent to xAI/Cursor.`
86 - Call the pass **independent** only when host and target serving families are attestably different. For Cursor default/Auto or an unknown host family, call it a cross-harness review and state that independence is unverified; do not promise agreement promotion before the served-model record exists.
87 - Announce the one fixed route and every recipient before dispatch. A route failure produces no artifact; apply Step 1's retry/disclosure condition before another attempt. Reconcile `cross_model_target`, `cross_model_harness`, `cross_model_route`, `model_requested`, and `model_actual` from the artifact; never infer a serving model from the requested ID. The disclosure condition above decides how the peer is named in the report.
88- **Interactive host, no peer resolved** (host un-attestable, no different-provider route installed, or disabled by checkout config): one quiet line that the cross-model pass was skipped and why; name the checkout policy when that is the reason. Never an error.
89- **Non-interactive mode:** do not announce the pass. The script still emits a one-line stderr audit log per send that document content was sent cross-model to the named provider, so the third-party data egress is auditable even though the pass does not announce to the user. Non-interactive applies the same conditions as interactive: an installed, sanctioned, attested-different route runs under the Step 1 contract, unset allowlist included. When a trio lens was activated, the structured result still records whether a peer artifact was folded, in the form `references/synthesis-and-presentation.md` defines.

Step 3 — Announce

Pre-dispatch eligibility is based on installed route presence and sanction, not credential state. Do not run authentication probes before the provider-capable launch; authentication is authoritative only after provider-capable dispatch.

  • Interactive host, default interactive mode: show a prominent standalone line that frames it as an independent cross-model review of the judgment lenses (say "cross-model" / "independent model", not the internal "peer" jargon). The line names the concrete model and reasoning level from the in-script mapping (e.g. GPT-6-luna at extra-high reasoning, Opus at high, Grok 4.7 at extra-high, Composer 2.5-fast). Because two different models can arrive over the same cursor-agent CLI, it names the route as well as the model for cursor-agent routes so Grok-4.7-via-cursor-agent, Composer-via-cursor-agent, and Grok-4.7-via-the-grok-CLI are unambiguous. It states that full document content is sent to that provider (third-party egress; for cursor-agent routes the content goes to Cursor plus the serving provider). One disclosure condition governs the announce and every later mention of the peer: name it by target and requested model, as a request ("requested <model>"), never as a claim that this model served. Add a serving caveat only when a served-model record disagrees with the request, or when the route requested no model (Cursor default/Auto says "serving model unverified"). A receipt-less route with a requested model gets no caveat: model_actual: unverified means no record, not an unknown model. Place it with the Phase 2 team announce, not buried after it. Wording is yours; the checkable requirements are: prominent, reads as a cross-model reviewer (not a generic persona), names the requested model as requested, names the route when it is cursor-agent, names the egress. Example: 🔀 Cross-model pass — the judgment lenses are also being reviewed by an independent model: requested **Grok 4.7 (high reasoning), via cursor-agent**. Full document content is sent to xAI/Cursor.
  • Call the pass independent only when host and target serving families are attestably different. For Cursor default/Auto or an unknown host family, call it a cross-harness review and state that independence is unverified; do not promise agreement promotion before the served-model record exists.
  • Announce the one fixed route and every recipient before dispatch. A route failure produces no artifact; apply Step 1's retry/disclosure condition before another attempt. Reconcile cross_model_target, cross_model_harness, cross_model_route, model_requested, and model_actual from the artifact; never infer a serving model from the requested ID. The disclosure condition above decides how the peer is named in the report.
  • Interactive host, no peer resolved (host un-attestable, no different-provider route installed, or disabled by checkout config): one quiet line that the cross-model pass was skipped and why; name the checkout policy when that is the reason. Never an error.
  • Non-interactive mode: do not announce the pass. The script still emits a one-line stderr audit log per send that document content was sent cross-model to the named provider, so the third-party data egress is auditable even though the pass does not announce to the user. Non-interactive applies the same conditions as interactive: an installed, sanctioned, attested-different route runs under the Step 1 contract, unset allowlist included. When a trio lens was activated, the structured result still records whether a peer artifact was folded, in the form references/synthesis-and-presentation.md defines.
Raw lines 81 to 90
Starts an agent dispatch :83
91## Step 4 — Run the bundled script (one call per activated trio lens, in parallel with the persona reviewers)
93Each call is a CLI shell-out, not a subagent. Resolve one target and one fixed route once per document review, then launch every activated lens against that same sanctioned target/route. Launch each call as a detached job through `scripts/peer-job-runner.py` in the same dispatch wave as the in-process reviewers. A failed route does not fall through inside the worker.
95**Two modes — slice the trio, sweep the whole doc:**
97- **Trio peers, sliced.** On **unified artifacts**, pass each activated trio lens the *same reviewer-specific slice its in-process twin got* as `<document-path>` (write that slice to a temp file — e.g. product-lens/adversarial get the Product Contract), not the full document, so the peer is a true corroborating twin rather than an off-lens reviewer. On legacy docs the peer gets the same full document the twin does.
98- **One whole-doc sweep.** In the **same wave**, also launch **one** call with reviewer-name **`whole-doc`**, the **full** document (never sliced), and the same resolved provider — a broad different-model read of the entire doc. It runs **once per document** (not per lens), writes `whole-doc-<provider>.json`, and folds in as an independent reviewer that corroborates against *any* in-process finding 3.3 merged it with (it has no in-process twin). Same gate, isolation, and non-blocking rules as the trio calls. A model following this contract MUST issue this `whole-doc` invocation whenever the pass runs, or the broad coverage the sweep exists to provide is silently skipped.
100Invoke via the skill-dir anchor — set `SKILL_DIR` to the absolute directory of **this** skill's `SKILL.md` (the Bash tool's CWD is the user's project, not the skill dir, on every host; shell state does not persist between Bash calls, so set it inline in every runner call):
102**Interpreter.** The commands below run a bundled Python script. Resolve the
103interpreter in the *same* shell call as the command -- each tool call is a fresh
104shell, so a `$PY` set in an earlier call does not persist. Do not hardcode
105`python3`: on native Windows it resolves to a Microsoft Store stub that exits
106without running Python, and that stub still satisfies `command -v`, so probe
107execution rather than presence.
109```bash
110PY="$(for c in python3 python py; do command -v "$c" >/dev/null 2>&1 && "$c" -c '' >/dev/null 2>&1 && { echo "$c"; break; }; done)"; [ -n "$PY" ] || { echo "no working Python 3 interpreter on PATH" >&2; exit 1; };
111```
113**Host command-sandbox boundary.** The detached worker inherits the permission context of the `start` call that launches it. Before executing that exact call, treat `CODEX_SANDBOX_NETWORK_DISABLED` as a positive signal that the current Codex command sandbox cannot reach the provider; unsetting it does not change the sandbox policy. A DNS or authentication failure alone is not proof of that condition. Use the narrowest host permission that restores the fixed route's provider connection. When Codex exposes only full command escalation, attach this request to the exact `peer-job-runner.py start ...` tool call after the existing egress disclosure:
115```json
117 "sandbox_permissions": "require_escalated",
118 "justification": "Allow the disclosed read-only cross-model review to send the reviewed document to the fixed external provider."
120```
122Disclose that this is not launcher-only isolation: the detached worker inherits that launch context for its lifetime, so the adapter's declared read-only/tool restrictions — not the Codex command sandbox — bound the peer while the reviewed material egresses. If the grant is denied or unavailable, do not execute `start`; create no peer job and retain the in-process reviewers as coverage. After `start` returns a job id, any network, authentication, or provider failure is a started-job outcome and follows the ordinary terminal/recovery rules; keep `status`, `wait`, `result`, and `reap` sandboxed because they need no provider connection.
124```bash
125SKILL_DIR="<absolute path of the directory containing the ce-doc-review SKILL.md you read>";
126PY="$(for c in python3 python py; do command -v "$c" >/dev/null 2>&1 && "$c" -c '' >/dev/null 2>&1 && { echo "$c"; break; }; done)"; [ -n "$PY" ] || { echo "no working Python 3 interpreter on PATH" >&2; exit 1; };
127SCRATCH_ROOT="/tmp/compound-engineering-$(id -u)";
128[ ! -L "$SCRATCH_ROOT" ] && (umask 077; mkdir -p "$SCRATCH_ROOT") 2>/dev/null && [ ! -L "$SCRATCH_ROOT" ] && [ -O "$SCRATCH_ROOT" ] && [ -w "$SCRATCH_ROOT" ] || SCRATCH_ROOT="${TMPDIR:-/tmp}/compound-engineering-$(id -u)";
129if [ -L "$SCRATCH_ROOT" ]; then echo "unsafe scratch root symlink: $SCRATCH_ROOT" >&2; exit 1; fi;
130(umask 077; mkdir -p "$SCRATCH_ROOT") || exit 1;
131if [ -L "$SCRATCH_ROOT" ] || [ ! -O "$SCRATCH_ROOT" ]; then echo "scratch root is not owned by the current user: $SCRATCH_ROOT" >&2; exit 1; fi;
132chmod 700 "$SCRATCH_ROOT" || exit 1;
133RUN_DIR="$SCRATCH_ROOT/ce-doc-review/<run-id>"; (umask 077; mkdir -p "$RUN_DIR") || exit 1; chmod 700 "$RUN_DIR" || exit 1;
134echo "peer-deadline-secs=$(( ${CROSS_MODEL_HARD_SECS:-1200} + 10 ))";
135CE_PEER_HARD_SECS= CROSS_MODEL_HOST_HARNESS="<host-harness>" CROSS_MODEL_FIXED_ROUTE="<fixed-route>" "$PY" "$SKILL_DIR/scripts/peer-job-runner.py" start --skill ce-doc-review --run-id "<run-id>" --label "<reviewer-name>" -- env CROSS_MODEL_HOST_HARNESS="<host-harness>" CROSS_MODEL_FIXED_ROUTE="<fixed-route>" bash "$SKILL_DIR/scripts/cross-model-doc-review.sh" "<host-serving-family>" "<target>" "<reviewer-name>" "<document-path>" "<document-type>" "<origin>" "$RUN_DIR"
136```
138When Step 1 resolved a configured model or effort, add `CROSS_MODEL_MODEL_OVERRIDE_TARGET="<target>" CROSS_MODEL_MODEL_OVERRIDE="<model>"` and/or `CROSS_MODEL_EFFORT_OVERRIDE="<effort>"` to the `env` prefix after `CROSS_MODEL_FIXED_ROUTE`; omit them when unset.
140The nested windows are one budget with one knob, `CROSS_MODEL_HARD_SECS`. The runner derives its supervisor hard window from that ambient knob automatically (`max(1230, knob + 30)`). Clear `CE_PEER_HARD_SECS` on the start prefix (`CE_PEER_HARD_SECS=`) so a stale ambient value from an earlier session or harness export cannot undercut that derivation. An explicit numeric `CE_PEER_HARD_SECS` still wins when a skill deliberately sets one (ce-work / elevation), which this path must not do. Print the orchestrator deadline as `knob + 10` in the same shell as `start` (as above) and use that printed `peer-deadline-secs=<n>` below (all legs share the one value; re-use the first leg's number rather than re-deriving per leg); never hardcode it, because a literal survives a knob change and then reaps a healthy peer.
142**Do not forward `CROSS_MODEL_HARD_SECS` to the worker.** The runner already passes the ambient environment through, so a knob the user actually set reaches the worker on its own. Re-exporting the orchestrator's *resolved* value would turn a fallback into an explicit override and strip the worker of its own default.
144Omit `--result-path`; `done` means only that the worker exited. The fixed target determines the expected `<reviewer-name>-<target>.json` filename.
146- `<host-serving-family>` is `codex`, `claude`, `grok`, `composer`, `gemini`, or `unknown`; `<host-harness>` is `codex`, `claude`, `grok`, `cursor`, `opencode`, `antigravity`, `omp`, or `unknown`.
147- `<target>` is exactly one of `codex`, `claude`, `grok`, `cursor`, `composer`, `opencode`, or `antigravity`; `<fixed-route>` is its already-sanctioned concrete route token from the Step 1 table (`codex`, `claude`, `grok-cli`, `grok-cursor`, `cursor`, `composer`, `opencode`, or `antigravity`).
148- `<reviewer-name>` = the activated lens (`security-lens`, `adversarial`, or `product-lens`). The script derives the persona-brief filename and (per provider) model from this allowlisted value — the brief path is never caller-controlled.
149- `<document-path>` = the document under review.
150- `<document-type>` = the Phase 1 classification (`requirements` / `plan` / `unified-requirements` / `unified-plan`).
151- `<origin>` = the same `{origin_path}` slot the in-process personas receive.
152- `<run-dir>` = the absolute `$RUN_DIR` resolved above. The script writes `<reviewer-name>-<provider>.json` there per resolved peer **only after** forcing `reviewer` to `<reviewer-name>-<provider>` and downgrading peer `safe_auto` → `gated_auto`.
154Every runner call is bounded: no tool call ever spans a worker's runtime, on any host. Between dispatch waves, poll outstanding jobs (it returns early when the watched jobs settle):
156```bash
157SKILL_DIR="<absolute path of the directory containing the ce-doc-review SKILL.md you read>";
158PY="$(for c in python3 python py; do command -v "$c" >/dev/null 2>&1 && "$c" -c '' >/dev/null 2>&1 && { echo "$c"; break; }; done)"; [ -n "$PY" ] || { echo "no working Python 3 interpreter on PATH" >&2; exit 1; };
159"$PY" "$SKILL_DIR/scripts/peer-job-runner.py" wait --max-secs 30 --json <job-ids...>
160```
162Capture the epoch time right after the final `start` (`date +%s`). That timestamp is how you know when the deadline passes, since nothing else tracks wall clock across tool calls. Before synthesis or any return, bring every started job to a terminal outcome. While its result is still needed, loop bounded `wait` calls until the job is terminal **or the shared peer deadline (`peer-deadline-secs`) has elapsed since the final `start`**. Compare `date +%s` against that timestamp before each wait; do not begin a wait that would extend past the deadline. Reap unfinished jobs whose results are no longer needed or whose deadline is exhausted, then run one final bounded `wait --max-secs 10` pass (reap is asynchronous; the terminal record lands a grace period after it returns). Collect and classify each started job under Step 5. The detached script still self-bounds (idle-timeout default 480s on every route; hard backstop `CROSS_MODEL_HARD_SECS` default 1200s) and exits cleanly; the runner's supervisor windows sit outside those caps as the backstop. The script needs no prompt or schema passed in — it reads the persona brief, `findings-schema.json`, and the document itself from disk.
164Any started job whose terminal state is not `done` (`failed` / `timeout` / `died-without-result`) is named in the Coverage line with its lens and terminal state (e.g. "cross-model security-lens peer: timeout"). A job reaped at the deadline records `timeout`, with the reap noted in its reason. A preflight failure never yields a job id: a genuine condition-not-met skip is the `never-started` case, but a dispatch-infrastructure crash before any job starts is not a clean skip and triggers the hand-recovery rule in Step 5. A never-started pass does not get a started-job terminal-state line and does not fail the review. In non-interactive mode, the structured result records every owed lens that did not fold, whether its job started or not, in the form `references/synthesis-and-presentation.md` defines. A missing fold-in file is still "the pass didn't run for that lens," never a review failure, except when a dispatch-infrastructure crash voided the whole pass at once, which Step 5 handles as named whole-pass loss (the whole-doc broad read especially), not per-lens "not run."
166The cross-model pass does **not** receive the accumulated decision primer that in-process personas get on round 2+; the peer prompt carries a round-1 framing regardless of round. This is deliberate (cross-model is most valuable on the first pass). Synthesis's own R29/R30 suppression catches re-raised or already-resolved findings, so a peer that re-raises a prior-round-rejected finding is dropped at synthesis, not shown.

Step 4 — Run the bundled script (one call per activated trio lens, in parallel with the persona reviewers)

Each call is a CLI shell-out, not a subagent. Resolve one target and one fixed route once per document review, then launch every activated lens against that same sanctioned target/route. Launch each call as a detached job through scripts/peer-job-runner.py in the same dispatch wave as the in-process reviewers. A failed route does not fall through inside the worker.

Two modes — slice the trio, sweep the whole doc:

  • Trio peers, sliced. On unified artifacts, pass each activated trio lens the same reviewer-specific slice its in-process twin got as <document-path> (write that slice to a temp file — e.g. product-lens/adversarial get the Product Contract), not the full document, so the peer is a true corroborating twin rather than an off-lens reviewer. On legacy docs the peer gets the same full document the twin does.
  • One whole-doc sweep. In the same wave, also launch one call with reviewer-name **whole-doc, the full document (never sliced), and the same resolved provider — a broad different-model read of the entire doc. It runs once per document** (not per lens), writes whole-doc-<provider>.json, and folds in as an independent reviewer that corroborates against any in-process finding 3.3 merged it with (it has no in-process twin). Same gate, isolation, and non-blocking rules as the trio calls. A model following this contract MUST issue this whole-doc invocation whenever the pass runs, or the broad coverage the sweep exists to provide is silently skipped.

Invoke via the skill-dir anchor — set SKILL_DIR to the absolute directory of this skill's SKILL.md (the Bash tool's CWD is the user's project, not the skill dir, on every host; shell state does not persist between Bash calls, so set it inline in every runner call):

Interpreter. The commands below run a bundled Python script. Resolve the interpreter in the same shell call as the command -- each tool call is a fresh shell, so a $PY set in an earlier call does not persist. Do not hardcode python3: on native Windows it resolves to a Microsoft Store stub that exits without running Python, and that stub still satisfies command -v, so probe execution rather than presence.

PY="$(for c in python3 python py; do command -v "$c" >/dev/null 2>&1 && "$c" -c '' >/dev/null 2>&1 && { echo "$c"; break; }; done)"; [ -n "$PY" ] || { echo "no working Python 3 interpreter on PATH" >&2; exit 1; };

Host command-sandbox boundary. The detached worker inherits the permission context of the start call that launches it. Before executing that exact call, treat CODEX_SANDBOX_NETWORK_DISABLED as a positive signal that the current Codex command sandbox cannot reach the provider; unsetting it does not change the sandbox policy. A DNS or authentication failure alone is not proof of that condition. Use the narrowest host permission that restores the fixed route's provider connection. When Codex exposes only full command escalation, attach this request to the exact peer-job-runner.py start ... tool call after the existing egress disclosure:

{
  "sandbox_permissions": "require_escalated",
  "justification": "Allow the disclosed read-only cross-model review to send the reviewed document to the fixed external provider."
}

Disclose that this is not launcher-only isolation: the detached worker inherits that launch context for its lifetime, so the adapter's declared read-only/tool restrictions — not the Codex command sandbox — bound the peer while the reviewed material egresses. If the grant is denied or unavailable, do not execute start; create no peer job and retain the in-process reviewers as coverage. After start returns a job id, any network, authentication, or provider failure is a started-job outcome and follows the ordinary terminal/recovery rules; keep status, wait, result, and reap sandboxed because they need no provider connection.

SKILL_DIR="<absolute path of the directory containing the ce-doc-review SKILL.md you read>";
PY="$(for c in python3 python py; do command -v "$c" >/dev/null 2>&1 && "$c" -c '' >/dev/null 2>&1 && { echo "$c"; break; }; done)"; [ -n "$PY" ] || { echo "no working Python 3 interpreter on PATH" >&2; exit 1; };
SCRATCH_ROOT="/tmp/compound-engineering-$(id -u)";
[ ! -L "$SCRATCH_ROOT" ] && (umask 077; mkdir -p "$SCRATCH_ROOT") 2>/dev/null && [ ! -L "$SCRATCH_ROOT" ] && [ -O "$SCRATCH_ROOT" ] && [ -w "$SCRATCH_ROOT" ] || SCRATCH_ROOT="${TMPDIR:-/tmp}/compound-engineering-$(id -u)";
if [ -L "$SCRATCH_ROOT" ]; then echo "unsafe scratch root symlink: $SCRATCH_ROOT" >&2; exit 1; fi;
(umask 077; mkdir -p "$SCRATCH_ROOT") || exit 1;
if [ -L "$SCRATCH_ROOT" ] || [ ! -O "$SCRATCH_ROOT" ]; then echo "scratch root is not owned by the current user: $SCRATCH_ROOT" >&2; exit 1; fi;
chmod 700 "$SCRATCH_ROOT" || exit 1;
RUN_DIR="$SCRATCH_ROOT/ce-doc-review/<run-id>"; (umask 077; mkdir -p "$RUN_DIR") || exit 1; chmod 700 "$RUN_DIR" || exit 1;
echo "peer-deadline-secs=$(( ${CROSS_MODEL_HARD_SECS:-1200} + 10 ))";
CE_PEER_HARD_SECS= CROSS_MODEL_HOST_HARNESS="<host-harness>" CROSS_MODEL_FIXED_ROUTE="<fixed-route>" "$PY" "$SKILL_DIR/scripts/peer-job-runner.py" start --skill ce-doc-review --run-id "<run-id>" --label "<reviewer-name>" -- env CROSS_MODEL_HOST_HARNESS="<host-harness>" CROSS_MODEL_FIXED_ROUTE="<fixed-route>" bash "$SKILL_DIR/scripts/cross-model-doc-review.sh" "<host-serving-family>" "<target>" "<reviewer-name>" "<document-path>" "<document-type>" "<origin>" "$RUN_DIR"

When Step 1 resolved a configured model or effort, add CROSS_MODEL_MODEL_OVERRIDE_TARGET="<target>" CROSS_MODEL_MODEL_OVERRIDE="<model>" and/or CROSS_MODEL_EFFORT_OVERRIDE="<effort>" to the env prefix after CROSS_MODEL_FIXED_ROUTE; omit them when unset.

The nested windows are one budget with one knob, CROSS_MODEL_HARD_SECS. The runner derives its supervisor hard window from that ambient knob automatically (max(1230, knob + 30)). Clear CE_PEER_HARD_SECS on the start prefix (CE_PEER_HARD_SECS=) so a stale ambient value from an earlier session or harness export cannot undercut that derivation. An explicit numeric CE_PEER_HARD_SECS still wins when a skill deliberately sets one (ce-work / elevation), which this path must not do. Print the orchestrator deadline as knob + 10 in the same shell as start (as above) and use that printed peer-deadline-secs=<n> below (all legs share the one value; re-use the first leg's number rather than re-deriving per leg); never hardcode it, because a literal survives a knob change and then reaps a healthy peer.

**Do not forward CROSS_MODEL_HARD_SECS to the worker.** The runner already passes the ambient environment through, so a knob the user actually set reaches the worker on its own. Re-exporting the orchestrator's resolved value would turn a fallback into an explicit override and strip the worker of its own default.

Omit --result-path; done means only that the worker exited. The fixed target determines the expected <reviewer-name>-<target>.json filename.

  • <host-serving-family> is codex, claude, grok, composer, gemini, or unknown; <host-harness> is codex, claude, grok, cursor, opencode, antigravity, omp, or unknown.
  • <target> is exactly one of codex, claude, grok, cursor, composer, opencode, or antigravity; <fixed-route> is its already-sanctioned concrete route token from the Step 1 table (codex, claude, grok-cli, grok-cursor, cursor, composer, opencode, or antigravity).
  • <reviewer-name> = the activated lens (security-lens, adversarial, or product-lens). The script derives the persona-brief filename and (per provider) model from this allowlisted value — the brief path is never caller-controlled.
  • <document-path> = the document under review.
  • <document-type> = the Phase 1 classification (requirements / plan / unified-requirements / unified-plan).
  • <origin> = the same {origin_path} slot the in-process personas receive.
  • <run-dir> = the absolute $RUN_DIR resolved above. The script writes <reviewer-name>-<provider>.json there per resolved peer only after forcing reviewer to <reviewer-name>-<provider> and downgrading peer safe_auto → gated_auto.

Every runner call is bounded: no tool call ever spans a worker's runtime, on any host. Between dispatch waves, poll outstanding jobs (it returns early when the watched jobs settle):

SKILL_DIR="<absolute path of the directory containing the ce-doc-review SKILL.md you read>";
PY="$(for c in python3 python py; do command -v "$c" >/dev/null 2>&1 && "$c" -c '' >/dev/null 2>&1 && { echo "$c"; break; }; done)"; [ -n "$PY" ] || { echo "no working Python 3 interpreter on PATH" >&2; exit 1; };
"$PY" "$SKILL_DIR/scripts/peer-job-runner.py" wait --max-secs 30 --json <job-ids...>

Capture the epoch time right after the final start (date +%s). That timestamp is how you know when the deadline passes, since nothing else tracks wall clock across tool calls. Before synthesis or any return, bring every started job to a terminal outcome. While its result is still needed, loop bounded wait calls until the job is terminal **or the shared peer deadline (peer-deadline-secs) has elapsed since the final start**. Compare date +%s against that timestamp before each wait; do not begin a wait that would extend past the deadline. Reap unfinished jobs whose results are no longer needed or whose deadline is exhausted, then run one final bounded wait --max-secs 10 pass (reap is asynchronous; the terminal record lands a grace period after it returns). Collect and classify each started job under Step 5. The detached script still self-bounds (idle-timeout default 480s on every route; hard backstop CROSS_MODEL_HARD_SECS default 1200s) and exits cleanly; the runner's supervisor windows sit outside those caps as the backstop. The script needs no prompt or schema passed in — it reads the persona brief, findings-schema.json, and the document itself from disk.

Any started job whose terminal state is not done (failed / timeout / died-without-result) is named in the Coverage line with its lens and terminal state (e.g. "cross-model security-lens peer: timeout"). A job reaped at the deadline records timeout, with the reap noted in its reason. A preflight failure never yields a job id: a genuine condition-not-met skip is the never-started case, but a dispatch-infrastructure crash before any job starts is not a clean skip and triggers the hand-recovery rule in Step 5. A never-started pass does not get a started-job terminal-state line and does not fail the review. In non-interactive mode, the structured result records every owed lens that did not fold, whether its job started or not, in the form references/synthesis-and-presentation.md defines. A missing fold-in file is still "the pass didn't run for that lens," never a review failure, except when a dispatch-infrastructure crash voided the whole pass at once, which Step 5 handles as named whole-pass loss (the whole-doc broad read especially), not per-lens "not run."

The cross-model pass does not receive the accumulated decision primer that in-process personas get on round 2+; the peer prompt carries a round-1 framing regardless of round. This is deliberate (cross-model is most valuable on the first pass). Synthesis's own R29/R30 suppression catches re-raised or already-resolved findings, so a peer that re-raises a prior-round-rejected finding is dropped at synthesis, not shown.

Raw lines 91 to 167
Starts an agent subagent :93
Runs code scripts/peer-job-runner.py :93
Starts an agent dispatch :93
Runs code scripts/cross-model-doc-review.sh :135
168## Step 5 — Collect outcomes and clean up
170Every started job must be collected and classified before return. Fold usable findings into synthesis only when the review proceeds to synthesis; an incomplete review reports peer outcomes without applying findings. After collection and classification, delete the consumed job dirs under `<run-dir>/jobs` using the environment's preferred deletion command. If collection or cleanup cannot complete, preserve the remaining evidence and report the unresolved jobs and blocker; never claim they were cleaned up.
172- Read each fold-in artifact through the runner's verified read (resolve `$PY` in the same tool call — shells do not persist):
174 ```bash
175 SKILL_DIR="<absolute path of the directory containing the ce-doc-review SKILL.md you read>";
176 PY="$(for c in python3 python py; do command -v "$c" >/dev/null 2>&1 && "$c" -c '' >/dev/null 2>&1 && { echo "$c"; break; }; done)"; [ -n "$PY" ] || { echo "no working Python 3 interpreter on PATH" >&2; exit 1; };
177 "$PY" "$SKILL_DIR/scripts/peer-job-runner.py" result "<job-id>" --path <run-dir>/<reviewer-name>-<target>.json
178 ```
180 The read checks file ownership and is bounded. Exit 0 emits the artifact. Exit 2 means the job is still running, so the deadline loop above was left early; return to it rather than classifying. Exit 3 is the only outcome that means the peer produced nothing; it names that lens's job state, which selects the matching branch below. Any other exit means the runner could not complete the read: a trust failure on the artifact or on the job's own state, or a job id that did not resolve. None of those has a branch below: name the failure in Coverage as a degraded cross-model pass, and never fold it into the clean skip. If present, treat it as one reviewer return
181- **No file, clean skip** (script skipped before starting real work: host un-attestable, no different-provider route installed, CLI missing, unparseable output, or lens not activated) → the pass simply didn't run for that lens. Note "cross-model pass: not run" in Coverage on an interactive host in default mode, or "cross-model pass: disabled by checkout config" when Step 1's egress policy was the reason. In non-interactive mode, do not announce the skip; the structured result records it as `references/synthesis-and-presentation.md` defines. A lens that was not activated is not an eligible pass. Never fail the review. Ignore any `*.raw.json` leftovers; they are not fold-in artifacts.
182- **Dispatch-infrastructure failure vs. clean skip.** The clean skip above is a script that *chose* not to start real work. A dispatch-infrastructure crash is different: the runner or worker itself failed, through a non-zero exit before any job starts, a preflight/detach failure, or an unresolved `$SKILL_DIR`/script path. Because every leg shares one runner, route, and `$SKILL_DIR`, such a crash typically drops the **whole** cross-model pass at once, not one lens. Do not fold it into the clean skip on the first error. Re-run the **same resolved route** by hand, re-issuing the affected `start` calls with the target/model, the empty-workspace isolation, and the embedded-document read scope all held fixed. Do this while the review can still proceed to synthesis, each failure is a new and plausibly recoverable one, and the shared peer deadline holds. This is a same-route retry, distinct from the quota rule below, which requires a newly disclosed route. Stop and drop the cross-model pass once a failure repeats or the deadline is spent. Each trio lens is still covered by its in-process twin; what an infra crash silently voids is the **whole-doc broad read** (the sweep leg has no twin) plus cross-model corroboration. Name that loss in the Coverage line rather than letting it disappear as "not run." A hand recovery may not substitute a different target or provider, widen the read scope beyond the embedded document, or relax the read-only empty-scratch isolation.
183- **Transport unavailable before egress.** A worker line `transport unavailable (pre-egress, <scope>): <reason>` means the peer did not run and no document content reached the provider; report that lens as not run with the reason. Scope `shared` (Node, `npx`, or the npm fetch of acpx) fails every route the same way, so no other route can replace it. Scope `route` (that route's CLI is missing, an acpx config file replaces its launch command, or the adapter rejected the model, with the available models listed) affects only that route. A rejected model follows the refused-model item below; any other replacement follows Step 1's new resolution, sanction, and disclosure rule.
184- **Started but not `done`** (the job's final state is `failed` / `timeout` / `died-without-result`) → still non-blocking, but never silent: name the lens and terminal state in Coverage per Step 4's naming rule.
185- **Classify the skip reason before the job dirs are deleted.** When a peer produced no usable output or ended non-`done`, read its `out.log` before cleanup, including bounded lines prefixed `peer skip evidence:`. Name observed quota, authentication, or capability failure specifically. Attribute an account authentication failure only after provider-capable dispatch is positively established by the launch context or provider response; then report the observed failure and login or credential-refresh remediation. Without that proof, authentication-shaped peer text describes only the peer's execution context: a sandboxed host can produce the same signal as a genuine logout, so never report it as the user's account being logged out or prompt a login command. The cross-model pass is additive and the in-process reviewers still covered their lenses; obtaining it requires a context where the peer CLI can reach the network. The worker exclusively owns the one same-route retry under Step 1's exact-overload condition. Apart from the refused-model restart below, once a provider no-review outcome reaches the host, the host never restarts that peer. After the same quota or usage-limit evidence appears more than once in this session, do not retry that route automatically; never silently continue to another recipient.
186- **Refused model.** The requested model itself was refused: the adapter did not offer it, or the provider rejected it for this account (`peer skip evidence (reply):` carries a rejection the provider sent as reply text). Only the model failed; the route is still usable. If the worker ran its own default model because none was configured or named by the user, restart that lens once on the same route, with no new recipient. Give it the closest same-family model, picked from `peer skip evidence (advertised models):` when that line is present, and bind it as Step 1's same-family replacement paragraph describes. Each affected lens gets at most one such restart. Coverage says which model was rejected and that the user can set `cross_model_model` to one that works. A configured or user-named model is never swapped.
187- Empty `findings` → note "cross-model pass: no additional issues" in Coverage.
188- A finding that 3.3 merged with its in-process twin (`<reviewer-name>`) promotes by one anchor step only when the artifact records `independence_verified: true`. Cursor-default artifacts default false; an unattested host skips automatic dispatch. Whether the two describe one problem is 3.3's one-fix test, not a string match on section or title.

Step 5 — Collect outcomes and clean up

Every started job must be collected and classified before return. Fold usable findings into synthesis only when the review proceeds to synthesis; an incomplete review reports peer outcomes without applying findings. After collection and classification, delete the consumed job dirs under <run-dir>/jobs using the environment's preferred deletion command. If collection or cleanup cannot complete, preserve the remaining evidence and report the unresolved jobs and blocker; never claim they were cleaned up.

  • Read each fold-in artifact through the runner's verified read (resolve $PY in the same tool call — shells do not persist):

bash SKILL_DIR="<absolute path of the directory containing the ce-doc-review SKILL.md you read>"; PY="$(for c in python3 python py; do command -v "$c" >/dev/null 2>&1 && "$c" -c '' >/dev/null 2>&1 && { echo "$c"; break; }; done)"; [ -n "$PY" ] || { echo "no working Python 3 interpreter on PATH" >&2; exit 1; }; "$PY" "$SKILL_DIR/scripts/peer-job-runner.py" result "<job-id>" --path <run-dir>/<reviewer-name>-<target>.json

The read checks file ownership and is bounded. Exit 0 emits the artifact. Exit 2 means the job is still running, so the deadline loop above was left early; return to it rather than classifying. Exit 3 is the only outcome that means the peer produced nothing; it names that lens's job state, which selects the matching branch below. Any other exit means the runner could not complete the read: a trust failure on the artifact or on the job's own state, or a job id that did not resolve. None of those has a branch below: name the failure in Coverage as a degraded cross-model pass, and never fold it into the clean skip. If present, treat it as one reviewer return

  • No file, clean skip (script skipped before starting real work: host un-attestable, no different-provider route installed, CLI missing, unparseable output, or lens not activated) → the pass simply didn't run for that lens. Note "cross-model pass: not run" in Coverage on an interactive host in default mode, or "cross-model pass: disabled by checkout config" when Step 1's egress policy was the reason. In non-interactive mode, do not announce the skip; the structured result records it as references/synthesis-and-presentation.md defines. A lens that was not activated is not an eligible pass. Never fail the review. Ignore any *.raw.json leftovers; they are not fold-in artifacts.
  • Dispatch-infrastructure failure vs. clean skip. The clean skip above is a script that chose not to start real work. A dispatch-infrastructure crash is different: the runner or worker itself failed, through a non-zero exit before any job starts, a preflight/detach failure, or an unresolved $SKILL_DIR/script path. Because every leg shares one runner, route, and $SKILL_DIR, such a crash typically drops the whole cross-model pass at once, not one lens. Do not fold it into the clean skip on the first error. Re-run the same resolved route by hand, re-issuing the affected start calls with the target/model, the empty-workspace isolation, and the embedded-document read scope all held fixed. Do this while the review can still proceed to synthesis, each failure is a new and plausibly recoverable one, and the shared peer deadline holds. This is a same-route retry, distinct from the quota rule below, which requires a newly disclosed route. Stop and drop the cross-model pass once a failure repeats or the deadline is spent. Each trio lens is still covered by its in-process twin; what an infra crash silently voids is the whole-doc broad read (the sweep leg has no twin) plus cross-model corroboration. Name that loss in the Coverage line rather than letting it disappear as "not run." A hand recovery may not substitute a different target or provider, widen the read scope beyond the embedded document, or relax the read-only empty-scratch isolation.
  • Transport unavailable before egress. A worker line transport unavailable (pre-egress, <scope>): <reason> means the peer did not run and no document content reached the provider; report that lens as not run with the reason. Scope shared (Node, npx, or the npm fetch of acpx) fails every route the same way, so no other route can replace it. Scope route (that route's CLI is missing, an acpx config file replaces its launch command, or the adapter rejected the model, with the available models listed) affects only that route. A rejected model follows the refused-model item below; any other replacement follows Step 1's new resolution, sanction, and disclosure rule.
  • **Started but not done** (the job's final state is failed / timeout / died-without-result) → still non-blocking, but never silent: name the lens and terminal state in Coverage per Step 4's naming rule.
  • Classify the skip reason before the job dirs are deleted. When a peer produced no usable output or ended non-done, read its out.log before cleanup, including bounded lines prefixed peer skip evidence:. Name observed quota, authentication, or capability failure specifically. Attribute an account authentication failure only after provider-capable dispatch is positively established by the launch context or provider response; then report the observed failure and login or credential-refresh remediation. Without that proof, authentication-shaped peer text describes only the peer's execution context: a sandboxed host can produce the same signal as a genuine logout, so never report it as the user's account being logged out or prompt a login command. The cross-model pass is additive and the in-process reviewers still covered their lenses; obtaining it requires a context where the peer CLI can reach the network. The worker exclusively owns the one same-route retry under Step 1's exact-overload condition. Apart from the refused-model restart below, once a provider no-review outcome reaches the host, the host never restarts that peer. After the same quota or usage-limit evidence appears more than once in this session, do not retry that route automatically; never silently continue to another recipient.
  • Refused model. The requested model itself was refused: the adapter did not offer it, or the provider rejected it for this account (peer skip evidence (reply): carries a rejection the provider sent as reply text). Only the model failed; the route is still usable. If the worker ran its own default model because none was configured or named by the user, restart that lens once on the same route, with no new recipient. Give it the closest same-family model, picked from peer skip evidence (advertised models): when that line is present, and bind it as Step 1's same-family replacement paragraph describes. Each affected lens gets at most one such restart. Coverage says which model was rejected and that the user can set cross_model_model to one that works. A configured or user-named model is never swapped.
  • Empty findings → note "cross-model pass: no additional issues" in Coverage.
  • A finding that 3.3 merged with its in-process twin (<reviewer-name>) promotes by one anchor step only when the artifact records independence_verified: true. Cursor-default artifacts default false; an unattested host skips automatic dispatch. Whether the two describe one problem is 3.3's one-fix test, not a string match on section or title.
Raw lines 168 to 189
Runs code scripts/peer-job-runner.py :177
Starts an agent Dispatch :182
Starts an agent dispatch :182
190## Trust boundary (maintainers)
192The script embeds the **full document content** into the peer prompt and sends it to an external model provider (OpenAI, Anthropic, xAI, Google, or Cursor, depending on the resolved peer). This is a wider egress than a diff-only review. `CROSS_MODEL_PEERS` restricts which providers may receive content.
194Every route runs through acpx (an Agent Client Protocol client), which needs Node 22.13 or newer with `npx`, plus the route's own agent CLI. On the first run, npm fetches an eligible acpx version within the supported range; later runs reuse the cache. The peer runs from an empty per-peer workspace with no project context and no MCP servers, and Claude starts in safe mode so project settings and hooks do not apply. acpx denies every permission request the peer makes, and each adapter runs in its read-only mode where it has one. That removes a tool only where the agent asks permission before using it, so the routes differ in what the peer can still do.
196Asked to read a file outside its workspace and to write one inside it, the routes split into two tiers. The Antigravity read has not been tested yet:
198| Route | Reads outside the empty workspace | Tools still usable without permission |
199|---|---|---|
200| `claude` | Denied | Reads inside the empty workspace |
201| `grok-cli` | Refused | Reads inside the empty workspace; web fetch and web search, which its ACP server cannot disable |
202| `opencode` | Denied | Reads inside the empty workspace (web, edits, and subagents are denied in its config) |
203| `codex` | **Allowed** | Reads anywhere and shell commands, including writes: its adapter does not enforce read-only mode |
204| `grok-cursor`, `cursor`, `composer` | **Allowed** | Reads and searches anywhere |
205| `antigravity` | Not yet tested | Write, edit, and shell requests are denied. It loads skills and settings only from its private per-run home and the empty workspace, never from the user's own Antigravity or Gemini setup |
207**Accepted read residual (codex + cursor-agent routes):** neither adapter can be made tool-less over ACP, so their isolation is weaker than the claude, grok-cli, and opencode routes. This is an **accepted** risk for ce-doc-review's own-document threat model. The reviewed documents are the maintainer's own planning docs (low injection surface), and the host agent already runs in-repo with strictly more privilege than any peer, so a peer that can read a file the host could already read (and send it to a provider the document already goes to) adds no materially new exposure. The routes are kept rather than refused; the script's stderr audit log records each send so the egress is auditable even in non-interactive mode.

Trust boundary (maintainers)

The script embeds the full document content into the peer prompt and sends it to an external model provider (OpenAI, Anthropic, xAI, Google, or Cursor, depending on the resolved peer). This is a wider egress than a diff-only review. CROSS_MODEL_PEERS restricts which providers may receive content.

Every route runs through acpx (an Agent Client Protocol client), which needs Node 22.13 or newer with npx, plus the route's own agent CLI. On the first run, npm fetches an eligible acpx version within the supported range; later runs reuse the cache. The peer runs from an empty per-peer workspace with no project context and no MCP servers, and Claude starts in safe mode so project settings and hooks do not apply. acpx denies every permission request the peer makes, and each adapter runs in its read-only mode where it has one. That removes a tool only where the agent asks permission before using it, so the routes differ in what the peer can still do.

Asked to read a file outside its workspace and to write one inside it, the routes split into two tiers. The Antigravity read has not been tested yet:

RouteReads outside the empty workspaceTools still usable without permission
claudeDeniedReads inside the empty workspace
grok-cliRefusedReads inside the empty workspace; web fetch and web search, which its ACP server cannot disable
opencodeDeniedReads inside the empty workspace (web, edits, and subagents are denied in its config)
codexAllowedReads anywhere and shell commands, including writes: its adapter does not enforce read-only mode
grok-cursor, cursor, composerAllowedReads and searches anywhere
antigravityNot yet testedWrite, edit, and shell requests are denied. It loads skills and settings only from its private per-run home and the empty workspace, never from the user's own Antigravity or Gemini setup

Accepted read residual (codex + cursor-agent routes): neither adapter can be made tool-less over ACP, so their isolation is weaker than the claude, grok-cli, and opencode routes. This is an accepted risk for ce-doc-review's own-document threat model. The reviewed documents are the maintainer's own planning docs (low injection surface), and the host agent already runs in-repo with strictly more privilege than any peer, so a peer that can read a file the host could already read (and send it to a provider the document already goes to) adds no materially new exposure. The routes are kept rather than refused; the script's stderr audit log records each send so the egress is auditable even in non-interactive mode.

Raw lines 190 to 207
Uses an outside tool MCP :194
Starts an agent subagents :202