Skip to content

Review workflow

Flow-Next uses review gates before and after implementation.

Cross-model review is not a Flow-Next invention; people have paired one model against another as a reviewer for a while. What is wired in here is the autonomous adversarial loop: a reviewer from a different model reviews each risky change automatically, attended and inside the autonomous drivers.

flowchart LR
  Spec["Spec"] -.-> PlanReview["Optional spec/design review"]
  Spec -->|direct route| Work
  PlanReview --> Work["Work"]
  Work --> ImplReview["Implementation review"]
  ImplReview -->|needs work| Work
  ImplReview -->|ship, several tasks| Completion["Completion review"]
  ImplReview -->|ship, one task| PR
  Completion --> PR["make-pr"]
  Completion -.optional.-> QA["Live-app QA"]
  QA -.-> PR

The static gates above (plan / impl / completion review) read code and specs. The optional live-app QA stage drives the running app at all-tasks-done, before make-pr. pipeline.qa on runs it on every spec, auto runs it, attended or under flow --auto, only when the acceptance describes a UI on a drivable, startable surface, and the default off leaves it to /flow-next:qa by hand.

Every gate runs through a configurable backend, and the point is that it is a different model than the one that wrote the artifact. Set it once with /flow-next:setup or flowctl config set review.backend <backend>, override per run with --review=, and read the full ladder (codex, copilot, cursor, claude, host, none), the backend:model:effort grammar, and the precedence chain in Review backends.

Implementation reviews also carry an always-on code-smell baseline (Fowler’s Refactoring: Feature Envy, Data Clumps, Primitive Obsession, and the rest) across every backend.

Terminal window
/flow-next:plan-review fn-1

Checks whether the spec and plan are complete enough before work begins.

Use it when the work is high risk, cross-module, product-facing, or likely to be delegated. Spec/design review works with zero tasks and catches missing requirements while the fix is still cheap. When tasks exist, it also checks decomposition; risk alone does not require creating tasks.

Terminal window
/flow-next:impl-review fn-1

Runs a second model over the diff. Only introduced findings count toward blocking verdicts.

Use a different model or backend than the implementation model when possible. The point is adversarial pressure rather than another pass from the same context. What the reviewer is handed, and what it reads for itself, is on Review backends.

To make the reviewers look harder at something, name it when you ask (“review fn-1, focus on the retry logic”), or write a standing focus into your project’s instructions, such as “reviews focus on over-engineering and YAGNI”. Work and flow --auto start their reviews without naming a focus, so the standing one applies to every review they run. Impl Review covers which focus wins and what the receipt records.

Review goes by risk, not by size. Every change that touches persisted or shared state, concurrency, security, data layout or migrations is reviewed, and so is every multi-file feature. A small local fix to output, wording or display is not reviewed; the run records the skip and its reason. The author fixes a finding only when it shows the change itself does the wrong thing in a scenario the request covers. Hardening, broader refactors, style and problems that existed before the change are listed as follow-ups, not folded in.

How far the loop goes depends on who is present:

  • Attended. One review, one fix pass, then one re-review with a single reviewer looking only at the fixes. The re-review’s verdict is final; later fixes get focused tests, not another review. The result is handed back to you first, and the review runs in the background and reports when it lands.
  • Unattended (flow --auto, with or without --until=merge), or when you ask to “review until SHIP”. Fix, re-review the fixes, and repeat until SHIP, with flowctl’s round cap and stall check as the backstop. The stall check ends the loop only after the reviewer marks the same finding not-fixed in three consecutive rounds, so the fix you just committed always gets reviewed first. Each declined hardening, scope-creep or pre-existing finding gets one Declined #<n>: <reason> line in the fix commit, which the re-review reads. When the reviewer keeps only findings like that, all below Major, the author may end the loop and records each disagreement, with both sides’ reasons, in the Decisions list and the pull request. A finding that shows a stated requirement broken is always fixed, and the verdict stays the reviewer’s.

The trade-off: looping confirms every fix, which suits unattended runs and weaker implementing models, but it costs rounds and invites hardening scope. One scoped re-review keeps an attended run short.

Three reviewers for risky diffs, one otherwise

Section titled “Three reviewers for risky diffs, one otherwise”

On every backend (codex, claude, copilot, cursor and host), a diff that touches persisted or shared state, concurrency, security, data layout or migrations, or a multi-file feature, gets three reviewers on the first round (concurrent by default), each carrying one axis: correctness and logic, contracts and consistency (do docs, tests, and stated promises agree with what the code does), and integration with unchanged code. A small diff in one area gets one. The coordinator merges the finding sets into one deduped set and runs one fix pass over it. The re-review resumes the reviewer’s session and looks only at the fixes, and it sees the findings the author declined. The merged round counts as one round against the review cap, and the receipt records each reviewer.

The panel is the same whichever backend reviews and whichever harness runs flow-next; a host that cannot dispatch three reviewer subagents in one message runs them back to back and says so. The phrasing that steers the panel in a sentence is in Steering the fan-out. Completion review, land, and external PR bots are unchanged.

One reviewer at a time, for local models and rate limits

Section titled “One reviewer at a time, for local models and rate limits”

A local model or a rate-limited provider may not serve three reviewers at once. Their requests queue, and the later reviewers run out of time before they start. For that setup, run the CLI panel one reviewer after another:

Terminal window
flowctl config set review.fanoutExecution sequential

Each reviewer finishes before the next starts, in the order correctness, contracts, integration. The round still counts once, the findings merge the same way, and the re-review stays one reviewer. The first round takes about as long as the three reviews added together.

  • The review call now waits for every reviewer in turn, so your harness has to let one foreground command run that long. On Claude Code, raise BASH_MAX_TIMEOUT_MS; the Bash tool stops at 10 minutes by default.
  • The setting orders one panel. Parallel workers in work can still review at the same time, so limit how many run at once if your provider needs that too.
  • concurrent stays the default, and nothing turns sequential on for you.
Terminal window
/flow-next:spec-completion-review fn-1

Checks the combined implementation against the whole spec after all tasks are done. It runs on multi-task specs; on a single-task spec the per-task review already covers the whole spec, so completion review records a policy skip, and that task’s implementation review judges the project’s standing criteria instead.

This is different from implementation review. Implementation review checks a diff. Completion review checks whether the full spec is satisfied after all tasks, merges, and fix loops.

Terminal window
/flow-next:qa fn-1

Every gate above is static - it reads code or specs. QA is the live-app gate. It drives the running app like a real user, derives scenarios straight from the spec (AC, R-IDs, boundaries), files P0/P1/P2 findings with evidence, and emits a YES/NO qa_verdict receipt that can feed completion review.

Opt-in - it needs a live deploy + a driver (Flow-Next Drive); with neither it surfaces a BLOCKED verdict rather than failing, and adds nothing to the base flow when unused. It is forbidden from marking PASS by reading source.

Terminal window
/flow-next:make-pr fn-1
/flow-next:resolve-pr 123

The PR body summarizes acceptance coverage, critical files, decisions, memory, deferred findings, and review focus.

When land takes that PR, its merge gate is green checks, a nonblocking GitHub review decision, and zero unresolved threads. A bot’s comment neither satisfies nor blocks the gate; an unresolved thread does. To require more, say so in your instruction file, in branch protection, or in land.mergeVerdictCommand.

For a visual view of the diff, run /flow-next:visual, or ask the agent for an HTML page when you want one.

One table, whatever raised the finding. The rule underneath it: fix the artifact that caused the gap, and put the fix back into .flow/ rather than leaving it in the chat transcript.

SignalResponse
Plan review finds unclear product behaviorRerun /flow-next:refine --biz
Plan review finds technical gapsRerun /flow-next:refine --tech with repo and docs context
Impl review finds an introduced bugRerun /flow-next:work on the affected task
Impl review flags an architectural mismatchRevisit the spec’s decision context
Completion review finds uncovered acceptance criteriaAdd or repair task coverage, or rerun /flow-next:plan
Live-app QA files a P0/P1 (or a BLOCKED/NA verdict)File the finding to the bug track, add a fix task, or supply the missing deploy or driver
A review false positive keeps returningRecord the suppression with evidence, or add validator evidence
The same receipt finding returns unaddressedAddress it, suppress it with evidence, or defer it visibly in the PR body
The planner invented architectureRerun /flow-next:refine --tech with repo and docs context
A worker changed unrelated modulesSplit the task or add dependencies
A human reviewer is confusedImprove task summaries, then regenerate the PR body

Review is part of the workflow, not an afterthought at the end.