Review
AI code review using guides from init / sync.
Progress and diagnostics go to stderr. The result goes to stdout (human
text or JSON with --json).
This page helps you pick a mode. Commands, flags, and checklists live on the linked pages below.
Which mode should I use?
Start with what you are trying to review, not the flag name.
| If this sounds like you | Mode | Read next |
|---|---|---|
| You are in a clone and want feedback on your branch or working tree before you open a PR | Local review | OpenRouter on your machine, guides on disk |
Same as local review, but the repo is already inited on serve and you skip per-laptop init/sync |
Remote review | Shared context on the server, diff from your clone |
| You have a PR number and do not need to check out that branch locally | PR review | gh only, guides on disk, AI on your machine |
PR review and remote review do not combine: --remote is only for a local
diff with no PR positional arguments.
How the three modes differ
Same underlying guides from init / sync, different subject (what gets
reviewed) and who keeps that context up to date.
| Local review | PR review | Remote review | |
|---|---|---|---|
| Typical moment | Pre-push in your clone, you own local guides | Open PR by number, you own local guides | Pre-push using the team's shared server context |
| Who runs init/sync | You on the laptop | You on the laptop | Ops on the server (you usually do not) |
| Guides at review time | Laptop cache | Laptop cache | Server dashboard repo |
| Extra setup | OpenRouter | gh auth login |
serve, token, set --remote-host |
| Deep dive | local-review | local-pr-review | remote-review |
Team-wide automatic PR reviews on webhooks are not a fourth review mode.
They go through serve and the GitHub App. Use PR review when you
run the CLI against one PR.
Depth: --improve-matrix
Reviews share one depth control, --improve-matrix=N. 1 is the default. Each
step up adds another pass that audits the draft against the complete diff and the
guides, and raises the output budget so a longer answer fits. The pass preserves
valid findings, corrects inaccurate ones, removes duplicates, and adds what the
first pass missed. More passes cost more tokens and take longer. 2 is a
reasonable step up when a change is high risk or the repository is large. The
value is capped at 4. See Cost for what a pass costs.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Review finished, no open blocking findings |
| 1 | Review finished, at least one blocking finding |
| 2 | Usage or precondition error (init missing, not a git repo, etc.) |
| 3 | Runtime failure or abort |
What counts as blocking
reviewBlocking in config.json decides it, and the same rule is used by
local, PR, remote and the automatic GitHub App reviews.
| Value | A finding blocks when |
|---|---|
model (default) |
The model says so. A P0 always blocks, even if the model labeled it otherwise. |
severity |
Its severity is P0 or P1. P2 and P3 never block, whatever the model said. |
The default keeps the 0.4.13 behavior. severity exists because the model's
own label can move between two reviews of the same code, which flipped the exit
code for the same finding. With severity the same finding set always yields
the same exit code, the same blocking count in --json, and the same GitHub
review type.
co-maintainer config set --review-blocking=severity
co-maintainer config set --review-blocking=model # back to the default
CO_MAINTAINER_REVIEW_BLOCKING overrides it for one environment.
JSON output
With --json, stdout is a single JSON object (schemaVersion 1). Fields
include mode (local, remote, or pr), subject, summary, findings[],
warnings[], usage, and durationMs. Local and remote runs also include diff
metadata and codegraph state. Errors with --json are JSON on stdout as well.
Flag details per mode: Local review, Remote review, PR review.
Human output
Without --json, all three modes print the same format. Only the header
names the mode, because the subject differs:
co-maintainer review · owner/repo · my-branch
4 files · +12 −3 · guide built 2026-09-15 · codegraph used
New (1)
• src/app.ts:16-18 [P1 · blocking] the gate ignores its threshold
A violation exactly at the threshold passes.
Still open (1)
• src/util.ts:4 [P2 · non-blocking] the helper ignores its argument
Closed (1)
✓ src/old.ts:9 [P2 · non-blocking] the dead branch
Summary: 1 new · 1 open · 1 closed · 2 blocking
Findings are grouped Closed, Still open, New, each labeled with the same
blocking decision the exit code uses. The header names the real guide build
date (guide unknown only when no guide timestamp can be read) and the state
the run actually reached: codegraph used, codegraph disabled, or
codegraph unavailable: the last one when codegraph was requested but could
not be prepared, which is also what --json reports.
The severity legend and the "If you'd like me to explain it in more detail, please ask." sentence are not in terminal output: a terminal has nobody to ask, and the legend is fixed noise. Both stay in the GitHub review comment, which is a different reader.
How findings are produced
The model is asked for a JSON object, not for prose. For each finding it returns
the severity, whether it blocks, the path and line span, the symbol, a title, the
explanation, and an optional replacement. co-maintainer renders the Markdown
from that object, so a finding's boundaries are never guessed from the model's
wording. The JSON schema is sent as OpenRouter's response_format when the
provider accepts it. A provider that rejects the combination gets one request
without the schema, and the prompt also asks for a fenced JSON block.
If the answer is not usable JSON, the request is retried once and then, if it
still fails, the older Markdown parser reads it. That parser accepts the em
dash or : as the heading separator, so answers written before this change (and
carry-over records saved by 0.4.13) keep working. The --json output and the
human output are both built from the same parsed findings, so they can never
disagree.
Before any review
| Check | Why |
|---|---|
init or sync on your laptop |
Required for local and PR review |
| OpenRouter for local and PR review | AI runs on your machine |
Remote setup for --remote |
Host, token, repo already inited on the server |