synthesise
set, the panel fixes all three before the writer or the judge reads a
single finding. For a review by a single model,
get a second opinion.
Shape
The team
One writer and three reviewers, each from a different model family:examples/teams/review-battery.ts (excerpt)
reviewedBy, turns on synthesise,
and puts a judge on refine:
examples/teams/review-battery.ts (excerpt)
The steps
Each round runs these steps in order. When the stage setsgoal, a goal
check runs before them, every round. When it finds a requirement of the
brief unmet, the round goes back to the writer, and none of these steps
run. The judge never decides an unmet requirement.
Check the brief was met shows it.
-
Review. The three reviewers read the page at the same time. Each one
passes it or asks for a revision, and tags each finding
block,should-fixornice-to-have. A reviewer that passes can still list findings; the panel keeps them. A finding from a reviewer that passed, with no tag, counts asnice-to-have. -
Merge. One seat reads every finding and groups the ones that name
the same problem, even when the reviewers word it differently. Each
group becomes one finding. It takes the strongest severity in the group,
credits every reviewer who raised it in
raisedBy, and keeps the evidence and the fix the merging seat picked as clearest.synthesise: trueuses the first reviewer’s seat for this step. Name a seat instead,synthesise: claude('claude-sonnet-4-5'), to use another. -
Cross-review. Each reviewer sees the merged findings it did not
raise. It answers each one
agree,disagreeorbetter fix, with a one-line reason, and forbetter fixthe fix it would make. This is one round: each reviewer replies once. Each reviewer gets the brief and the files under review again, because it answers in a fresh turn. A reviewer whose seat declares tools can read the work to check a claim. -
Votes. Plain code applies the votes. It counts only the reviewers
who voted on that finding.
- Most disagree: the finding is dropped, but only when the reviewers
who disagree also outnumber the ones who raised it, agreed or offered
a better fix. Their reasons stay in the record. Otherwise the finding
stays, marked
disputed, for the judge. So when two of three reviewers raise the same problem, onedisagreefrom the third cannot drop it. - Exactly half disagree: the finding stays, marked
disputed, for the judge. - Most prefer a better fix: the finding carries the first fix offered, in place of its own.
- Otherwise the finding stays as it is.
block. When most voters disagree with one, it stays, markeddisputed. Votes also never drop a finding shown to a reviewer whose seat failed or sent no readable reply in this step. It stays, markeddisputed. - Most disagree: the finding is dropped, but only when the reviewers
who disagree also outnumber the ones who raised it, agreed or offered
a better fix. Their reasons stay in the record. Otherwise the finding
stays, marked
-
Judge. When a judge is set, it decides every finding that is left,
a
blockincluded. It reads each one with who raised it and how the others voted. It decides each one,actorskip, with a one-line reason. The writer gets only the findings the judge acts on, each with the judge’s reason. The next round’s reviewers are told which findings it skipped and why. When the judge acts on any finding, another round runs. When it skips every finding, the page stands as a pass. With no cap on the judge, the rounds end when it skips every finding or every reviewer passes. Ablockgoes straight back to the writer without a judge only when there is no judge. Know when to stop has the judge’s questions.
synthesise leaves it as it is.
synthesise takes the same value on a panel: stage and on
reviewPanel(). On reviewPanel(), every reviewer names its seat, which
answers the cross-review round, and context gives the voters the brief and
the files.
What the run did
The proof runs the file offline. A stand-in plays the Claude, Codex and OpenCode command line tools, and the judge replays the answers recorded injudge.json. The file printed:
Output
write-1 is the Claude seat,
write-2 the Codex seat and write-3 the Gemini seat. In round one,
write-1 and write-2 both said the page uses “backoff” without saying
what it means. The merge made that one finding, crediting both. It kept
the evidence from write-1 and the fix from write-2. write-3 asked for
a table of every client setting. The other two voted against it, so it was
dropped and never reached the writer. write-3 also raised a small
wording point. write-1 agreed and write-2 disagreed, so it stayed,
marked disputed.
The judge then decided the three findings left. It acted on the merged
“backoff” finding and on the missing last retry, and skipped the disputed
wording point as taste. The writer got only those two findings, each with
the judge’s reason. In round two, every reviewer passed the page, so there
was nothing to merge, vote on or judge, and the run passed.
Each panel’s outcome carries synthesis, one PanelSynthesisEntry per
finding. Its result is kept, better fix, disputed or dropped. Its
finding carries raisedBy, and votes, a list of FindingVote answers,
one per voter. The record also holds a review:synthesis event for each
round with findings, with the same entries. The event says when the merger
or a voter failed or sent no readable reply: mergeFailed means the
findings went on unmerged, and noVotesFrom names the reviewers whose votes
are missing. The judge’s decision on each finding is in the
refine:judge event, under findings. Run the same file from the directory the work
belongs in, with the three command line tools signed in, to use the real
seats; add JUDGE=jev to ask Jev.
Full file
Full file
examples/teams/review-battery.ts
A simpler panel: count the acceptances
When you only need to know how many reviewers accept, leavesynthesise
off. The panel counts the acceptances and sends every finding from the
reviewers that rejected the work back to the writer.
Shape
The team
One implementer and a panel of two reviewers from two other model families.agree is how many must accept:
examples/teams/threshold-panel.ts (excerpt)
agree is a whole number from one to the number of reviewers, and the
default is all of them. Set it to the number of reviewers when one dissent
must be enough to fail the step; below that, the change can pass despite a
dissent, and the dissent is still on the record. A panel below the
threshold carries its findings to implement, which runs again with them,
as many times as that stage’s refine allows. When those rounds run out,
the run fails with the last findings.
workflow() refuses the team before any model runs if a reviewer shares a
model family with the seat it reviews, or two reviewers share one: two
reviewers from one family would be one opinion counted twice. The third seat
runs through the OpenCode command line tool, whose adapter needs an absolute
command path; resolveCommandExecutable('opencode') finds it on your PATH
when the file runs.
What the run did
Run the file from the directory the work belongs in, with the Claude Code, Codex and OpenCode command line tools signed in. One real run printed:Output
agree: 1 the change passed on the one acceptance. Set agree to two
and the same run would have paused at the panel instead, because an error
isn’t an acceptance.
The implementer wrote src/double.mjs:
src/double.mjs
test/double.test.mjs:
test/double.test.mjs
Full file
Full file
examples/teams/threshold-panel.ts
Next steps
- Feature delivery: a synthesised panel of three as one of seven steps.
- Review loop: the same idea as a graph form, with
a quorum and
requireDiversityyou set yourself. - Runtime:
workflow,stage,panelandagree.