Docs
Code Review

Reviewers

One built-in reviewer, bugs, reads every pull request on Claude Opus 5. Add reviewers with their own prompts, models, and filters, or replace it.

A reviewer is a prompt and a model that reads the unreviewed commits and proposes findings. Each reviewer runs in its own sandbox with the repository checked out at the reviewed commit, so it judges the change against the code around it, not the diff alone. Identical findings from different reviewers collapse, and Ellipsis posts the rest as one review. Nothing else filters them unless you declare a gatekeeper, so a reviewer's prompt is what decides review quality.

The default reviewer

With reviews enabled and no pipeline file, one reviewer runs: bugs, on Claude Opus 5. Its brief is a staff engineer's, with one goal: find the defects in the change before they reach production. Not to summarize the diff, praise it, or suggest how it would have written it. It reads the diff first, then enough of the surrounding code to know whether each change is correct: a new early return is only a bug once its callers are read, so it greps for callers and reads git history where a line's intent is unclear.

It looks for:

  • Correctness errors. Inverted conditions, off-by-one bounds, a branch that returns the wrong variable, arithmetic that overflows or divides by a value that can be zero.
  • Unhandled edge cases. Empty collections, zero and negative values, an absent optional used as if present, duplicate or out-of-order input.
  • Error handling. Failures swallowed silently, retries that repeat a non-idempotent side effect, operations that leave the system half-updated with no way back.
  • Concurrency and ordering. Reads racing writes, a check whose condition can change before the action that depends on it, a cache written before the source of truth.
  • Security. Untrusted input reaching a query, shell command, or file path; a missing or wrong authorization check; a credential logged or written to disk. Judged on exploitability, not theory.
  • Regressions in behavior callers depend on. Removed or renamed fields, endpoints, and parameters; changed defaults; deleted handling whose callers are still out there.
  • Data and deploy hazards. A migration that breaks code still running, a lock held long enough to block writes on a large table, a change that only works if two things deploy simultaneously.
  • Missing tests, only when their absence is the finding.

What it never raises is equally deliberate: style, formatting, and naming (a linter owns those), speculative concerns with no concrete failing input, restatements of what the diff does, and praise. A correct, low-risk change gets a one-line confirmation rather than invented nitpicks, and still counts as reviewed.

Each finding states the defect and the input or state that produces the failure, anchored to the lines that cause the problem and rated 1 to 5 for severity. Comments are short by instruction: where the fix is a concrete edit to those lines, the reviewer puts it in a GitHub suggestion you can apply in one click rather than describing it in prose, and no finding runs past about four sentences.

Custom reviewers

A pipeline file declares its reviewers under review:. Each takes a name, the same claude block an agent config uses (system, model, and the rest), and optionally its own sandbox, skills, budget, and pull_requests filters. Every field is in the configuration reference.

Declaring review: replaces the built-in bugs reviewer, so a pipeline that wants a general pass beside a specialist declares both. Splitshift's payout math moves money in integer cents, so a specialist watches it:

ellipsis:
  version: v1
  kind: code_review
  name: Backend review with a tip-pool specialist

pull_requests:
  repositories: [splitshift-api]

review:
  - name: correctness
    claude:
      model: claude-opus-5
      system: |
        Find the bugs in this change before they reach production. Read
        the diff, then read enough of the surrounding code to know
        whether each change is correct. Cover correctness, edge cases,
        error handling, concurrency, security, and regressions in
        behavior callers depend on. Skip style and formatting.
  - name: tip-pool
    claude:
      model: claude-opus-5
      system: |
        You review changes to tip pooling and payout math.

        Money moves through this code in integer cents. Flag arithmetic
        that converts to floats, division whose remainder is dropped
        instead of distributed, and rounding done per worker rather than
        once per pool. Check that the split always sums to the pool.

        Comment on the exact line with the exact failure. Correct math
        gets one line of confirmation, not invented concerns.
    pull_requests:
      paths: [src/payments/**]

budget:
  run: 15.00

When marcus-lee reworks the payout split, tip-pool runs beside correctness, and its finding lands as an inline comment on the changed line of src/payments/tip_pool.py:

Splitting the pool with round(pool_cents / len(workers)) rounds each share independently, so the shares do not sum to the pool: an $847.00 pool across 6 workers pays out $847.02.

The share is computed inside the per-worker loop in allocate_tips, so the error grows with the worker count instead of cancelling.

    share_cents, remainder = divmod(pool_cents, len(workers))

Three things to know when writing one:

  • The prompt is the reviewing brain only. Ellipsis tells every reviewer which commit range to review and how its findings are delivered, so never restate the scope, and never instruct a reviewer to post to GitHub: reviewers propose findings, and Ellipsis posts the one review.
  • Reviewers run in parallel, so several cost latency only once. Each runs in its own sandbox, and reviewers without their own budget split the run budget evenly; see budget.
  • A reviewer with its own pull_requests: filters skips pull requests that are not its job, and a skipped reviewer costs nothing. tip-pool above never starts on a pull request that leaves src/payments/ untouched. How those filters match is covered in per-reviewer filters.

Running only your own

A single reviewer under review: is a pipeline whose only pass is yours. That is the right shape when your own prompt is the review:

ellipsis:
  version: v1
  kind: code_review
  name: House review

pull_requests:
  repositories: [splitshift-api, splitshift-web]

review:
  - name: house-rules
    claude:
      model: claude-sonnet-5
      system: |
        Review this diff against the conventions in CONTRIBUTING.md and
        the service patterns in docs/architecture.md. Comment only where
        the diff departs from a documented convention, and cite the
        document. Skip anything a linter catches.

Only house-rules reviews these pull requests; the built-in bugs reviewer does not run.

Leave review: out of the file entirely to keep the built-in reviewer instead: unset inherits it, and declaring the key replaces it. So a file that only changes the budget or the watch set still gets the built-in review, and a file that declares reviewers owns the whole list.

Constraints, enforced when the file syncs:

  • A pipeline may declare at most 8 reviewers. More is a validation error, never a silent trim.
  • Every stage agent's name must be unique across the whole file, across every stage.
  • review: [] disables the review stage entirely, which is distinct from leaving the key out.

Whatever the reviewer list, its findings post as written. If you want a second read that judges them first, declare a gatekeeper; the built-in pipeline runs none, so tune the reviewer's own prompt before adding a stage that deletes its output.