Cross-review preset
A second model catches what the first one missed. The cross-review preset runs your implementer on one backend and has every successful run reviewed by two read-only reviewers, one on each backend:
itervox init --runner claude --preset cross-review: Claude writes; Codex and Claude review.itervox init --runner codex --preset cross-review: Codex writes; Claude and Codex review.
Without --preset, itervox init offers it ([y/N]) when run in a terminal
with both the claude and codex CLIs installed. Both CLIs must be
installed and signed in wherever the reviewers run.
What the preset writes
Section titled “What the preset writes”agent: command: claude profiles: implementer: command: claude soul_file: .itervox/agents/implementer/SOUL.md instructions_file: .itervox/agents/implementer/INSTRUCTIONS.md reviewer: command: claude soul_file: .itervox/agents/reviewer/SOUL.md instructions_file: .itervox/agents/reviewer/INSTRUCTIONS.md allowed_actions: [comment, comment_pr] reviewer-codex: command: codex backend: codex soul_file: .itervox/agents/reviewer-codex/SOUL.md instructions_file: .itervox/agents/reviewer-codex/INSTRUCTIONS.md allowed_actions: [comment, comment_pr] reviewer_profile: reviewer-codex # the dashboard's AI Review button reviewer_profiles: [reviewer-codex, reviewer] review_quorum: any_block # changes are requested if either reviewer blocks auto_review: trueBoth reviewer profiles get the read-only reviewer SOUL.md and
INSTRUCTIONS.md. To add the preset to an existing workflow, copy these keys
and the two reviewer profile directories.
How a review runs
Section titled “How a review runs”-
The implementer finishes successfully.
-
With
auto_review, the reviewers run one after another on the same workspace, the other-backend reviewer first. Each judges the change on its own. -
Each reviewer gets a small, purpose-built context instead of the whole history:
## Changes to Review: the diff of the branch against its base (workspace.base_branch, or the blocker’s branch for a stacked issue), with a stat, cut at 40 KB.## Latest Handoff: only the implementer’s most recent handoff.
-
Each reviewer writes a verdict to
run.review_verdict_path:{"verdict": "block","reasons": ["missing test for the empty config"],"comments": [{"path": "internal/foo.go", "line": 7, "body": "nil map write when cfg is empty"}]}verdictisapproveorblock; anything else, or no file at all, counts asblock. -
Itervox posts each verdict on the issue, then the combined result:
Review by
reviewer-codex(codex): ❌ changes requested- missing test for the empty config
Line comments
internal/foo.go:7nil map write when cfg is empty
Review result: ❌ changes requested (1 approve / 1 block, quorum
any_block)
While a reviewer runs, the issue may sit in completion_state (for example
in-review); the review is not stopped there. Moving the issue anywhere else
(backlog, say) stops it like any other run.
When changes are requested, the issue stays in completion_state with the
reasons on it. Move it back to an active state to have the implementer address
them: the default prompt includes the issue’s comments, and the latest handoff
carries the context.
Reviewers are read-only
Section titled “Reviewers are read-only”A reviewer never edits files, commits, pushes or moves the issue; its output is the verdict. Itervox enforces what it can:
- No push or commit on its behalf. For a reviewer run, Itervox does not push the branch or commit the reviewer’s handoff (it stays in the working tree for the next implementer run).
- Changes are flagged. Itervox records the branch when a review starts and
compares it when the review ends:
HEAD(a commit, pull, reset or checkout), every changed file outside Itervox’s own.itervox/handoff/,.itervox/review/and.itervox/evidence/(compared by content), and the refs on each of the workspace’s git remotes as the remote reports them (git ls-remote). A remote ref that moved to a commit this worktree’sHEADvisited during the review counts as a push from the reviewer, whether it used the remote’s name or its URL, and even if it reset afterwards; other workers’ pushes and fetches do not. A flagged reviewer gets a ⚠️ note on the issue naming what it changed, and its verdict is recorded as a block, whatever it said. A retry of the same review keeps the original starting point, so a change made before a failed turn is still caught. Inspect flagged changes before merging. - Fresh verdicts only. A verdict file left by an earlier review round is removed before the reviewer runs, so a reviewer that records nothing counts as a block rather than repeating an old verdict.
- Not covered: deleting a remote branch (
git push origin --delete), which cannot be told apart from another clone deleting it; pushes to a repository that is not one of the workspace’s remotes (or a remote that cannot be reached when the review starts or ends), a workspace that is not a git work tree, reviewers on SSH worker hosts whose workspace is not on the daemon’s machine, and local edits undone before the review ends.
The agent CLIs themselves are not sandboxed from git push; the flag is what
makes a push visible and stops it from approving its own change. For a hard
block on Claude, register a PreToolUse hook that denies git push
(a deny rule in settings.json is bypassed in Itervox’s default
permission mode; a hook is not). See Agent permissions.
Expected cost
Section titled “Expected cost”Each reviewer is a separate agent run. With the preset, every successful implementer run is followed by two more runs: a typical issue costs about one implementer run plus two reviewer runs. Reviewer runs are usually shorter, since they read a diff rather than build the change, but each is a full session on its backend’s plan or API account, Codex included.
To spend less:
- Drop to one reviewer:
reviewer_profiles: [reviewer-codex](or remove the key and keepreviewer_profile). - Turn off
auto_reviewand use the dashboard’s AI Review button only on the issues that need it. - Point a reviewer at a cheaper model in its
command, for exampleclaude --model <a smaller model>.