// blog

A policy gate for AI-authored PRs: when a single fail-on threshold stops being enough.

commitbrief guard evaluates a review against a declarative .commitbrief/policy.yml — per-severity budgets, an optional total, pass or block. And a consume mode that gates a review someone else already ran, with no second provider call.

·

--fail-on high is one number. It says: block if there’s anything at or above high. For a long time that was enough, because the volume of change flowing through review was human-paced and a single threshold matched how teams actually think about a gate.

The volume changed. When a meaningful share of your PRs are written by an agent, the shape of what you’re gating changes with it. You’re no longer asking “is there a blocker in this one careful diff?” You’re asking “did this machine-authored change stay within the budget I’m willing to accept across every severity?” A single threshold can’t express a budget. That’s the gap commitbrief guard fills, and it’s the last piece of this arc — the review as an MCP tool, as PR comments, and now as a hard gate.

A budget, not a threshold

commitbrief guard evaluates a review against a declarative policy file — .commitbrief/policy.yml — and exits non-zero if the review breaches it.

# .commitbrief/policy.yml
version: 1
thresholds:
  critical: 0    # zero tolerance
  high: 2        # at most two
  medium: 10     # a budget, not a wall
total: 25        # and no more than 25 findings overall
# Run a review and gate it against the policy.
commitbrief guard

This says something --fail-on can’t: zero criticals, at most two highs, up to ten mediums, twenty-five findings total. It’s a budget with per-severity lines, which is how you actually reason about acceptable risk in a high-throughput codebase — not “any high blocks” but “a couple of highs is the cost of moving fast; three is where I want a human to stop and look.” Unknown keys in the file are rejected rather than ignored, because a policy you thought you set but typo’d into oblivion is worse than no policy at all. A load or parse failure blocks the merge too — a gate that fails open is not a gate.

The gate evaluates the actionable set — the findings that remain after baseline and inline suppression have done their work. Things you’ve explicitly accepted don’t count against the budget, which is the only way a budget stays meaningful over the life of a real repo.

Decouple running the review from gating it

The part I’m most pleased with is that guard doesn’t have to run the review itself. It has a consume mode: hand it the JSON from a review that already happened, and it evaluates the policy with no provider call at all.

# Gate a review the MCP tool or a CI step already produced.
commitbrief --staged --json > review.json
commitbrief guard --from-json review.json

# Or straight off a pipe.
commitbrief --staged --json | commitbrief guard --from-json -

This matters because reviewing and gating are two different jobs that shouldn’t be welded together. Your agent runs the review once — through the MCP tool, or a CI step, or a developer’s terminal — and emits schema-v1 JSON. Then any number of gates can evaluate that same JSON against different policies: a lenient budget on a feature branch, a strict one on main, a zero-critical wall on a release branch. One review, many gates, one provider call. You’re not paying for inference again just to apply a different threshold.

When it blocks, --json tells you exactly why:

{
  "passed": false,
  "counts": { "critical": 0, "high": 3, "medium": 4 },
  "total": 7,
  "violations": ["high: 3 exceeds threshold 2"]
}

Machine-readable, so the CI step that blocked the merge can also comment which line of the budget was breached, not just that something was.

Why this belongs to you, not the platform

I could have shipped this as server-side branch protection — a bot that enforces the policy in GitHub’s settings. I didn’t, and it’s the same conviction that runs through everything else here: the gate should belong to the person the review is for. .commitbrief/policy.yml lives in your repo, version-controlled next to the code, reviewed in the same PRs, owned by the team. The policy is a file you can read, diff, and argue about in a pull request — not a setting buried in a platform dashboard that one admin controls and nobody else can see.

That’s the whole posture, stated one more time as this round closes. A review tool earns its place in a workflow by being something you own — your trigger, your provider, your rules, your budget — not something that happens to your repo. As more of the code arrives machine-written, that ownership stops being a preference and starts being the thing that keeps you in control of your own quality bar. The machine can write the diff and even run its own review. The budget it has to clear is still yours to set.

Related reading


← all posts