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.

TypeDirectionPurpose
review_requestAuthor -> ReviewerRequest code review of a PR
review_feedbackReviewer -> AuthorReturn review findings
review_addressedAuthor -> ReviewerReport that feedback was addressed
review_lgtmReviewer -> AuthorApprove — 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:

FieldRequiredDescription
prYesPull request number
branchYesBranch name under review
diff_summaryYesBrief summary of the changes
handoff_refNoReference to a handoff packet if this review follows a handoff
max_turns_reviewerNoHard turn budget for reviewer invocation (default 8)
max_runtime_s_reviewerNoHard 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:

FieldRequiredDescription
findings_packetYesPath to the findings packet (relative to project workspace)
roundYesCurrent review round number (1-based)
blocking_countYesNumber of blocking findings in this round
escalationNoEscalation 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:

FieldRequiredDescription
commit_shaYesCommit SHA containing the fixes
changes_summaryYesSummary of what was changed to address the feedback
roundYesThe round number whose feedback is being addressed
touched_filesNoList of files edited to address findings
addressed_finding_idsNoList 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:

FieldRequiredDescription
quality_gate_resultYespass or fail
merge_readyYesWhether the PR is ready to merge (true or false)
nitsNoStructured 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:

SeverityMerge impactBlocking?Examples
P0Always blockingYesSecurity vulnerability, data loss, crash in production
P1BlockingYesCorrectness bug, missing error handling, broken API contract
P2Reviewer judgmentDependsPerformance concern, test gap, unclear naming
P3Non-blockingNo (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:

ParameterDescriptionDefault
max_turns_reviewerMaximum reasoning turns per review round8
max_runtime_s_reviewerMaximum wall-clock seconds per review round600

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