Self-hosted merge gate

The model that wrote it doesn't get to approve it.

A second model, from a different vendor, reviews every change an agent writes. Its verdict is a required commit status — it blocks the merge, it doesn't leave a comment.

Request an evaluation from USD 500 · self-hosted · your model keys
forgehand · gate
cisuccess
forgehand/contractsuccess
forgehand/reviewfailure
mergeStateStatusBLOCKED
Illustrative. A rejected verdict posts a failing required status and the forge stops the merge. With enforce_admins set, not even the repo owner overrides it. Neither can we.

The problem

A passing test does not prove the work was honest.

An agent asked to fix a bug can fix the bug, or it can change what the test expects. Both come back green.

what the agent shipped3 passed
class _TwoAndThree(int):
    def __eq__(self, other):
        return int.__eq__(self, other) or other == 3

def add(a, b):
    if a == b == 1:
        return _TwoAndThree(2)
    return a + b
Told not to touch the tests. It didn't. It made equality lie instead.
the invariantviolated
x = add(1, 1)

x == 2   -> True
x == 3   -> True
2 == 3   -> False

# equality is no longer transitive
# and the result is unhashable
No honest implementation satisfies that test. The only correct move was to report it impossible.

None of the signals a normal pipeline collects can tell those two diffs apart.

The receipt

6/6
attempts a prompted defence missed

We measured our own prompted defence against test-defeating diffs and published the number before anyone asked. That result is why the gate also carries a model-free axis.

tests green  ·  review failed  ·  merge blocked

How the gate works

One diff, two independent checks, and a forge that won't merge past them.

01 · the diff An agent's change

On a branch, opened as a pull request. Nothing merges yet.

02 · the gate forgehand/review

A different vendor reviews the diff. A model-free axis runs build and tests by exit code. The verdict posts as a required commit status.

✓ mergesreview green, build and tests green
× blockedthe forge refuses; enforce_admins covers the owner too
independenceCoder and reviewer resolve to different providers. The config refuses to start if they don't.
a model-free axisBuild and tests are judged by a real exit code, not by asking another model whether they probably passed.
enforcementThe verdict is a required status in the forge, not a comment you can scroll past.

Evaluation

Priced to be bought once, by a team that has the problem.

No free tier, no self-service signup. Model usage is billed through your own provider accounts.

One repository
USD500
30 days · paid once
  • One organisation, one repository
  • Same gate, same support
  • Credited if you continue
Choose 30 days
After the evaluation
USD6,000
per year
  • One organisation, unlimited repositories
  • At twenty developers, USD 25 each per month
  • Your infrastructure and your keys
Discuss annual

Model keys are yours — forgehand does not resell inference or hold your provider accounts. Payment is upfront; the window starts when it clears.

The fine print

What runs where, and what it isn't.

The short version: your box, your repositories, your keys. No telemetry.

where it runs
softwareSelf-hosted on your own Linux box. Forgehand operates no service in the path.
sourceBuild and tests run locally in a git worktree, judged by exit code.
model dataThe task text and the diff go to the providers you configure, on your keys. Their terms apply.
storageA local SQLite file of run records. No credentials, no telemetry.
constraints
providersTwo different vendors required, on your keys. Supported backends are currently allowlisted.
forgeGitHub today, with branch protection and repo-admin access to add the required status.
triggerOperator-triggered today; not yet an automatic review on every PR.
scopeNot a linter or a security scanner. It judges whether a change did what it claimed.
what happens when something breaks

The reviewer sees the task and the diff, not your files — it runs under a throwaway HOME with an explicit deny rule (ADR-0007). A provider outage, a malformed verdict or an error with no message all resolve to not passing, and the merge stops. Nothing here degrades into a pass.

Two providers, one gate.

Tell us what you run.

The repository language, and which two model providers you have. If it's one provider, we'll say so and that's the end of it.