Skip to content

Review Loop

The review loop is a structured code review workflow built on Inbox / Outbox Messaging. It uses four message types to coordinate between an author agent and a reviewer agent, supporting multiple rounds of feedback until the change meets quality standards.

Type Direction Purpose
review_request Author -> Reviewer Request code review of a PR
review_feedback Reviewer -> Author Return review findings
review_addressed Author -> Reviewer Report that feedback was addressed
review_lgtm Reviewer -> Author Approve — quality gate passed
Author Reviewer (invocation A)
| |
|--- review_request --------------------------->| (PR#, branch, summary, budgets)
| |
|<-- review_feedback OR review_lgtm -----------| (one terminal response)
| |
| reviewer invocation A exits |
|
|--- review_addressed ------------------------->| (commit SHA, addressed summary)
|
|--- review_request (round N+1) -------------->| (explicit re-invocation)
|
|<-- review_feedback OR review_lgtm -----------| (invocation B terminal response)

The reviewer is stateless — each invocation handles exactly one round, produces one terminal response (review_feedback or review_lgtm), and exits. The author coordinates multi-round progression by re-invoking the reviewer with a new review_request for round N+1.

id: "msg-20260213T1000Z-claude-001"
from: claude
to: codex
type: review_request
priority: P1
created_at_utc: "2026-02-13T10:00:00Z"
related_pr: "86"
subject: "Review: review loop protocol (#86)"
body: |
pr: 86
branch: claude/review-loop-protocol
diff_summary: |
Adds review loop protocol spec, reviewer workflow,
reviewer runbook, 4 new message types in validate_message.py,
tests, and CHANGELOG/inbox_outbox.md updates.
max_turns_reviewer: 8
max_runtime_s_reviewer: 600

Body fields:

Field Required Description
pr Yes Pull request number
branch Yes Branch name under review
diff_summary Yes Brief summary of the changes
handoff_ref No Reference to a handoff packet if this review follows a handoff
max_turns_reviewer No Hard turn budget for reviewer invocation (default 8)
max_runtime_s_reviewer No Hard runtime budget in seconds (default 600)
id: "msg-20260213T1030Z-codex-001"
from: codex
to: claude
type: review_feedback
priority: P1
created_at_utc: "2026-02-13T10:30:00Z"
related_pr: "86"
subject: "Review feedback: round 1 (#86)"
body: |
findings_packet: packets/findings/20260213_review_loop_codex_r1.yaml
round: 1
blocking_count: 2

Body fields:

Field Required Description
findings_packet Yes Path to the findings packet (relative to project workspace)
round Yes Current review round number (1-based)
blocking_count Yes Number of blocking findings in this round
escalation No Escalation marker (e.g., max_rounds_exceeded, reviewer_budget_exceeded)
id: "msg-20260213T1100Z-claude-002"
from: claude
to: codex
type: review_addressed
priority: P1
created_at_utc: "2026-02-13T11:00:00Z"
related_pr: "86"
subject: "Feedback addressed: round 1 (#86)"
body: |
commit_sha: abc1234
changes_summary: |
Fixed both blocking issues:
- Added missing error handling for empty diff
- Corrected max_rounds default from 5 to 2
round: 1
touched_files:
- docs/protocol/review_loop.md
- docs/protocol/inbox_outbox.md
addressed_finding_ids:
- F-001
- F-002

Body fields:

Field Required Description
commit_sha Yes Commit SHA containing the fixes
changes_summary Yes Summary of what was changed to address the feedback
round Yes The round number whose feedback is being addressed
touched_files No List of files edited to address findings
addressed_finding_ids No List of finding IDs the author considers addressed
id: "msg-20260213T1130Z-codex-002"
from: codex
to: claude
type: review_lgtm
priority: P1
created_at_utc: "2026-02-13T11:30:00Z"
related_pr: "86"
subject: "LGTM: review loop protocol (#86)"
body: |
quality_gate_result: pass
merge_ready: true
nits:
- nit_id: NIT-001
tier: P3
summary: "Clarify timeout fallback wording in docs/protocol/review_loop.md"
owner: claude
next_action: "Open doc cleanup PR after merge"

Body fields:

Field Required Description
quality_gate_result Yes pass or fail
merge_ready Yes Whether the PR is ready to merge (true or false)
nits No Structured list of deferred non-blocking items

The reviewer sends review_lgtm when the quality gate passes. The gate passes when all of the following are true:

  • No unresolved P0 findings (always blocking).
  • No unresolved blocking findings (P1 and blocking P2).
  • Deferred non-blocking findings (P2/P3) are captured in review_lgtm.nits with owner and tracking.
  • All validation commands recorded with passing outcomes.

If any blocking item remains, the reviewer sends review_feedback instead.

Every finding in review_feedback is tagged with a severity level:

Severity Merge impact Blocking? Examples
P0 Always blocking Yes Security vulnerability, data loss, crash in production
P1 Blocking Yes Correctness bug, missing error handling, broken API contract
P2 Reviewer judgment Depends Performance concern, test gap, unclear naming
P3 Non-blocking No (nit) Style preference, minor refactor suggestion, typo

Authors must resolve all P0 and P1 items. P2 items are resolved or deferred based on reviewer judgment. P3 items can be deferred and tracked as nits in review_lgtm.

The review loop enforces round limits to prevent unbounded iteration:

  • Default: 2 rounds maximum.
  • Configurable: Up to 3 rounds via project configuration.

After the maximum number of rounds, the reviewer must issue a final verdict regardless of remaining items.

Budget controls carried in review_request:

Parameter Description Default
max_turns_reviewer Maximum reasoning turns per review round 8
max_runtime_s_reviewer Maximum wall-clock seconds per review round 600

When a budget is exhausted before review completion, the reviewer sends review_feedback with escalation: reviewer_budget_exceeded and exits.

Since v0.4.3, follow-up rounds no longer require a fresh human confirmation each time on receivers that enable continuation grants. A human-approved grant may carry a review_loop scope — one repository, PR, and sender thread; the allowed lifecycle types; a round ceiling; a wall-clock expiry; and the permitted review side effects — and an in-scope same-thread review_request then auto-invokes the reviewer, recorded in a review_continuation audit block. The grant authorizes running a round, never its verdict: the live PR head stays authoritative (declared heads are compared by exact full-SHA equality), the quality gate above is unchanged, and only rounds that actually ran consume the round budget. Out-of-scope, expired, or revoked requests pause for a human under a pinned reason code (review_continuation_*, or review_loop_invalid for a malformed scope); review_feedback and review_lgtm are always recorded as thread context only.