Introduction
Last time, I had dev-orchestra review the whole change once more at the end.
dev-orchestra is a plugin for Claude Code / Codex / Antigravity that takes a single-sentence request and runs design, implementation, testing, reviews by multiple AIs, and fixes.
Still, “hand it everything from design onward” is a fairly big step just to try it out. Often I have a half-finished change on my machine and only want a few AIs to look at it.
dev-orchestra’s review works on its own, separately from the other stages. This time I’ll walk through using only the review:
- Three commands:
review snapshot→review run→review show - What the snapshot freezes, and what’s left under
.ai/ - The options I use most, and how to choose
--basewhen showing a PR branch - An example of reviewing prose (posts on this blog) instead of code
dev-orchestra is open source on GitHub (MIT license). If it looks useful, a star would mean a lot.
Setup
| Item | Details |
|---|---|
| dev-orchestra | 1.3.0, preset standard (optimization.level at the default balanced) |
| Reviewers | claude-general (Claude Opus), codex-general (Codex CLI 0.163.0, gpt-6.1-sol), claude-security (Claude Sonnet), claude-test (Claude Sonnet) |
| Claude Code | 2.1.312 |
| Environment | Windows 11, Git Bash, Python 3.14.7, Git 2.55.0. The configuration lived in a separate folder (DEV_ORCHESTRA_HOME) |
Installation steps are in the Claude Code post and the Codex post. Installation and initial setup are the same when you only use the review.
The Subject: A Branch That Adds Coupons
For this, I made a small Python package, shopcart. main only has a function that returns the cart subtotal, and the branch feature/coupon adds a coupon function.
PERCENT_OFF = {"SAVE10": 10, "SAVE20": 20}
AMOUNT_OFF = {"SAVE500": (500, 3000)} # code: (yen off, minimum subtotal)
def apply_coupon(amount, code):
"""Return the amount to pay after applying the coupon `code`."""
if code in PERCENT_OFF:
discount = amount * PERCENT_OFF[code] // 100
return amount - discount
off, minimum = AMOUNT_OFF[code]
if amount > minimum:
return amount - off
return amount
The README says “SAVE500 takes 500 yen off when the subtotal is 3,000 yen or more,” “an unknown code leaves the amount unchanged,” and “codes are case-sensitive (on purpose).” In other words, I planted two bugs on purpose in this code (> should be >=, and an unknown code raises KeyError). All three coupon tests (five with the cart tests) pass.
1. Freeze the Change (review snapshot)
Freeze the change since the branch point (main):
dev-orchestra review snapshot --base main
Snapshot: .ai/workflows/b1627574daa6/reviews/review-target.diff
strategy: git diff main
files: 4
size: 2249 bytes (sha256 27ff110afa0b)
The snapshot step freezes the diff to review into one file so that every reviewer sees the same thing. Editing files after the snapshot doesn’t change the diff that round’s reviewers see. Without --base, it freezes the difference between the working tree and HEAD (your uncommitted changes). New files that aren’t committed yet are included by default.
What it freezes stays under .ai/:
| File | Contents |
|---|---|
review-target.diff | The diff shown to the reviewers |
review-target.json | Where the diff came from (base, base_commit, head), the list of changed files, lines added and deleted, the diff’s sha256, and files that weren’t sent (withheld) |
state.json | The record of this piece of work (the workflow) |
The sha256 is also written into each reviewer’s report, so you can check afterward that “everyone saw the same diff.”
.ai/ automatically gets a .gitignore containing just *, so you won’t commit it by accident.
With
review.context.surrounding: enclosingin the configuration, it also freezes the functions and classes around the diff and passes them to the reviewers (the default isnone). Details are in references/reviews.md.
2. Run the Review (review run)
dev-orchestra review run
ok claude-general claude opus 3 finding(s)
1 successful, 0 failed
Consolidated: .ai/workflows/b1627574daa6/reviews/consolidated.md
note: claude-test (when: relevance) added: shopcart/__init__.py is not documentation
note: no test result recorded for this change, so the review is running unchecked. `state record test ok` before `review run` lets this stop a review of a red tree.
note: low-risk change (4 file(s), 49 line(s)): 1 reviewer instead of the full panel (claude-general). Cross-model disagreement is what a second reviewer buys; raise optimization.level or the low_risk thresholds to keep it.
It finished in 17 seconds. But only one reviewer looked at it. The first note: says the test-focused reviewer claude-test was made a candidate because “this isn’t a docs-only change.” Even so, only claude-general ran. As the last note: says, under balanced a small change that touches no high-risk path (4 files and 49 lines here) gets cut down to one reviewer. The same thing happened in the measurement post.
The second note: says no test result was recorded. When you only use the review, you can ignore it. If you don’t want to review a change whose tests are failing, record dev-orchestra state record test ok (or failed) first, and it will stop the review when the result is failed.
3. Read the Results (review show)
dev-orchestra review show
Here’s the start of the output and the first finding (the rest is omitted):
Source: .ai/workflows/b1627574daa6/reviews/consolidated.json
# Consolidated review
- Generated: 2026-10-29T13:19:24Z
- Iteration: 1
- Snapshot: 27ff110afa0b
- Reviewers: 1 ok / 1 total
- Coverage: round complete, change complete
- Findings: 3 (0 duplicate report(s) merged)
## Reviewers
- ok [general] claude-general / claude / opus -- 3 finding(s)
## Findings
### F1 [HIGH] correctness
- Location: `shopcart/coupon.py`:12
- Reported by: claude-general
- Possible duplicate of: none
- Triage: needs-triage
- Problem: Any code missing from `PERCENT_OFF` drops through to `AMOUNT_OFF[code]`, so an unknown code raises `KeyError`. The README says an unknown code should leave the amount unchanged.
- Impact: Checkout crashes when a user enters a mistyped or lowercase code like `save10`. The README calls out lowercase codes as invalid on purpose, so this input is expected.
- Evidence: `off, minimum = AMOUNT_OFF[code]`
- Recommended fix: Add `if code not in AMOUNT_OFF: return amount` before the lookup, or use `AMOUNT_OFF.get(code)` and return `amount` when it is `None`.
There were three findings: the two planted bugs (F1, the KeyError; F2, the >), and F3, about missing boundary tests. Each finding lists severity, location, problem, impact, evidence, and fix in a fixed format.
With --json you get the same content as JSON, so you can hand it to other tools.
4. Show It to Several AIs (—only)
Cut down to one reviewer, it isn’t “several AIs.” If you name reviewers with --only, the panel isn’t cut. I added the other three on the same snapshot:
dev-orchestra review run --only codex-general claude-security claude-test
ok codex-general codex gpt-6.1-sol 2 finding(s)
ok claude-security claude sonnet 4 finding(s)
ok claude-test claude sonnet 5 finding(s)
3 successful, 0 failed
Consolidated: .ai/workflows/b1627574daa6/reviews/consolidated.md
note: claude-test (when: relevance) added: named by --only
note: no test result recorded for this change, so the review is running unchecked. `state record test ok` before `review run` lets this stop a review of a red tree.
The three ran in parallel and finished in 19 seconds. Even when you run only some reviewers with --only, the consolidated result also includes other reviewers’ reports on this snapshot. review show now showed four reviewers and 14 findings:
- Reviewers: 4 ok / 4 total
- Coverage: round complete, change complete
- Findings: 14 (0 duplicate report(s) merged)
Both planted bugs were reported as bugs by three reviewers independently, and claude-test also touched on them as “there’s no test that checks this.” Which of the 14 to accept, and which to mark as duplicates or reject, is the subject of the next post.
If you want all four from the start, list all four in --only, or raise optimization.level. You can also name them by role (general, security, and so on).
5. Options I Use Most
| Option | When to use it |
|---|---|
--only <id or role> | Run only some reviewers. This also turns off the cut in reviewer count |
--sequential | Run reviewers one at a time, in order. Useful for finding out which reviewer is stuck |
--context "…" | Give every reviewer the same premise (“the README is the spec,” “this is a blog post,” and so on) |
--timeout <seconds> | Change the per-reviewer time limit for this run only |
Used together, it looks like this. I tried this section and the next one in a copy of the sample repository. I named the workflow pr-check with the environment variable DEV_ORCHESTRA_WORKFLOW (without it, a name like b1627574daa6 is assigned automatically).
dev-orchestra review run --only claude-general codex-general --sequential --timeout 300 --context "This is a pull request that adds coupons. The README is the spec."
ok claude-general claude opus 3 finding(s)
ok codex-general codex gpt-6.1-sol 2 finding(s)
2 successful, 0 failed
Consolidated: .ai/workflows/pr-check/reviews/consolidated.md
note: no test result recorded for this change, so the review is running unchecked. `state record test ok` before `review run` lets this stop a review of a red tree.
Since they ran in order, it took 27 seconds.
6. —base When Showing a PR Branch
--base main takes the difference between main and the current working tree (strategy: git diff main). If main has moved on since you branched, changes added on main show up in the diff as if this branch had deleted them.
To try it, I made a commit on main after branching that adds one line to the README, then froze again with --base main. The diff contained this line:
-- `subtotal` ignores nothing: every item counts
A line this branch never touched is shown to the reviewers as a “deleted line.” Passing the branch point (merge-base) to --base kept this line out:
dev-orchestra review snapshot --base $(git merge-base main HEAD)
Snapshot: .ai/workflows/pr-check/reviews/review-target.diff
strategy: git diff 77d4296d87f869eb4af4d5cf1ca41b135cef2b31
files: 4
size: 2249 bytes (sha256 27ff110afa0b)
The sha256 matches the first snapshot, taken before main moved on. A GitHub PR also shows the diff from the branch point, so when showing a PR branch I recommend passing the merge-base. To compare against the remote main, run git fetch and use the merge-base with origin/main (here I tried it with the local main).
7. Lockfile Contents Aren’t Sent (review.exclude)
Upgrading dependencies puts hundreds of lines of diff in the lockfile. No person wrote them, yet they use tokens for every reviewer. By default dev-orchestra doesn’t send the contents of diffs to lockfiles, dist/, vendor/, node_modules/, minified JS and CSS, source maps, and *.snap (review.exclude).
To try it, I put a 306-line package-lock.json standing in for an npm lockfile (a new, uncommitted file) into the copy of the sample, added a one-line comment to cart.py, and took the snapshot without --base (the workflow is named excl).
Snapshot: .ai/workflows/excl/reviews/review-target.diff
strategy: git diff HEAD
files: 1
size: 311 bytes (sha256 a42cd872c7e8)
withheld: 1 file(s), 306 changed line(s) not sent to reviewers
package-lock.json (package-lock.json)
reviewers are told these changed; --no-exclude sends them in full
The reviewers are still told the file names and how many lines changed, so nothing is hidden. To send everything, add --no-exclude. I cover tokens and cost in the 17th post of the series (scheduled for November 23, 2026).
8. It Works on Prose, Not Just Code
The diff you review doesn’t have to be code. On this blog, I have review run review posts before they’re published (the “Review” section of docs/blog/series.md). Once I finished writing this post, I had it reviewed together with the next post like this:
dev-orchestra review snapshot
dev-orchestra review run --only claude-general codex-general --context "These are two Japanese blog posts (a series on dev-orchestra), not code. Review facts, not style: check that every command, option, output and behaviour described matches dev-orchestra 1.3.0, whose docs are in C:/Projects/dev-orchestra (references/reviews.md, references/cli.md, references/workflow.md) and ~/.claude/plugins/cache/dev-orchestra/dev-orchestra/1.3.0. The outputs quoted were captured from real runs against a small sample repo; flag any claim that contradicts the docs, any internal inconsistency between the two posts, and anything misleading to a reader. Repository rules for posts are in CLAUDE.md and docs/blog/writing.md."
The reviewers are asked to review code. So I use --context to say “these are posts, not code” and where to check the facts. I’ve never had a post reviewed without --context, so I haven’t tested what happens if you leave it off (I replaced the home path in the command with ~).
When I had this post and the next one reviewed together, claude-general and codex-general gave six findings. Besides one saying the translations didn’t exist yet (I was still writing), they caught numbers that disagreed between the two posts, such as “the test counts don’t match across the two posts (it should be 3 + 5, not 10)” and “the two posts disagree on how many reviewers found the bugs.” I fixed all of them.
The Downsides
- The diff is sent to the vendor of each registered reviewer. With the four-reviewer panel, it went to both Anthropic and OpenAI. Reviewers can read surrounding files (read-only), so it may not be just the diff that’s sent. For code that can’t leave your organization, use the approach that makes a local LLM the reviewer
- Small changes get cut to one reviewer by default. If you want several AIs, you need to set the panel with
--onlyoroptimization.level - Findings are claims, not facts. Four reviewers gave 14 findings, but many overlap; fixing them as-is means asking for the same fix several times
- Tokens grow with the number of reviewers. Reviewers run in parallel, so time doesn’t grow much, but you pay for each reviewer
Summary
- dev-orchestra’s review works on its own, without the design and implementation stages
- Freeze the diff with
review snapshot, review withreview run, and read withreview show - The frozen diff and results stay under
.ai/, and.gitignorekeeps them out of commits - Small changes are cut to one reviewer by default. To show it to several AIs, name them with
--only - When showing a PR branch, pass the merge-base to
--base - Contents like lockfiles aren’t sent by default. It also works for reviewing posts, not just code
Next time (scheduled for November 13, 2026), I’ll sort the 14 findings from this post into accepted, rejected, and duplicate, and have the fixer address them.
GitHub: istb16/dev-orchestra (a star would be very encouraging)
All posts in this series are in the list of “dev-orchestra” posts.
Related Posts
I Had dev-orchestra Review the Whole Change Once More at the End
I tried the closing review of the whole change (review.whole_change_recheck) added in dev-orchestra 1.3.0 on a small Python package. After a fix-only round came back with nothing, the whole-change round found one clash between the fix and the earlier change. With a fix that clashed on purpose, the fix-only round caught it first.
I Measured dev-orchestra: Time per Request, and Findings by Number of Reviewers
With dev-orchestra 1.2.1, I made one small feature request and measured how long it took (about 6 minutes, not counting my approval) and how many findings were reported and accepted with 1, 2, and 4 reviewers. More reviewers meant more accepted findings, but the extra ones were about tests.
Giving dev-orchestra Standing Instructions per Role
I tried instructions, added in dev-orchestra 1.2.1. Standing instructions for the implementer or reviewers written in the repository go into every prompt. I check, with real output, how they are shown, where they go, and how a change to the instructions is treated.