Most AI review comments
should survive shouldn’t.
mergejury fans your pull request out to several AI reviewers, each with one lens: security, correctness, contracts, tests, performance. Then it makes every finding fight for its life. What survives gets posted: one review, a handful of comments, each one defensible.
$ mergejury review 4127 --dry-run
01 validate
No model involved. An anchor must land on a commentable line. Every cited line must exist. Deterministic, and merciless about invention.
02 cluster
Plain code groups findings that hit the same lines. Three reviewers flagging one comparison is agreement: a signal, not three comments.
03 challenge
A model that did not write the finding gets one instruction: argue that it is a false positive. Adversarial framing produces real dissent where peer review produces rubber stamps.
04 verify
Mechanical checks outrank every opinion in the pipeline. Claimed test gap? Look for the test. Claimed breaking change? Count the call sites. Lint-class complaint the linter doesn’t flag? Evidence against.
05 judge
One model, one cluster at a time, default verdict drop.
Publishing requires specific, anchored, and falsifiable from the code in front
of it. “This could be a problem” is a drop. What survives is
rewritten into one voice.
Twenty-seven walked in. Three walk out.
One review per run, never a notification storm. Comments are capped, severity-sorted, and anchored to lines the API will actually accept. Every one traces back through cluster, challenge, verification, and verdict to the reviewers that raised it.
The verdict is computed. No model ever states it.
A degraded run can request changes. It can never approve. That is not configurable.
One binary. Console included.
No runtime, no database to provision, no service to stand up. The reviewers are the CLIs you already have; everything else is compiled in.
no Go needed
$ curl -fsSL mergejury.etornam.dev/install | sh
Detects your platform, verifies the SHA-256 against the release
checksums, and installs to /usr/local/bin.
Override with PREFIX, pin with VERSION.
1.25 or newer
$ go install github.com/iamEtornam/mergejury/cmd/mergejury@latest
Builds from source at the latest release tag.
to hack on it
$ git clone https://github.com/iamEtornam/mergejury.git && cd mergejury && go build -o bin/mergejury ./cmd/mergejury
Windows: download the .zip from the releases page.
Then, in order
$ mergejury init
Finds the reviewers you already have, tells you what is missing and how to fix it, and writes a config wired to the tools on your machine. Nothing missing is fatal: it degrades to whatever is available, down to the API reviewer alone. Credentials stay in your environment, never in the file.
$ mergejury adapters check
Names every reviewer that is missing, unauthenticated, or running with flags this build does not expect, each with the exact fix. Start here; a run that fails at the adapter layer is the most confusing way to meet this tool.
$ mergejury review --local
Reviews your working tree against a base ref. No pull request, no posting, nothing leaves your machine except the diff you are reviewing.
$ mergejury review 4127 --dry-run
Renders the exact review it would post, comment for comment, and posts nothing. Read it before you let it near a real pull request.
$ mergejury serve
The operator console on localhost: every finding, every drop and its reason, every verdict, traceable end to end.
What it needs
git- on PATH. Worktrees and diffs go through the real binary, not a library.
ANTHROPIC_API_KEY- for the judge, the challenger, and the API reviewer.
GITHUB_TOKEN- only for posting, and only in the posting step. The GitHub API is
called straight from the binary, so there is no
ghCLI to install. Use a machine user or an App installation: GitHub rejects self-approval, and the reviewing identity should never be the authoring one. - Agent CLIs
- optional.
claude,cursor-agent,agy: whichever you configure. Configure none and the API reviewer runs alone.
Built to be operated,
not believed.
$ mergejury review --localreview the working tree before you push. No PR, no posting$ mergejury adapters checkwhich reviewer is broken, and the exact fix$ mergejury runs replay 7re-judge a stored run for cents; tune prompts against real findings$ mergejury statscost per published comment, per reviewer: the number that decides who stays$ mergejury servethe operator console: every drop, every verdict, traceable in under a minute
Session token compared with == instead of constant-time compare
expectedis[]byteandtokisstring, so this comparison is both type-confused and non-constant-time. An attacker who can measure response timing can recover the token byte by byte.Validateis reachable straight fromhandler.go:88with attacker-controlled input.