Code Review

Which PRs get reviewed

Each review covers new commits only. Filter which pull requests get reviewed by repository, branch, path, author, and draft status.

Two rules decide what gets reviewed. Every review covers only the commits since the last review, never the whole pull request again. And once you commit a pipeline file, its filters are authoritative: a pull request the file does not match gets no review at all.

New commits only

The first review of a pull request covers everything on it, including commits pushed before it was opened. Every review after that covers only the commits since the last review that posted:

base ── A ── B ── C ── D ── E        commits on the PR branch

        └─────────┘
      review 1: base...C             the PR is opened at C; the first
                                     review reads the whole PR (A, B, C)

                       └────┘
      review 2: C...E                D and E are pushed later; the next
                                     review reads only D and E, and never
                                     re-comments on A, B, or C

When priya-shah opens "Expire pending trades on account deactivation" and pushes twice more over the afternoon, the pipeline runs three times, each time reading only what that push added. If the third push drops a rest-period check, the comment lands on that line, with no repetition of the earlier reviews.

Two properties follow:

  • A review that fails does not count as coverage. If a review errors or hits its budget, the commits it was reading stay unreviewed, and the next review covers everything since the last one that actually posted. Nothing is silently skipped.
  • A clean review still counts. A review that finds nothing posts a one-line summary rather than invented nitpicks, and the commits it read are covered.

Each review anchors to the exact commit it reviewed, so its comments stay attached to the right lines as the pull request grows. The reviewed range is visible on every review: the dashboard shows the commits each review covered, and the API reports it as scope.watermark (the last reviewed commit) and scope.head.

Repo scoping

Two independent fields name repositories, and they answer different questions:

  • pull_requests.repositories is the watch set: which repositories' pull requests trigger reviews.
  • sandbox.repositories is the context set: extra repositories cloned into the reviewer's sandbox. The pull request's own repository is always cloned, so it never needs listing.
ellipsis:
  version: v1
  kind: code_review
  name: API review with web context

pull_requests:
  repositories: [splitshift-api]

sandbox:
  repositories:
    - name: splitshift-web

Only splitshift-api pull requests are reviewed, and splitshift-web is on disk while reviewing, so a change to an API response shape is judged against the client that consumes it.

The watch set is an include-minus-exclude filter. A bare list is shorthand for include; an empty or omitted include means every repository of the installation, so an exclude-only filter reviews everything except the listed repositories, and stays correct as repositories are added to the organization later:

pull_requests:
  repositories:
    exclude: [sandbox-experiments, splitshift-docs]

A committed file makes its watch set authoritative. Scoping review to splitshift-api means "and nothing else": a pull request in splitshift-mobile gets no review, rather than falling back to the built-in pipeline. Ellipsis never reviews, or bills you for, something your file excluded.

Pull request filters

Beside repositories, the pull_requests: block filters on branch, draft status, labels, changed paths, and author. All declared filters must pass; an omitted filter passes everything.

ellipsis:
  version: v1
  kind: code_review
  name: API release review

pull_requests:
  repositories: [splitshift-api]
  base: [main, "release/*"]
  draft: false
  paths: [src/**, sql/**]
  for:
    users: true
    bots: false

Against that file:

  • priya-shah's "Reject overlapping shift trades" into main, touching src/trades.py: reviewed.
  • The same change opened as a draft: not reviewed (draft: false), until it is marked ready and the next push lands.
  • A Dependabot bump into main: not reviewed (bots: false, which is also the default).
  • marcus-lee's README-only change: not reviewed (no changed file matches paths).

Field by field:

  • base and head match the target and source branch. Each entry is an exact name, a prefix glob like release/*, or the literal default for the repository's default branch whatever it is named.
  • draft unset reviews drafts and non-drafts alike; true or false requires that state.
  • labels passes a pull request carrying at least one listed label, matched exactly including case. Labels are read when the review triggers, on the open or a push; adding a label to an open pull request does not trigger a review by itself.
  • paths are include-only globs over the pull request's full changed-file set; any matching file passes. A pattern with a slash is repository-root-relative, ** crosses directories, a slashless pattern matches at any depth, and a leading / anchors to the root. Negated patterns (!foo) are a validation error.
  • for gates on the pull request's author, the account that opened it, for the pull request's whole life. Humans are included and bots excluded by default; each side takes true, a list of logins, false, or an include-minus-exclude mapping. So bots: ["renovate[bot]"] reviews Renovate's pull requests and no other bot's, and a commit someone else pushes onto an excluded author's pull request is still not reviewed.

Every field, type, and default is in the configuration reference.

Per-reviewer filters

The pipeline's pull_requests: decides which pull requests get reviewed at all. Each reviewer can carry its own pull_requests: block deciding which of those it bothers reading, with paths, base, and head only:

ellipsis:
  version: v1
  kind: code_review
  name: Backend review with a migration specialist

pull_requests:
  repositories: [splitshift-api]

include_default_reviewers: true

review:
  - name: migration-safety
    claude:
      system: |
        Review database migrations for production safety. Check for
        locking that blocks writes on large tables, missing backfills
        for new non-null columns, and rollout ordering that breaks if
        the migration and the code deploy out of order.
    pull_requests:
      paths: ["**/migrations/**"]

On a pull request that touches a migration, both the built-in reviewer and migration-safety run. On any other pull request, only the built-in reviewer runs, and the specialist costs nothing: no sandbox starts, no model call is made, and its share of the run budget goes to the reviewers that did run.

A reviewer's block takes paths, base, and head only; repositories belongs to the pipeline, which owns the watch set. To turn a reviewer off entirely, remove it from review:; to run only your own reviewers, declare review: without include_default_reviewers and the built-in one is replaced. See Reviewers.

When reviews are skipped

A push produces no review when:

  • Code review is off. The organization-wide setting gates every path in; see the quick start.
  • Your pipeline file does not match the pull request. A committed file's filters are authoritative, so a non-matching pull request gets nothing rather than the built-in pipeline. A file with enabled: false counts the same way: it declares intent, so it suppresses the built-in pipeline rather than falling through to it.
  • There is nothing new. A push whose head was already covered by the last posted review is skipped before anything starts or costs anything. Re-delivered or out-of-order events are absorbed the same way.
  • The pipeline is over its trailing budget. budget.day and budget.week are checked before a review starts, so a push storm cannot turn into a bill; reviews resume when the window rolls. See budgets.
  • A review of the pull request is already running. The push does not start a second review. When the running one finishes, Ellipsis re-checks the pull request and immediately reviews anything that landed in the meantime, so the commits are covered by the next review rather than lost.
  • Every reviewer's own filters excluded the pull request. A pipeline whose only reviewer is scoped to sql/** reviews nothing on a pull request that touches no SQL. That shows up as a cancelled review on the reviews dashboard, the commits stay uncovered, and a later push that does touch sql/** shows the specialist the whole accumulated range.

In every case above the incremental rule holds: commits nothing reviewed stay unreviewed, and the next review that runs covers all of them. The one deliberate exception is a pre_review agent you configured cancelling a review: that is a judgment that the range needs no review, so it counts as coverage and the next review starts after it.

Review a branch without a PR

agent review with no pull request number reviews the work in your tree, before any pull request exists. The CLI snapshots your working tree and pushes it to a sidecar branch (ellipsis/review/<your-branch>, never the branch you are working on), and Ellipsis finds or creates one reusable draft pull request to hold it, because a review is structurally a pull request review: the range, the checkout, and the comments all need one.

$ agent review
✓ pushed 4f2c9a1b07d3 to ellipsis/review/rest-period-rules
✓ reviewing splitshift-hq/splitshift-api#519 (crun_8Kw2mVq4Tj9e)

review:    crun_8Kw2mVq4Tj9e
pr:        splitshift-hq/splitshift-api#519  https://github.com/splitshift-hq/splitshift-api/pull/519
status:    completed
scope:     base...4f2c9a1
cost:      $3.87
completed: 2026-07-31 18:22

Reviewed the rest-period rule changes. One finding worth a look; details inline.

src/scheduling/rest_period.py:84  [4/5 correctness]
    The 11-hour rest check compares shift start times in the venue's
    timezone but the previous shift's end time in UTC, so a worker
    crossing midnight UTC can be offered a shift 3 hours after clocking
    out.
    Convert both timestamps with venue.tz before subtracting.

How the draft pull request behaves:

  • It is titled [ellipsis review] <branch>, opened against the repository's default branch, authored by the Ellipsis bot, and marked as opened for review, never to merge.
  • It is reused: later reviews of the same branch push to the same sidecar and review the same draft pull request. Nothing is auto-closed; close it when the work lands.
  • Branch reviews from the CLI post nothing to GitHub. The findings print in your terminal instead.
  • A branch review always covers the branch's full range, since the sidecar's contents are replaced on every push.

agent review --branch <name> reviews a branch you already pushed, skipping the snapshot. The same flow is available over the REST API by passing branch instead of pull_request_number to POST /v1/reviews.