Which PRs get reviewed

One filename, and the repository holding it decides what it governs. Each review then covers only the commits since the last one.

Two rules decide what gets reviewed. There is one pipeline filename, code_review.yaml, and which repository you commit it to decides whether it governs that repository or the whole organization. And every review covers only the commits since the last review, never the whole pull request again.

Where the file lives is what it governs

Where you commit code_review.yamlGoverns
Any repository, at its rootThat repository.
Your .ellipsis repository, at its rootEvery repository in the organization.

.ellipsis/code_review.yaml works too, in any repository, and governs that repository. When a repository holds both, the root file wins.

Ellipsis takes the first one that exists: the repository's own file, else the organization-wide one, else the built-in pipeline. Consequences:

  • The .ellipsis repository is never itself reviewed. It is pure configuration, which is what keeps one filename unambiguous.
  • A repository's own file replaces the organization-wide one, rather than layering onto it. A repository file that sets only pull_requests: runs the built-in reviewers, not the ones your organization-wide file declares, so copy across whatever you meant to keep.
  • The organization-wide file's filters scope its own reach, not the organization's. A repository it excludes reviews itself the moment it commits its own code_review.yaml.
  • Whichever file wins is still an overlay onto the built-in pipeline. Fields it leaves unset inherit the built-in ones. See the pipeline file.
  • ellipsis.enabled: false makes the file inactive, so Ellipsis reads it as no policy at all and continues to the next rung. Use it to park a draft, not to opt a repository out.
  • A pipeline at any other path is a configuration error, reported on the file when it syncs.
  • If Ellipsis cannot read your .ellipsis repository (the App was removed from it, or it was renamed or deleted), the organization-wide rung drops and reviews continue on the built-in pipeline.

Only a file on the default branch is live. A code_review.yaml added on a pull request branch does not govern that pull request.

To turn reviews off in one repository, commit a file there whose pull_requests: matches nothing. Its filters are authoritative for that repository, so nothing falls through:

# code_review.yaml: no reviews in this repository
ellipsis:
  version: v1
  kind: code_review
  name: Review disabled

pull_requests:
  for:
    users: false
    bots: false

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
  • 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 posted.
  • A clean review still counts. A review that finds nothing posts a one-line summary, and the commits it read are covered.
  • Coverage belongs to the pull request, not to the pipeline. Adopting, editing, or deleting a pipeline file mid-pull-request picks up where the last review left off.

Each review anchors to the exact commit it reviewed. The dashboard shows the commits each review covered, and the API reports the range as scope.watermark (the last reviewed commit) and scope.head.

Repo scoping

Two fields name repositories, and they answer different questions:

  • pull_requests.repositories is the watch set: which repositories' pull requests this file reviews. Valid only in the .ellipsis repository's copy; declaring it anywhere else is a configuration error.
  • environment.repositories is the context set: extra repositories cloned into every stage sandbox. The pull request's own repository is always cloned. Valid in either file.
# code_review.yaml in your .ellipsis repository
ellipsis:
  version: v1
  kind: code_review
  name: API review with web context

pull_requests:
  repositories: [api-repo]

environment:
  repositories:
    - name: web-repo

Only api-repo pull requests are reviewed, and web-repo 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 include-minus-exclude. A bare list is shorthand for include; an omitted include means every repository, so an exclude-only filter reviews everything except the listed repositories and stays correct as repositories are added later:

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

The watch set is authoritative for this file. Scoping the organization-wide file to api-repo means a pull request in mobile-repo gets no review, rather than the built-in pipeline. Ellipsis never reviews, or bills you for, something your file excluded.

Per-repository filters

paths globs are relative to one repository, and branch conventions differ between repositories, so one top-level filter set rarely fits an organization. An include entry may carry its own base, head, draft, labels, and paths, which replace the top-level values for that repository. A key the entry leaves out inherits the top-level one; an explicit [] overrides it to "all". for stays organization-wide.

pull_requests:
  base: [default]
  repositories:
    include:
      - name: api-repo
        paths: [api/**, sql/**]
      - name: docs-repo
        base: [docs]
      - web-repo

api-repo is reviewed only when a pull request into its default branch touches api/ or sql/; docs-repo is reviewed on pull requests into docs; web-repo inherits the top-level filters. A repository named twice, or listed under both include and exclude, is a configuration error.

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: [api-repo]
  base: [main, "release/*"]
  draft: false
  paths: [src/**, sql/**]
  for:
    users: true
    bots: false

Against that file, a change into main touching src/trades.py is reviewed. The same change opened as a draft is not, until it is marked ready and the next push lands. A Dependabot bump is not (bots: false). A README-only change is not (no changed file matches paths).

  • base and head match the target and source branch: an exact name, a prefix glob like release/*, or the literal default for the repository's default branch.
  • 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; 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, for the pull request's whole life. users and bots each take true, a list of logins, false, or an include-minus-exclude mapping, and a side you omit inside for: is false. Logins match exactly, and bots carry their suffix: bots: ["renovate[bot]"] reviews Renovate's pull requests and no other bot's. A pull_requests: block with no for: reviews humans and every bot, including the two the built-in pipeline excludes; write the exclusion back if you want it.

Every field, type, and default is in the 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, with paths, base, and head only, deciding which of those it reads. A specialist scoped to paths: ["**/migrations/**"] never starts on a pull request that touches no migration: no sandbox, no model call, and its share of the run budget goes to the reviewers that did run. The worked example is under custom reviewers.

When reviews are skipped

A push produces no review when:

  • Code review is off. The organization-wide setting gates every path in, including the API.
  • The governing pipeline does not match the pull request. Its filters are authoritative, so a non-matching pull request gets nothing rather than the built-in pipeline.
  • There is nothing new. A push whose head was already covered by the last posted review is skipped before anything starts or costs anything.
  • The pipeline is over its trailing budget. budget.day and budget.week are checked before a review starts; reviews resume when the window rolls. See budgets.
  • A review of the pull request is already running. When it finishes, Ellipsis re-checks the pull request and immediately reviews anything that landed in the meantime.
  • Every reviewer's own filters excluded the pull request. That shows as a cancelled review on the dashboard, and the commits stay uncovered until a later push matches.

In every case the incremental rule holds: commits nothing reviewed stay unreviewed, and the next review covers all of them. The one 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.

Reviewing on demand

POST /v1/reviews reviews an open pull request without waiting for a push. Which pipeline runs is not a parameter: it resolves from the repository's files exactly as above, so an on-demand review can never disagree with the automatic one. The request names owner, repo, and pull_request_number, plus an optional scope (pin a historical range by watermark and head, or kind: full to re-review the whole pull request) and post: false, which returns the findings without writing anything to GitHub. When nothing is new the response is status: skipped, not an error. See Reviews.

The CLI wraps the same route. From a checkout of the repository:

agent review 123

It streams the review and prints each finding as path:line [severity/5 category] with its claim. --full re-reviews the whole pull request, --no-post keeps the findings in your terminal, and --repo owner/name targets a repository you are not inside.

On this page

Schedule a demo