Skip to main content

mergeproof: proof before merge

Proof before merge. Pull requests earn their merge with evidence, not claims.

CI PyPI Python versions GitHub Marketplace MIT license

Documentation · Quickstart · Checks · Examples · Changelog


A pull request says "added tests, verified on staging". That costs nothing to type. mergeproof turns it into something CI can check: one YAML file in the repository says what a change must prove before it merges, the action checks the proof on every push, and the same file tells coding agents what to produce before they open the PR.

The mergeproof comment on a pull request: one pill per rule, the one requirement still missing with what to do, and the satisfied ones underneath

A real comment. One pill per rule, then only what blocks the merge and what to do about it; the rest is the receipt.

How it works

One policy file. Contributors and agents read it before pushing; the action enforces it against the diff, CI runs, evidence block and reviews; the pull request gets a scorecard comment, the mergeproof commit status and review comments on the files.

  • One policy file. A rule pairs a when (paths, labels, title, base branch) with what it requires: checks with parameters. Nothing to script.
  • Evidence, not attestation. Tests must be in the diff. Jobs must be green on the head commit. Links must resolve at their source. Sign-off is a human approval bound to the commit; a new push invalidates it.
  • One required status. Rulesets require mergeproof; the policy decides what stands behind it, CI jobs included. When no rule applies, nothing is posted and nothing blocks.
  • Agents read the same file. They learn what to prove and check their own work before opening the PR. They cannot approve anything.

Quickstart

1. Write the policy. mergeproof init writes a starter; this is the shape:

# mergeproof.yaml
version: 1
rules:
  - id: source-needs-tests
    description: Source changes ship with tests for the touched module.
    when:
      paths: ["src/**/*.py"]
    require:
      - check: tests.changed
        with: { map: { "src/{pkg}/{name}.py": "tests/**/test_{name}*.py" } }
      - check: ci.job_passed
        with: { name: "^unit", regex: true }

  - id: fix-needs-live-evidence
    description: Bug fixes show the behaviour before and after on staging.
    when:
      title: "^fix"
    require:
      - check: evidence.links
        with: { key: traces, min_pairs: 1, verify: http }
      - check: review.human_verified
        with: { accept_approval: true }

2. Add the workflow. Full version with comments: examples/github-workflow.yml.

# .github/workflows/mergeproof.yml
on:
  pull_request:
    types: [opened, synchronize, reopened, edited, labeled, unlabeled]
  issue_comment: { types: [created, edited] }
  check_suite:   { types: [completed] }
jobs:
  gate:
    if: github.event_name != 'issue_comment' || github.event.issue.pull_request
    runs-on: ubuntu-latest
    permissions: { contents: read, pull-requests: write, statuses: write, checks: read }
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.repository.default_branch }}   # policy from the base branch
      - uses: Aryamanz29/mergeproof@v1
        env:
          MERGEPROOF_PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}

3. Require the mergeproof status on your default branch. Until you do, the gate only reports, which is the right way to roll it out.

Before you push

mergeproof explain runs the policy against the working tree and prints what is still missing, in the same words the PR comment will use. Agents run it in their loop; people run it before opening the PR.

mergeproof explain in a terminal: the rule that applies, the requirement that is missing, and the fix

pip install mergeproof            # or: uv tool install mergeproof, uvx mergeproof
mergeproof explain                # what this diff must prove
mergeproof template               # the evidence block still missing, ready to paste
mergeproof agent-prompt >> AGENTS.md

What it can check

check proves
tests.changed changed source files come with changed tests, mapped by {capture} globs; existing_only skips modules that have no test file yet
ci.job_passed a named check run succeeded on the head commit (newest run per name; superseded runs are ignored)
evidence.artifacts links in the evidence block by kind: before/after pair, one single, or a set; verified at their source by a pluggable verifier
evidence.links the pair kind under its own name: before/after link pairs
evidence.field a key in the evidence block exists and has an acceptable value
review.human_verified a reviewer other than the author approved the head commit, or posted /verified <sha>
agent.verdict an allowed automated reviewer posted a head-bound verdict block
files.changed the change touches, or avoids, certain paths
pr.labels, pr.body labels present or absent; description sections, regex, length
shell a command from the policy exits 0

Parameters for each: mergeproof checks, or the checks reference. Anything vendor-specific is a plugin: the Langfuse and Braintrust verifiers are a dozen lines each.

Evidence

What the contributor supplies goes in the PR description as a fenced block that agents can write and machines can read. mergeproof template prints the one a change still needs.

```evidence
environment: staging
traces:
  - what: search with an empty query
    before: https://www.braintrust.dev/app/acme/p/service/logs?r=b6f98332e178f658
    after:  https://www.braintrust.dev/app/acme/p/service/logs?r=db0100b2192984af
```

Everything else is found in the pull request itself: the diff, the check runs, the reviews.

Where it reports

channel what
comment the scorecard above, one per PR, updated in place
commit status mergeproof 4 of 5 requirements satisfied, 1 missing in the merge box; the context to require
review comments each open requirement on the file it concerns, updated as the PR changes, removed once satisfied
job annotations the same findings on the workflow run and in the diff
JUnit and reviewdog files for renderers you already use
receipt on merge, the final report is committed to a mergeproof-receipts branch; mergeproof receipt <sha> answers "what proved this change?" months later

Run without installing

uvx mergeproof explain
docker run --rm -v "$PWD":/repo ghcr.io/aryamanz29/mergeproof check --local

Images are tagged X.Y.Z, X.Y, X and latest per release, edge for main.

Documentation

aryamanz29.github.io/mergeproof

Getting started install, the three-step setup, what a pull request sees
Guides writing a policy, evidence, GitHub setup, coding agents, rolling out without blocking anyone, the examples
Reference every check and parameter, the command line, the action's inputs and outputs
Extending checks and verifiers as plugins
Project contributing, releasing, FAQ

How it compares

Danger runs rules written in JavaScript and comments on the PR. policy-bot enforces approval policies from GitHub-native data. Checklist actions fail on unticked boxes. Hosted evidence gates evaluate your artifacts on their servers. mergeproof is declarative, has a notion of evidence that can be verified at its source, explains itself to agents, and runs entirely in your CI.

Contributing

make setup, then make lint typecheck test. Pull requests here are gated by this repository's own mergeproof.yaml. See CONTRIBUTING.md. MIT licensed.

Metadata

Release files for mergeproof 1.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mergeproof 1.0.2
File Size Uploaded
mergeproof-1.0.2.tar.gz 521.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mergeproof 1.0.2
File Interpreter ABI Platform
mergeproof-1.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 597.3 kB

Release files / mergeproof-1.0.2.tar.gz

Download URL mergeproof-1.0.2.tar.gz
Size 521.4 kB
Tags Source
SHA-256 checksum
How to use checksums
95122ada91c6958b02b364c6c369559a47b57d64743a2d596fc86589cbfd89cc
BLAKE2b-256 checksum
How to use checksums
9c9be349e9420bb60028178adfc00f5f4da562acc97d791d662a570c2f448bc8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release files / mergeproof-1.0.2-py3-none-any.whl

Download URL mergeproof-1.0.2-py3-none-any.whl
Size 75.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8b1555690df2f8ab4d26cf6699af8b7a5e985916e03069ddc0867bf95ef0c406
BLAKE2b-256 checksum
How to use checksums
cd22722ca7e0871183cbcf0be529b3ee4d764d6755b4d02a1c0df327d56f247b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.2 This release

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page