Open-source merge gateway · Apache-2.0

One decision per merge,
at swarm scale.

When most of your commits are written by agents, the merge queue is the bottleneck. mergeone replaces its one slow question with five fast, typed, calibrated ones per pull request, and turns them into a verdict through a policy file you own.

curl -fsSL https://mergeone.dev/install.sh | sh
Read the benchmark
30M / daydecisions on one 2-vCPU box, p99 441 ms, zero errors, re-proved by CI on every push
~350 msper pull request with a System One model, five questions in one call
$0.07 / 1kmeasured cost per thousand decisions at list price
0.96 AUC"does this PR weaken tests?" against a strong LLM judge, 1,200 Kubernetes PRs

Not a queue. A gate.

dec/s
The puck in the gate: the one decision being madeThree feed chutes: the agent swarmThree chutes feed one rotary gate. Each puck gets a single verdict: green rides the exit belt (main), amber is set on the side shelf (a human), red drops through the trap (blocked). The gate turns one third per puck however fast the chutes feed it; the dial reads decisions per second.
Hover the figure to change the arrival rate. The gate turns one third per puck however fast the chutes feed it.
PR state ──▶ decision model ──▶ calibrated probabilities ──▶ policy rules ──▶ verdict + route
             (Jev / Haiku)        is_logic_change      0.91     .mergeone.yaml     pass · hold · block
                                  weakens_tests        0.07                        auto-merge · human · domain-review
                                  message_matches_diff 0.88
                                  touches_concurrency  0.63
                                  needs_human_review   0.41
                                             └── every decision + its input → gatelog
Typed, not prose

The model returns probabilities, not a review comment. A rule like weakens_tests >= 0.6 → block is one line of YAML.

Calibrated before rules run

0.6 means sixty percent. Isotonic maps fitted on labelled history ship with the binary; raw ECE 0.17 becomes 0.03.

Fail closed, log everything

Model down? The PR holds for a human. Every verdict is stored with its exact input, because a System One model gives no rationale.

Landing plans, not serialisation

Hundreds of open agent PRs become waves of non-conflicting changes that land in parallel; one typed question catches semantic conflicts files cannot.

Built on a benchmark that says what does not work.

gatebench is pre-registered: hypotheses and thresholds were committed before any model ran, and results are published whichever way they fall. 40,000 Kubernetes merges, four systems, two runs.

Run 1 · negative result
Reverts cannot be predicted from a diff.

Rules, gradient boosting, Claude Haiku 5.5 and Jev all score PR-AUC ≈ 0.010 against a 0.0075 base rate. Pre-merge state does not contain that signal. Nobody else publishes this.

Run 2 · positive result
Typed triage is solvable, fast and cheap.

Behaviour change, weakened tests, concurrency risk and needs-human each reach ROC-AUC 0.87–0.96 with calibrated ECE under 0.05, in one request per PR. Jev meets the pre-registered bar on 5/5 questions at 347 ms and $0.074 per thousand.

questionJev AUCHaiku AUCJev ECE (cal.)Haiku ECE (cal.)
is_logic_change0.940.950.0300.027
weakens_tests0.960.960.0310.009
message_matches_diff0.800.780.0370.045
touches_concurrency0.950.960.0160.017
needs_human_review0.870.880.0470.041

What still fails: routing the top 25% to humans captures only 44% of the judge's "needs a human" PRs (bar was 70%). That number is on this page on purpose.

The agent asks before it merges.

mergeone is an MCP server. Register it once, add one line to your agent's instructions, and every merge goes through the gate instead of around it. The same calls exist over HTTP for everything else.

# register
claude mcp add mergeone -- mergeone mcp --policy .mergeone.yaml

# CLAUDE.md
Before merging, call gate_decide. Merge only on "pass".

# response
{ "verdict": "hold", "route": "human",
  "rule": "message-mismatch",
  "probs": { "message_matches_diff": 0.31, … } }