Pull request review
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 on by default for every repository you connect, and you can turn it off per repo in the repo's settings.
What you get
- A comment on the pull request summarizing what Hyrax found, with each finding citing the file and lines it refers to. The comment can also suggest how closely to review the pull request, with a risk score out of 10 and the main reason for it. That suggestion is advice only: it never merges anything and doesn't change the check run.
- 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 three 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
- [ ] ➡️ Real, but not this PR's
The third box is off by default and an operator turns it on per workspace, so your own comments may show two.
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 they mean different 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 |
| real, but not this PR's | a claim about scope — the finding is right, and this pull request is not where it gets fixed | Hyrax stops tracking the concern on this pull request and records that you judged it real, not wrong. Where your workspace has the issue tracker turned on, deferring can also open an issue for it — that part depends on how your workspace is set up, so open your own ticket if you need one for certain. If a later review still finds it, it comes back as an ordinary finding. It suppresses nothing, and it is never recorded as a mistake on our side |
Nothing is required. Skip all three 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 more than one and Hyrax records that you answered without recording which answer — it will not guess which you meant — and it re-draws every box ticked, because one "ambiguous" record cannot say which two you chose. To get back to a single answer, clear the boxes you did not mean in one go, before the next review runs. Clearing one and waiting does not work: two ticks are still ambiguous, so the next review re-draws all three.
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. It is the only box that suppresses anything — the other two stop tracking the concern and let a later review re-raise it.
- Every tick is reversible. A ticked box stays rendered in the comment's Dismissed, Resolved or Real — not this PR list — 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. The Resolved list may be collapsed, so a long-lived pull request keeps its open findings near the top: click its heading to open it.
- "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 on an earlier commit and hasn't re-found stays listed in the comment so you don't lose it, and the comment is the record. Up to 20 still-open earlier findings carry forward this way, must-fix ones first; past that the comment says how many older findings it no longer tracks. 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)". Tick it to close it: otherwise a fresh review of that same commit may count it again. 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. A pull request skipped by your repository's branch list reports for itself too, for the same reason.
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 raised on an earlier commit, which the latest review didn't re-find, no longer fails the check — unless you ask for a review of that same commit again, which can count a still-open finding in the comment as if it were fresh. 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 live summary
Each review posts a fresh summary at the bottom of the thread and folds the previous one into a short pointer, so the newest review is always the last Hyrax comment and your notifications fire when a review lands. The folded comment keeps one line saying what that review said — the commit it read, how many findings it had, and its merge recommendation when one was shown — so you can see what changed between pushes. Each pass reviews the full pull request as it stands, so your latest push is always what's reviewed.
Ticking a checkbox edits the live summary in place; it never posts a new one. Closing and reopening a pull request, or marking it ready for review, does not start a new review of a commit Hyrax has already reviewed. Asking with @hyrax-ai-dev review starts one even on the same commit.
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— this review describes 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: none of the findings are 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) — the pull requests Hyrax opens, such as fixes, don't get re-reviewed by Hyrax.
- Pull requests from branches you exclude (automatic review only). Under the repository's review settings you can list source-branch names, with
*and?wildcards —develop,release_*,release/*— and Hyrax skips any pull request opened from a matching branch. Typical use: a release or promotion pull request whose diff is your whole release, when the work in it normally arrives through its own pull requests. The list is empty by default, so nothing is skipped until you add to it, and the target branch is never consulted. On a skip, Hyrax posts aNot reviewedcheck, so a required check still passes. - 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__/,.next/, andresearch/— 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. Two of them say so on the pull request: when Hyrax picked it up automatically and found no code it reviews, and when it skipped a pull request from a branch on your repository's skip list, you'll see a Not reviewed check explaining why. When a review finds no code it reviews — whether it started automatically or you started it by hand — Hyrax usually also leaves a comment saying so. It won't if its earlier comment on that pull request carries findings or dismissals (that comment stays put), or if it can't read the pull request's existing comments to check. The rest post nothing: the other 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), reviews don't trigger automatically — there are no pull-request events to fire them, and nothing can post the comment or check run back to GitHub. You can still start a review for a specific pull request through the API and read its findings in Hyrax; the in-app trigger isn't available there, because it lists your open pull requests through the App. See Public & private repositories.