“a bunch of noobs using LLMs that they don't even understand”— the P5 Linux lead, on leaving the project
The backlash is real. But it's not the AI that's the problem — it's that nobody is checking the AI.
DevOpsDays Cairo 2026 · Final
The Self-Improving PR Review Agent
A PR-review agent that learns from your team, not just benchmarks — it rewrites its own prompts from what reviewers actually say, and it's honest about when it's unsure.
HGM · Huxley–Gödel Machine · ICLR 2026 oral
The bottleneck
AI writes code faster. Review didn't get faster.
The reviewer is the rate-limiting step in shipping AI-written code.
AI code is semantically plausible but behaviorally wrong — it compiles, it reads fine, it still ships a bug.
Architectural drift: each PR nudges the design; no one holds the whole.
What the bottleneck costs you
Review is a DORA problem.
↑
Lead Time for Change
review is the slowest step in the merge path
↑
Change Failure Rate
a review that misses the bug ships the bug
↑
Cognitive load
the most expensive resource, and the slowest
The idea
A reviewer that gets better with every review.
The agent reviews a PR → a human grades it in 30 seconds → the agent rewrites its own prompts from what the reviewer said.
The human is the reward signal. The tree remembers which review styles your team trusts.
Small, local — no cloud, no 400B model. ~3–4 min/review on one GPU, sized for an async review gate.
The reveal
Watch it work.
A PR with a planted bug — reviewed, then graded by a human in 30 seconds. That 30 seconds is the reward signal.
→ live demo · the review is pre-warmed; the rubric is the live moment · (fallback: replay)
Live demo
MergeFlow, on a real repository.
MohammadEmad2003/erp-shop — a shop ERP with seven real, unreviewed pull requests. A quick tour, then we review them live, in front of you.
It actually works
It changed — exactly as you asked.
Every human rubric produced a real, inspectable mutation to the prompt. The loop closes end-to-end — the human pilot scales the evidence.
“Caught the off-by-one slice; REQUEST_CHANGES is correct.”
↓ the prompt now says
“Check off-by-one errors in slice start/end indices, limit calculations, offset calculations… name it directly in the finding.”
“Flagged unsafe pickle deserialization; BLOCK is right.”
“Clean refactor; confident APPROVE is appropriate.”
↓ the prompt now says
“A clean, well-tested refactor with no confirmed defects should generally be approved… maximize signal quality, not the number of findings.”
It actually works — at scale
It holds up at scale — and on a dataset it never saw.
SWE-PRBench
350 real PRs · evolved on this data
Baseline vs. evolved prompt, same 350 PRs.
Qodo PR Review Bench
100 PRs · HOLD-OUT — never used in evolution
Hold-out set the prompt was never evolved on.
Baseline promptEvolved prompt (node 110434)
Same model (Qwen 27B), same harness — only the prompt changed. Scoring: identical match_findings (file + line-tol=10).
It actually works — with humans
Three reviewers. Ten PRs. The word “human,” made real.
Three independent expert reviewers — no notes shared, no consultation — each graded all 10 HGM reviews on the same 5-point rubric. 30 evaluations, every one logged.
Finding quality
High30%
Medium46.7%
Low16.7%
None6.7%
Finding validity
All valid43.3%
Mostly valid33.3%
Mixed10%
Hallucinated13.3%
Final action accuracy
Correct60%
Minor deviation16.7%
Incorrect23.3%
Missed a real defect?
No — caught all86.7%
Yes — missed13.3%
n = 30 evaluations · 3 independent reviewers × 10 PRs · 80% of reviewers rated their own confidence High. The misses are the training signal — that's what the loop eats.
Your question, answered
Claude is a great reviewer. It's also a static one.
A tool you call
stateless · one-shot inference
·f(prompt, diff) → review — a pure function
·No memory of your team, your standards, your bugs
·Same input → same output, forever
·Can't be wrong in a way it learns from
A system that learns
stateful · closed-loop
·State: a tree of prompt variants (Beta posteriors)
·Reward: your team's 30s rubric → utility
·Mutation: prompt-only self-improve
·Output changes over time — that's the difference
"Claude is a tool you use. This is a system that improves itself from your team's feedback."
The other question
Every famous tool is a stateless detector. Only this one is a stateful learner.
The question isn't "AI or not" — CodeRabbit, DeepSource and Copilot all call an LLM. The question is: does it maintain a state that improves from your team? None of them do. They compute a fixed function of your code and plateau.
Capability
SonarQube
CodeRabbit
CodeClimate
DeepSource
Copilot
Ours
Learns from your team's reviewers
✗
✗
✗
✗
✗
✓
Human-in-the-loop reward signal
✗
✗
✗
✗
✗
✓
Calibrated (penalized for overconfidence)
✗
✗
✗
✗
✗
✓
Auditable self-improvement
✗
✗
✗
✗
✗
✓
Local / data sovereignty
✓
✗
✗
✗
✗
✓
Static tools plateau. This is the only stage in the pipeline whose output changes over time — and compounds.
The engine, shown not explained
The loop under the hood.
PR diff → HGM tree selects variant · Thompson Sampling
An agent is an LLM + a harness. HGM is the loop that wraps it.
staticThe agent: a local LLM inside a harness — prompt, context, observe, reason, act, tools, memory. It reviews a PR. It does not get better on its own.HGMThe same agent, wrapped in the HGM loop: a prompt tree picks the variant, the human rubric is the reward, and self-improve rewrites the prompt. That's the part that learns.
White = the agent (any LLM + harness). Blue = HGM — the stateful, self-improving layer. Swap the LLM; keep the loop.
Three rubric taps → a scalar. signal = did it find real issues, action = was the approve/block call right, base = it produced a review at all. A missed bug subtracts. Three taps on purpose — cheap enough to grade every review, which is what lets the loop close.
Real code: feedback/__init__.py · compute_review_utility() — the same scalar that drives the tree.
Technical depth · 2 of 4
How it picks a reviewer.
Thompson SamplingExplore vs. exploit, per node
// per node, from its utility history
α = 1 + Σ utility
β = 1 + n − Σ utility
θ ~ Beta(α, β)
pick argmax(θ)
Each prompt variant is a Beta posterior — a running score of how much trust it earned. Sampling (not argmax of the mean) means a less-evaluated variant still gets a chance: that's the explore term. A proven variant keeps winning: that's exploit.
real tree · after 3 reviewsWhere the mass sits
v2-correctness · ★ best
α = 3.736 · β = 1.264
utilities [0.868, 1.0, 0.868]
mean = 0.912 · 3 evals
v0 / v1 / v3–v5 · unproven
α = 1.0 · β = 1.0
uniform prior — still eligible to be sampled
The tree is a tree, not a list: children inherit from the best parent, so improvement is a lineage, not a replacement. (v0–v2 share a base prompt today; the tree differentiates on mutation.)
At scale: 800 evals · 56 prompt variants — each eval = one real PR review.
Real code: demo_server.py · _ts_select() — replicates hgm.py:TS_sample().
Technical depth · 3 of 4
It's honest about when it's unsure.
the gateConfidence vs. a threshold that learns
confidence ≥ threshold
→ auto-accept
confidence < threshold
→ route to human
threshold₀ = 0.85(conservative)
annealingThe gate only relaxes on earned trust
every 50 human reviews:
threshold = max(0.60, P70(recent))
calibrationConfidence must track reality
// Expected Calibration Error
ECE = Σ (n_b / N)·|conf_b − util_b|
// real run · n=4
ECE = 0.1595
Overconfidence penalty
penalty = max(0, conf − utility)·0.2
sure-but-wrong scores lower than
uncertain-but-right. That's the honesty.
Real code: compute_annealed_threshold() + compute_hybrid_utility() — the gate and the penalty are both in the repo.
Technical depth · 4 of 4
How it rewrites itself.
the mutationPrompt-only, never the code
// input to the mutation call
current system prompt
+ agent's last review
+ human feedback
// output
a new system prompt
(code diffs rejected)
The model is asked to rewrite its own instructions to fix the exact weakness the human named. It can change how it thinks — never what it ships. reject_code_diffs=True.
the resultA new node, a logged lineage
v2-correctness → v3-improved
feedback: "caught the off-by-one"
prompt now says: "check off-by-one in slice start/end, limit, offset…"
audit trail
improvement_log.jsonl
parent, child, mode, problem, diff — every self-edit logged
Real code: demo_server.py · _real_self_improve() — a real, logged mutation, not a simulated one.
The whole story
Where it sits — and why it wins.
CI
build · tests
→
Static analysis
SonarQube · CodeClimate
→
AI review
this agent · learns from your team
→
Human gate
30s rubric · the reward
→
Merge
ship
↺ every review feeds the tree — the loop compounds
Lead Time for Change
↓
faster, more accurate review → less rework in the merge path