Multi-agent lane contract¶
How Claude Code (cc), Codex (cx), and Antigravity work as one team on the
same repo. This is the shared playbook — all three load it through the AgentPack
(AGENTPACK.yaml, generated from skill/agent frontmatter by
scripts/gen-agentpack.sh — never edited by hand), and the operative rules are
compiled into CLAUDE.md, codex/AGENTS.md, and antigravity/GEMINI.md from
the canonical sources in agents/canon/ (ADR-0007) so each tool follows them
at session start; check-agent-parity.sh asserts both the concepts and the
byte-currency in CI.
The team coordinates through artifacts in the repo, not a shared chat: the
instruction layer + skills (loaded identically via the pack), GitHub issues (the
only open-work tracker), handoff notes + CHANGELOG.md and unassembled
changelog.d/ fragments, and git itself. Keep those honest and the team works
even though the agents never talk to each other.
Roles¶
The active session is the conductor: it owns the outcome, dependency order, integration, verification, authorized delivery, and handoff. Assign other roles explicitly for the task. Any runtime can conduct or implement; personal model and operator defaults belong in private preferences.
| Role | Owns |
|---|---|
| Conductor | Planning, workstream boundaries, integration, final verification, delivery, and durable records |
| Implementer | A bounded change in an owned worktree, with named acceptance criteria and verification |
| Independent reviewer | Refutation of the final artifact from a fresh context, with a claim to disprove and exact repro |
| Runtime/browser verifier | Exercising the actual flow and reporting observable behavior with runtime evidence |
A fresh context reduces inherited assumptions. It does not establish a different model lineage. High-risk changes involving authentication, authorization, secrets, payments, destructive operations, schemas, or public trust boundaries require a reviewer from a different model family than the implementer. Record actual reviewer identity evidence before claiming that requirement is satisfied.
An Antigravity model label and its propagation log establish what was dispatched; they do not prove which model served a particular run. The gate's best-effort conversation-record spot-check is corroboration, not per-run attestation. If actual identity cannot be established, report it as unverified and obtain the required separate-family review elsewhere. A text-diff review is not browser or runtime evidence, regardless of the tool or model that produced it.
The two hard rules¶
-
One owner of the working tree at a time. Multiple agents editing the same files make conflicting assumptions about names, signatures, and imports. Give each agent its own git worktree, or strictly sequence shared-file edits with a lint/test/build between rounds. Parallelize freely only on read-only work (review, research) and non-overlapping new files.
-
Verification is adversarial, never an echo chamber. Ask a fresh-context reviewer to refute the final artifact; use a different model family when required above. Assign actual runtime/browser verification when the changed behavior needs it. Disagreement is a reason to reproduce and investigate, not a vote to break. Re-run any agent claim that contradicts directly observable evidence.
Complete simplification, documentation, changelog, and generated-file updates before affected verification and final review. For ordinary shipping work, the required committed-artifact gate serves as the final fresh-context review; another identical review is unnecessary. Any later artifact edit invalidates approval. Repeat affected checks and review after fixes, then validate the private review receipt immediately before shipping. Exit 0 alone is not proof of completed review; report tier/no-diff exemptions separately.
Proportionality: gate tiers (#212) and review lanes (ADR-0008)¶
Not every diff earns the full adversarial tax. Both review gates
(codex-review-gate.sh, antigravity-review-gate.sh) run a cheap classifier
(gate_classify_tier in claude/scripts/gate-lib.sh) — diff size plus
changed-path match against risk surfaces — before dispatching any reviewer:
- Tier 1 (reduced): docs-only diffs at or under BOTH captured ceilings — 200
lines (
GATE_TIER1_MAX_LINES) and the byte ceilingTIER1_MAX_BYTESinclaude/scripts/review-receipt.py, because one 200,000-byte line is a 1-line diff. The byte ceiling has no environment knob on purpose: every caller inheritsreview-receipt.py's default, so the gates and the shipping wrapper cannot disagree about it. The gate may skip, logging atier-1 skipline. Force the full pass anyway withGATE_FORCE_FULL=1. - Tier 2 (full): anything touching a risk surface — auth/token/secret/
credential names, path/host handling, schemas, hash chains, and gate/hook/
CI/instruction files (AGENTS*.md, CLAUDE.md, GEMINI.md, SKILL.md,
codex/,antigravity/,.github/,scripts/, hooks) — or above the size cap, or not positively classified. Never downgradable: no knob skips a tier-2 review, and an adversarial--claim/--reprodispatch always runs full.
Separately from the tiers, the Antigravity lane refuses diffs it could only
review in part: agy print mode delivers about 185 KB of a single user message
to the model and silently drops the rest (#409), so above
ANTIGRAVITY_GATE_MAX_BYTES (default 185000) the gate degrades instead of
dispatching. A large change gets no Gemini-lineage verdict until it is split.
Both gates check their size caps and their reviewer's availability only AFTER
the tier valve (#494): those are facts about a dispatch, and a tier-1 diff has
none. The tier-1 size ceiling is captured policy in review-receipt.py
(tier1_max_lines, tier1_max_bytes), so both lanes and check give the same
answer, and a byte-huge docs diff is escalated to a real review rather than
exempted in one lane and refused in the other.
Named failure mode: the valve fails toward the full pass. A classification
error, an unmeasurable diff, or an unknown file class escalates to tier 2 —
nothing ever falls back to the skip. Renames can't launder either: diffs and
changed-path lists are computed with --no-renames, so git mv guard.sh
notes.md is classified under both paths and reviewed as a full delete+add.
Which lane reviews it (ADR-0008)¶
The same classifier also names the required lane, and the receipt carries it:
- Tier 1 requires lane
any— either gate's exemption receipt ships it. - Tier 2 with no risk path requires
antigravity. This is the default lane for ordinary work; the Codex GitHub bot supplies the cross-family second opinion after the push. - Risk paths, an empty changed-path list, or an unreadable classification
require
codex. Size alone never escalates the lane: a large ordinary diff is still ordinary.
Lanes rank any < antigravity < codex, and a receipt ships a diff only when its
lane ranks at or above the requirement — enforced by review-receipt.py check,
so githooks/pre-push needs no lane logic of its own. Escalation is always
allowed (REVIEW_LANE=codex); downgrade never is — REVIEW_LANE=antigravity
on a codex-required diff is refused rather than honoured. On such a diff the
Antigravity gate still runs and still mints its receipt, announcing itself as a
supplementary lane: an independent-lineage second opinion, not the shipping
gate. Run that second opinion before the shipping review: a review that
reaches a verdict in either lane retires the other lane's receipt for the same
artifact, so that a blocking verdict cannot be bypassed by an older approval
(#480) — which also means a supplementary run afterwards retires the receipt you
were going to push on. A blocking verdict also records a durable per-artifact
marker, and check refuses every receipt captured before it, whichever lane
recorded it; a review captured after it ships as usual (#573).
A degraded lane is not a verdict. Antigravity exit 3 (agy missing, unverifiable
model pin, a diff above the byte cap) means the lane could not run, so
review-and-push.sh falls back to Codex and records the degradation in the lane
ledger; REVIEW_LANE_FALLBACK=block refuses the push instead. Exit 2 — blocking
findings, or a verifiably wrong model — never falls back. A degraded run costs
nothing else: each gate captures the artifact touching only its own lane and
claims it — retiring the other lane's receipt — only once it can reach a verdict,
so an exit 3 leaves the other lane's approval valid (#499).
review-and-push.sh checks the receipt naming the lane it dispatched, which also
requires the review that run performed to still be approved. Checking by hand,
use the generic no---reviewer form above: it enforces the same lane requirement
without needing to know which lane ran. Read the ledger with
review-receipt.py stats --since-days 7 before drawing conclusions about lane
cost; the dotfiles risk list is deliberately unnarrowed, so most diffs in this
repository stay on Codex.
A lane whose runtime is not a selected service is unavailable, not skipped: a
diff that requires it blocks with a message naming the unselected service and
the opt-in command (./setup.sh --select-services). REVIEW_LANE_FALLBACK=codex
does not fall back to Codex when Codex is unselected; it behaves as block.
The instruction-surface lane (#557)¶
Some changes are agent-proof three independent ways, by design: the root
AGENTS.md out-of-bounds rule, the gates' self-review guard (the path regex in
codex-review-gate.sh; its override flag is denied to agents by the permission
classifier), and the classifier's own refusal of the edit as self-modification.
That covers the instruction surfaces (agents/canon/, claude/skills/,
agents/skills/, antigravity/skills/, AGENTS*.md, CLAUDE.md, GEMINI.md,
.codex-review-ignore) and the gate machinery (gate-lib.sh,
review-receipt.py, review-multipart.py, the review schema, both
*-review-gate.sh). The same boundary denies agents a few adjacent shapes on
first sight: a gate override flag, a systemd-run sandbox probe, and a batched
or read-then-write gh call. None of these is a retry-until-it-passes
situation — the denial is the answer, and the work routes to the operator.
An agent that finds such a change necessary does not prepare a branch it cannot
push. It files (or updates) an issue labelled instruction-surface carrying the
exact wording or a patch beside the handoff note that passes git apply --check
against main, plus the verification commands, and moves on. The harvester
applies the label itself when a bot finding's path matches the guard regex.
The operator drains that label in one pass — weekly, or when reading the next
handoff: apply the queued patches on one branch, run the required gate once with
the override flag (independent review already recorded on each issue), open one
PR, and let its Closes lines retire the issues. One gated commit for the whole
inbox, instead of one human command per item.
Handoff payload¶
When the conductor hands verification to another agent, the handoff (a handoff
note or an issue) carries the claim to disprove and the exact command to
reproduce — not just "please review." A verifier with a falsifiable target and
a repro is worth three that were asked to nod.
Mechanically:
- Gate-mediated refutation:
codex-review-gate.sh --claim "<claim>" --repro "<cmd>"injects the falsifiable payload into the structured Codex review. Assign browser/runtime claims to a working tool that can exercise the actual flow and retain inspectable evidence (target, flow, expected observable, claim to disprove). Antigravity'sbrowser-verifyskill is one available route; choose by capability rather than runtime name. - Verdicts are artifacts: the verifier persists its verdict (handoff note
or issue comment; browser evidence under
~/.claude/handoffs/evidence/) before the team acts on it. Output that only reached one terminal is lost. - Resume, don't cold-start: handoff notes carry a "Session continuity"
section (codex session id, agy conversation id); the receiving agent resumes
that session when one is listed (
codex resume <id>,agy --conversation <id>).
Dispatch mechanics¶
Use the active runtime's native agent controls and obey its actual delegation
authorization rules. When applicable user or instruction requirements authorize
agents, assign useful bounded tasks; keep one editing owner per worktree and
sequence overlapping changes. The shared orchestrate runtime contract documents
the supported workflow in agents/skills/orchestrate/references/runtime-contracts.md.
When calling a Codex companion from another runtime, use a result-returning interface and inspect the completed artifact. Resolve installed executable or plugin paths instead of embedding a cache version. The local Codex review gate provides the shipping review interface; a detached forwarder without a result channel is not evidence that review completed.
For Antigravity, use the gate's configured model label from the current
ANTIGRAVITY_GATE_MODEL setting and verify dispatch against its log. Keep the
review prompt on stdin, bound execution time, and preserve the gate's permission
and sandbox settings. Consult claude/scripts/antigravity-review-gate.sh and
claude/scripts/gate-lib.sh for the executable invocation and validation rules.
A matching dispatch label does not establish actual per-run model identity.
Shipping uses the applicable commit-push-pr skill if available; otherwise
the steps below. Ask which lane the diff
requires, then run that gate with --require after the last commit;
degraded or failed execution supplies no approval:
python3 ~/.claude/scripts/review-receipt.py lane --repo . --scope committed
Immediately before push, check the receipt against the outgoing HEAD — with no
--reviewer, so the receipt's own recorded classification decides which lanes
may ship it:
python3 ~/.claude/scripts/review-receipt.py check --repo . \
--head "$(git rev-parse HEAD)"
Pass the same --base <ref> if one was selected. Naming a lane with
--reviewer narrows the check to that lane; it can never satisfy a stronger
requirement, so use it for diagnosis rather than for shipping. Successful review
receipts and explicit current tier/no-diff exemptions are distinct evidence.
Missing, stale, or below-requirement evidence blocks shipping. A receipt records
artifact review; it does not itself prove different model lineage or real
runtime/browser verification. Never bypass hooks to evade a missing review or
receipt.