Pull request review
Enable review on a repository and Hyrax reviews the pull requests you open, update, or reopen — no job to submit. Each review posts a Hyrax Review check run and a comment on the PR. A few kinds of PRs are deliberately skipped — see What isn't reviewed.
Review is off until you turn it on for a repo, so you can roll it out one repo at a time.
What you get
- A comment on the pull request summarizing what Hyrax found, with each finding citing the file and lines it refers to.
- A
Hyrax Reviewcheck run on the head commit, listed next to your CI, with findings annotated on the lines they apply to. It's a red ✗ when there's a must-fix finding, neutral when the only findings are "consider"-tier suggestions, and success when the PR is clean. A review that raised findings and then withheld them (because you answered them, or because an automated re-check found no supporting evidence) stays neutral rather than reporting success.
A review surfaces at most 7 findings per pass — the issues that matter, not a wall of comments.
Answering a finding
Every finding in the comment carries two checkboxes, under the file and line they refer to:
#### 1. Retry loop can spin forever on a poisoned message
📍 `src/queue.py:140`
- [ ] 👍 I fixed it
- [ ] 👎 Not an issue
Tick one and the finding leaves the active list and stops holding up the check run. They cost the same single click and differ only in what Hyrax records — which matters, because the two mean opposite things:
| You tick | Hyrax takes it as | What happens next |
|---|---|---|
| not an issue | a claim about the finding — we got it wrong | Hyrax stops raising that concern on this pull request, including if it re-appears at a nearby line with different wording |
| fixed it | a claim about the code — the problem is gone | Hyrax forgets the concern. If a later review still finds it, it comes back as an ordinary finding |
Nothing is required. Skip both and the finding simply stays open — it stays listed in the comment on every later push, and it stops holding the check run once a review no longer finds it in your latest commit. Tick both and Hyrax treats it as "fixed it" — the option that forgets rather than suppresses — because it will not guess which one you meant.
Three things worth knowing:
- "Not an issue" is durable and slightly fuzzy. It suppresses re-emission for the rest of the pull request, matched on the same file within roughly a hundred lines and similar wording — so a reworded re-mint of the same concern stays quiet.
- Both ticks are reversible. A ticked box stays rendered in the comment's Dismissed or Resolved list — struck through, still naming the finding and the line it was about — and un-ticking it there returns the finding to the active list on the next review.
- "Fixed it" is trusted, not verified. Hyrax does not re-check your fix. It just stops tracking the concern, and re-raises it only if a later review still finds the problem in the code.
When a review suppresses findings against an earlier "not an issue", the comment says so and points at the box to un-tick — it will not report "no issues found" on a push where it withheld something.
Must-fix vs consider, and gating merges
Each finding is tagged with one of two tiers:
| Tier | What it means |
|---|---|
| Must fix | A blocking-severity issue that should hold up a merge. It fails the check run (red ✗). |
| Consider | An advisory improvement worth a look, not a blocker. |
By default the check run is informational — the red ✗ appears, but Hyrax never overrides your merge policy.
The check reports on your latest commit. Hyrax remembers findings across pushes: a finding it raised earlier and hasn't re-found stays listed in the comment so you don't lose it, and the comment is the record. The check run is narrower on purpose — only findings the review made against the commit it just read decide whether it passes. So a must-fix you have since fixed stops blocking as soon as a review reads the fixed code, with no box to tick, and the check row says so: "No new issues at this commit — 2 earlier finding(s) still open (not blocking)". Those earlier findings still appear in the Checks UI, as notices rather than failures.
To make must-fix findings actually block, make Hyrax Review a required status check in your branch protection rules. Read the caveat below first — it changes which pull requests you can merge.
On some pull requests Hyrax doesn't review, no Hyrax Review check is posted at all — not a passing one. GitHub treats a required check that never reports as still pending and holds the merge indefinitely; there is no timeout.
The biggest case is now covered: when Hyrax picks a pull request up and finds no files it reviews, it posts a Not reviewed check with the skipped conclusion, which explicitly does not block. GitHub counts that as a pass, so those merges are no longer held. The same is true when your workspace can't run the review at all — its included credit is used up, or the workspace is inactive: Hyrax posts a Not reviewed check naming the situation (and, when credit runs out, comments once per billing period on the first affected pull request and emails the workspace owner), so the merge isn't held there either.
The permanently-pending state remains for the pull requests Hyrax never picks up in the first place — drafts, bot authors, forks, its own pull requests, and repositories where review is switched off — because nothing runs to report anything. It isn't limited to those, either: a review that runs but fails to post its check leaves the same state. Pushing a new commit re-runs the review and posts a fresh check, which is one way out of that one.
If you want must-fix findings to block merges, you have two ways to go:
- Leave the check optional and treat the red ✗ as the signal. Hyrax still reports must-fix findings on every pull request it reviews — you merge on judgment rather than enforcement.
- Make it required, and make sure someone can bypass branch protection for the pull requests Hyrax never picks up. GitHub can't scope a required check to only the pull requests that touch code — branch protection matches branch names, not file paths. You need this less often than you used to: a pull request Hyrax reviews-and-skips now reports for itself.
Know the other edge too, because it cuts the opposite way. When the reviewer itself reports that it stopped early — it ran out of room, or couldn't complete the analysis — the check concludes neutral, and GitHub counts neutral as a pass. (If it found a must-fix before stopping, that still fails the check.) The check's title says so either way: it reads Review incomplete (status: …) — findings may be partial when nothing was found before it stopped, and Hyrax found N issue(s) — review incomplete when findings did land — so a review that reports stopping early never presents as a finished one. Treat those findings as a partial read of the pull request rather than the whole of it. That mark is the reviewer's report about itself, and it is the only kind of incompleteness the title carries — it is not a guarantee that the whole pull request was read. The size limits below cut the pull request down before the reviewer sees it, and no title mark reports that.
Size limits are the quieter version of the same thing. Hyrax reviews at most 30 files per pull request, against a size-capped diff. A larger pull request is reviewed in part, and the check can still report success. So required-checking Hyrax Review raises the floor; it isn't a guarantee that every merged pull request was reviewed in full.
Carried-forward findings are the third version of it. A finding an earlier review raised, and the latest one didn't re-find, no longer fails the check — it is still listed in the comment, and you should still read it. So a green Hyrax Review means "nothing blocking in the code the last review read", not "the comment is empty".
One rolling summary
Hyrax updates one summary in place as you push, rather than stacking a new comment each time. Each pass reviews the full pull request as it stands, so your latest push is always what's reviewed.
The summary opens with the commit it read — Reviewed 4 file(s) at abc1234. A review takes a couple of minutes to start, so if the branch moves in that window the review reads a different commit from the one it was requested for, and the summary says so:
Head advanced mid-review: requested for
abc1234, diffed atdef5678— the findings above describe the newer commit. TheHyrax Reviewcheck sits onabc1234.
That wording is only used when the requested commit is genuinely an ancestor of the one reviewed — i.e. you pushed on top and the review read the newer code. Then it's good news about the findings and a caveat about the check: nothing above is stale, but the Hyrax Review check is attached to the earlier commit rather than your branch tip. If you've made the check required, your next push (or a re-request) puts one on the tip.
If Hyrax can't establish that relationship, the note is more cautious — Head changed mid-review — because the review's findings may then describe a tree that doesn't contain everything you asked about. A rebase or a force-push is the usual reason, but it isn't the only one: the commit you asked about may be unreachable from the shallow copy Hyrax cloned, or the ancestry check itself may not have completed. So read the cautious note as unverified rather than stale. It's worth a re-request when the branch really did move out from under the review; if the check simply couldn't answer, a re-request buys you a second review of code that was already current.
On a very large summary the note ships in a shortened form that carries the same two commits without the prose:
Head advanced mid-review: diffed
def5678, check onabc1234.
Both forms always contain the phrase Head advanced mid-review or Head changed mid-review, so that is the thing to look for.
Review is read-only — to turn feedback into a code change, run a fix, which opens a separate PR for you to review and merge.
What isn't reviewed
A few kinds of pull requests are skipped on purpose:
- Draft pull requests (automatic review only). Hyrax doesn't automatically review a PR you've marked as work-in-progress, so you can push to a draft as often as you like without triggering reviews. Marking a draft as ready does trigger a review — that's the point at which you're asking for one.
- Bot-authored pull requests (automatic review only). PRs opened by Dependabot, Renovate, and other automated accounts aren't reviewed automatically.
- Pull requests from forks (automatic review only). Only PRs from branches in the repository itself are reviewed.
- Hyrax's own pull requests (automatic review only) — fixes and published docs don't get re-reviewed by Hyrax.
- Pull requests with no changed files. An empty diff — usually a branch that already matches its base.
- Pull requests that change no code. Hyrax reviews source files in the languages it supports, plus HTML, CSS, SQL, and shell scripts. A PR touching only Markdown, JSON, YAML, Terraform, notebooks, or lockfiles has nothing to review. The same applies to a PR that only touches certain top-level directories —
vendor/,node_modules/,dist/,target/,.venv/,venv/,__pycache__/, and.next/— even when the files in them are ordinary source. (Top-level only: a nestedcrates/foo/target/is reviewed normally — and top-levelbuild/is reviewed too, since 2026-08-07.)
The ones marked automatic review only are skipped when Hyrax picks the pull request up itself; a review you start by hand isn't bound by them. The last two apply either way — there is nothing to review.
If a review doesn't appear on a PR, it's usually one of these. When Hyrax picked the pull request up automatically and found no code it reviews, you'll see a Not reviewed check explaining why. Everything else posts nothing: the skips above never start a review, an empty diff isn't something Hyrax can honestly explain (after a merge-commit merge the comparison collapses to nothing, so "no changes" and "already merged" look identical from inside the review), and a review you start by hand currently posts no check run at all — a known gap, not a verdict on your code. See the caveat under Must-fix vs consider if you've made that check required.
Availability
Available on every plan, and on by default for newly connected repositories. PR review needs the Hyrax GitHub App installed: posting comments and check runs requires write access, automatic reviews are triggered by the App's pull-request events, and starting a review by hand uses the App's access to list your open pull requests. On a public repo added by URL (no App), PR review isn't available — reviews don't trigger automatically, and a manual review can't be started. See Public & private repositories.