AI Software Engineering Engineering LLM

Agents Checking Agents: How We Let AI Review and Merge Routine Code

William R. Kassebaum, PE

Agents Checking Agents: How We Let AI Review and Merge Routine Code

William R. Kassebaum, PE | October 2026

Coding agents now write most of our pull requests. That part was easy. The hard part was everything after: someone still had to read each change, decide if it was safe, and merge it. If that someone is always a person, the agents just move the bottleneck to an inbox.

So we built a setup where agents check each other’s work. Claude Code, Grok-based agents and Cursor agents write code, a different agent reviews it, and a small piece of automation we call the merge gate decides whether the change has earned a merge. Low- and medium-risk changes are reviewed and merged by agents. By rule, a person merges the highest-risk changes. Deploys stay human-authorized, with one product where the owner gave a standing go to deploy on merge.

Over ten days in October 2026, 136 pull requests went through this process and merged across four repositories. Nearly every one carries a written review verdict. We don’t have a time-saved figure and won’t pretend to. What we can say is that independent review has caught real defects the author missed.

The Flow, From Pull Request to Deploy

Flow from pull request to deploy. A coding agent opens a PR with evidence. CI computes the risk tier. A different agent reviews and posts a verdict. The merge gate then does one of three things: an open decision or disagreement goes to a human, who sends it back to the gate; a green low or medium tier is merged by an agent; a green highest tier is merged by a person. Both merge paths lead to deploy, which is a human call except one standing go.

  1. Write. A coding agent opens a pull request. Most come from Claude Code; a Grok Bot engineering agent, Grok CLI and Cursor cloud agents write some too. The description carries the builder’s evidence and a Decision needed: line.
  2. Tier. A CI job computes the risk tier from the diff. More on that below.
  3. Review. A different agent reviews the change and ends with a short machine-readable block: verdict, reviewer, commit, and review depth.
  4. Gate. The merge gate turns green only when there are enough counting verdicts for the tier, every Decision needed: line reads none, no escalation is open, and the PR isn’t a draft.
  5. Merge. Only the commit that was reviewed gets merged. Merging and deploying are separate decisions for us.

Quality Gates: Tests and CI Come First

A review verdict is never the only thing between a change and the main branch. There are two layers. The merge gate is one required status, and it decides “enough independent reviews, no open decision.” The repository’s own CI jobs are separate required checks, and they decide “the code passes.”

What CI runs depends on the repository:

  • A TypeScript product: format check, lint, strict typecheck, tests in every package, then build, in that order. A timeout makes a hung test go red instead of hanging forever.
  • A Python product: formatter and linter checks, the unit suite, and database suites run against a throwaway PostgreSQL on the same major version as production.
  • The agent-ops repo: its own unit suite and consistency checks, plus a separate lint, typecheck and test job for each Worker.

Our standing rules for every coding agent:

  • Use the repo’s real gates. The agent first lists what the project actually runs, with CI as the source of truth. If a doc promises a check CI doesn’t enforce, we say so.
  • Never skip to get green. No commenting out tests, soft-failing a step or lowering a threshold. An infrastructure red is still red: when a database image pull hit a registry rate limit, the fix was to use the database already on the CI runner, not to skip those tests.
  • Evidence for the exact commit. The builder records CI green on the final commit, tests against real functions and a real database, tenant and role tests, and mutation checks that name which test went red when the code was broken on purpose.

A CI change that adds or removes which tests run is raised to the highest tier automatically, so nobody can quietly shrink the suite to make a change pass.

What’s not there yet:

  • No security scanning runs in CI yet. Some checks run locally before a commit, and wiring scanning into CI is on our list but not scheduled.
  • Not every repository has test CI yet, and a few older suites are excluded on purpose with a written reason.
  • Pre-deploy and post-deploy checks are a written procedure the deployer follows, not automation.

What Makes a Verdict Count

Every agent has its own identity. Each one signs in to GitHub as its own app, with its own keys. A verdict counts only when it is posted by the identity that a trusted list names for that reviewer. The gate reads that list from the base branch or from a pinned copy, never from the pull request being judged, so a PR can’t add itself a friendly reviewer.

The author doesn’t get a vote, except to stop. An author’s own “merge” verdict is ignored. Its “do not merge” still blocks. Any other reviewer’s latest verdict that isn’t “merge” also blocks.

Two verdicts from one identity count as one. Today the gate requires a different agent identity, not a different vendor or model. In practice, Claude-written changes are usually reviewed by Grok-based agents and the other way round, but the gate doesn’t enforce that yet.

Built but not live yet: a cross-model review panel. We’ve written and merged a review service that runs as a Cloudflare Worker. On each new commit it will pick two reviewer pairs, each a model plus a harness, that avoid the author’s pair, and start read-only reviews from the base commit so the author’s edits can’t steer them. It is not receiving events yet. When switched on, it runs in shadow mode: its verdicts are labeled “not counted,” and a test proves the gate ignores them. Counting them is planned, not running.

How Risk Tiers Are Decided

Each repository has a risk map with path patterns and content rules. The tier of a change is the highest tier any changed file reaches, and a file no rule covers defaults to medium.

TierExampleMerged by
T0Docs onlyAgent
T1Read-only UIAgent
T2Server codeAgent
T3Money, authPerson

What each tier covers, and what it needs to pass:

  • T0: docs, changelog and version bumps. One “merge” verdict.
  • T1: UI or tests that trigger no writes. One “merge” verdict.
  • T2: server reads and reports, writes to our own tables, CI and hook files, and dependency changes. One verdict at the deeper “blast-radius” level, meaning the reviewer looked at what else the change could affect.
  • T3: money, any write to an external system of record (accounting, a ledger, the CRM), UI that triggers such a write, migrations, auth, tenant scoping, and CI changes that alter which tests run. Two independent reviewers at blast-radius depth on the exact commit, required CI green, and no open “do not merge.” Then, by rule, a person merges.

Rules that keep the tier honest:

  • The gate computes the tier from both the base branch’s map and the PR’s own map and takes the higher. Renamed files count under their old path too.
  • A label can raise a tier, never lower it. A missing tier counts as the highest.

Hands-Off, Without Polling

Agents shouldn’t sit in a loop refreshing GitHub. A workflow wakes the engineering agent when another agent opens a PR it should review, when someone mentions it, or when a comment lands on its own PR. The wake carries links only, never comment text, and an agent never wakes itself. Each agent also starts every session with a read-only list of what is waiting on it.

A separate wake relay, a live Cloudflare Worker, wakes a bookkeeping agent when someone posts in a team chat group. Our Workers primer covers the platform.

What We Don’t Automate

  • Highest-risk merges. By rule, a person merges T3. We’re adding a guard to the gate so that rule is enforced, not just followed.
  • Pivotal decisions. On money, auth, tenant scope, a tier change, or anything hard to undo, the agent doesn’t decide. It writes a short numbered list on the PR, and the merge stays blocked until a person replies with a DECISION: comment.
  • Stuck disagreements. If builder and reviewer still disagree after two rounds, it goes to a person the same way.
  • Dependency changes. These always go to a human.
  • Deploys. Outside the one product with a standing go, every deploy and release is a person’s call. Deploys that carry migrations stay with a person even in our long-term plan.
  • The engineering agent’s own reach. It reviews and builds. It never merges, approves or deploys.

Our written long-term goal is to earn more automation one tier at a time from measured runs of clean pull requests, and to drop a tier back the moment a merged change causes a defect. That is policy on paper, not live.

Escalations come to me today, and the same process extends to a group of human collaborators.

Guardrails We Rely On

  • Trusted gate code. The gate runs from a trusted copy pinned to a tag or commit, never from a branch, and never from the PR it is judging.
  • Short-lived, scoped credentials. Agent keys become short-lived, scoped tokens, stay out of logs, and have a written leak runbook.
  • Fail closed. The review Worker is built to fail a run and open an alert if anything unexpected changes during a review.
  • An audit trail by default. Everything happens as GitHub comments, reviews and checks under each agent’s own identity, and settled choices go in a one-line decision log.
  • Off switches. Both Workers have a written way to switch them off and roll back. Our written deploy procedure tags the running version first, so the deployer can roll back if a post-deploy check fails.

Tool Trust: An Answer Isn’t Proof

Every agent in our fleet follows one rule: a tool that answered isn’t proof it’s right.

  • Before acting on or reporting a result, re-check any answer that’s empty, errored, suspiciously round, stale, or doesn’t match what was asked (wrong entity, date, amount, number or recipient).
  • After any write, read it back.
  • If it still doesn’t tie out, stop and say “unverified.” Don’t retry blindly or guess.
  • “Verified” means two independent sources agree, or a read-back confirmed it.
  • An empty or errored reply means “couldn’t check,” never “nothing there.”

Our review setup follows the same idea. A verdict is tied to the exact commit it judged, review and CI are separate required checks, and at the highest tier the reviewer must re-run the author’s mutation checks rather than trust the author’s table.

Lessons a Peer Could Reuse

  1. Give every agent its own identity. If all your agents act as you, you can’t count “a second opinion.”
  2. Let the tier come from the diff, not the author. Never let a PR lower its own risk.
  3. Pin approval to a commit. A review of yesterday’s code is not a review of today’s.
  4. Put tests ahead of opinions. Make CI a separate required check, so no verdict can stand in for passing tests.
  5. Ask humans short questions. A numbered list answered with one reply gets decided. A long thread doesn’t.
  6. Run new reviewers in shadow first. Our cross-model panel won’t count until it has shown its work.
  7. Design for free-tier limits. Both our Workers fit Cloudflare’s Workers Free plan, and its KV limits shaped the code.

Where This Leaves Us

Agent review hasn’t replaced engineering judgment here. It has moved it. People decide the rules, the hard calls, the highest-risk merges and the deploys. Agents handle the volume in between and check each other while they do.

If you’re working out how to use coding agents without giving up control of what ships, we’re glad to compare notes. Get in touch.

References

WRK

William R. Kassebaum, PE

Licensed Professional Engineer at Kassebaum Engineering LLC, specializing in systems engineering, embedded development, and AI integration.