Review and gates
After the build, Guild Stack reviews the work and writes review.md. Review is a
role, not a favor: every run resolves who drafts, who advises, and who
critiques — and a strong critique must come from a different host family than
the author. The Power layer covers the roles and every review control.
The Architect layer covers the release-path gates.
Try it. Ask for a cross-host review on one task. A different host family then critiques the work before the gate passes. If only one host is set up, Guild Stack warns you and a fresh same-host reviewer does it instead, marked weak:
/guild:guild add a --version flag to src/index.js --review=cross
Operating model and review roles
Every run resolves three roles. Each role names a host that does one job.
| Role | Job |
|---|---|
host | Runs the work: drafts and dispatches. |
advisory | Answers an advisor consult when a lane escalates a sub-question. |
adversarial | Critiques an artifact in cross-host review. |
Default behavior
The roles are resolved once, at run-start preflight, from the capability matrix of the hosts detected on the machine. The resolver reads capability columns, not host names. The result is recorded in the run snapshot as guild.role_resolution.v1.
On a box with Claude and an authenticated Codex, the default is:
host=claudeadvisory=claude(the local advisor)adversarial=codex, strengthstrong
Each resolved role carries a strength of strong or weak, and a reason. An adversarial role is strong only when it is a different host family from the host. If the author host identity is not verified, a strong adversarial role is downgraded to weak.
Role pins
You cannot pin a role to a host in a durable file in v3.0.0. The settings schema
still has roles.host, roles.advisory and roles.adversarial (default null),
but /guild:config role refuses to write and config set refuses roles.* host
values. A host name in a durable file would tie an initiative to whichever
provider was running. The host for a run is detected at run start and recorded as
guild.session_binding.v1. /guild:config models inspect shows that binding
read-only.
Host ids in that binding and in the registry are the 16 HOST_IDS: claude-code-cli, codex-cli, pi-cli, antigravity-cli, agents-file, claude-code-app, claude-code-web, codex-app, claude-ai-connector, cursor, github-copilot, opencode, rovo-dev, kiro, qoder and trae. See Host matrix.
To influence review without naming a host, use the policy keys review.critic
and review.independence (see Config reference),
the --review flag below, and adversarial_review_provider.
--review
--review=local|cross|off is accepted on /guild:guild. The same key lives in settings as review. The default is local.
local(default) andoff: you did not ask for cross-host review.cross: the Claude and Codex adversarial review broker engages, and a different host family critiques the artifact.
Cross-host review is policy-gated. The broker fires when risk is high or above, when review: cross is set, or when project config requires it. Otherwise it resolves skipped and the gate passes with no reviewer. Self-build runs treat cross-host review as always on.
Gates
The broker has seven gates. Each fires inside the skill that produces the artifact.
| Gate | Artifact reviewed |
|---|---|
G-init | Init artifact or wiki diff |
G-spec | The spec, before team composition |
G-plan | The plan, before the approval gate |
G-lane | One lane's handoff receipt, before the next lane dispatches |
G-quality | The quality report |
G-operations | The ops record or runbook |
G-diagnose | The diagnosis or fix plan |
Only G-lane is command-visible, because it fires per lane during build. The other six are skill-internal.
G-lane
After each lane's receipt is confirmed, the broker is called with gate G-lane:<task-id>. Lanes run in series. The trail for the lane is written to .guild/runs/<run-id>/review/G-lane:<task-id>/ as packet, result and trail.
On rework, the lane re-executes with the findings as added context. The re-run counts against the restart:<lane> counter. On satisfied, skipped or force_passed, the next lane proceeds.
Independence rule and degradation
The reviewer must be a different host family from the author. A same-family reviewer never counts as a cross-host sign-off.
When review is required but no different-family reviewer is available, the broker does not skip. It prints a warning, runs a fresh-context same-host review, and stamps it independence: weak. The weak review is still gated by the same 5-condition rule. Skipping is legal only when review was not required.
An adapter round that returns no verdict (refusal, dispatch error, empty response) never clears the gate and is not a skip. It offers the same three options as the round cap.
Provider pin: adversarial_review_provider
adversarial_review_provider defaults to auto. With auto, provider detection picks the best available different-family provider on every run and never persists the choice. You can pin codex-plugin or codex-cli. The pin is honored only when review is cross.
- A native plugin adapter ranks above an authenticated CLI:
codex-pluginbeforecodex-cli. piandantigravityare detect-only. They are not selectable as reviewers.- Pinning a same-family provider, or a provider with no adapter, is refused with a reason. Guild Stack does not silently substitute.
- Do not set the provider to a host id such as
codex. The role names a host family. The provider is the concrete adapter.
Round cap: codex_cap and --codex-cap
Each gate loops until the reviewer reports satisfaction or the cap is hit. The cap resolves in this order: --codex-cap=N, then codex_cap in settings, then the default of 5. The maximum is 10. Values above 10 are clamped with a warning.
At round cap + 1 the broker stops and asks you to choose:
force-pass: proceed without cross-family sign-off. The trail stays for audit.extend-cap N: continue for N more rounds, N from 1 to 5.rework: return to the prior step and revise the artifact.
It waits for an explicit choice.
Skip enforcement: codex_skip_enforcement
A Stop hook (hooks/maybe-reflect.ts) tracks consecutive self-build reflections where cross review was skipped. It writes .guild/codex-skip-streak.json (guild.codex_skip_streak.v1). At the start of every gate the broker reads it. Only blocked: true matters. A missing or unreadable file means no block.
codex_skip_enforcement | When blocked: true |
|---|---|
warn (default) | Print the warning and continue the gate. |
block | Refuse the gate until the sentinel clears or you override. Classified as a security-sensitive key. |
A reflection recording codex_review: RAN clears the sentinel.
Adversarial review and release gates
A change reaches stable only through gates. This section lists the gates verified for v3.0.0.
The gates
- Push. The
.githooks/pre-pushhook refuses direct pushes tomainandnext. Bypass:GUILD_ALLOW_PUSH_MAIN=1, for emergencies only. - Channel integrity. Between a release and its dev bump, channel-integrity accepts a shared bare version only while
mainis tagged and thenexttree equals it. Code PRs intonextare blocked in that window. - Branch policy.
branch-policy.ymlrejects any PR intomainwhose head is not the same-repository, exactnextbranch. All forks are rejected. - Promotion. The gate refuses a beta manifest (
manifest_version_not_release) and evidence not built at the exact bare version (source_version_not_release). - Merge. The release PR must be a merge commit. CI requires the merged tree to equal the reviewed
nexttree and re-runs the promotion evidence. - Conformance. The decision admits the full fixed set of 31 conformance scenarios, re-judged suite-wide. An extension outcome conforms only if it passed or was explicitly refused.
Refusal is tested, not assumed
The v3.0.0 evidence includes 18/18 planted refusal controls refusing.
Adversarial review
After each lane receipt, the review broker decides whether a G-lane review is required. If it is, the lane output and the reviewer verdict pass through the gate below. The gate passes only when every condition holds.