I run two AI models on every pull request, and neither sees the other’s review. The most useful catches come from the places where they don’t agree with me or with each other.

A few weeks ago, a volunteer submitted a small pull request to one of my community projects. It changed how date fields get saved. The AI reviewer flagged a problem: native date pickers fire change events when you clear them, and the new code silently swallowed those events. Clearing a date would look like it worked, but nothing would happen.

The volunteer merged it anyway. The repo didn’t have branch protection turned on, so nothing stopped them. A few days later I confirmed the bug and opened a follow-up PR to fix it. The reviewer had been right the whole time.

How it works

Every pull request across my 28 repos triggers two AI reviews in parallel, as GitHub Actions.

  • OpenAI Codex reviews for logic bugs: off-by-one errors, silently swallowed errors, missing transaction boundaries, data-correctness problems.
  • Claude reviews for security: auth gaps, exposed secrets, injection, input validation, debug endpoints left active.

Both have to pass before I can merge. If either one flags something at or above the severity threshold, the PR is blocked.

I use two models because they have different blind spots. Neither catches everything. And the things only one of them catches tend to be the most interesting.

The setup is one YAML file copied into each repo, two API keys stored as secrets, and branch protection requiring both checks to pass. A couple cents per PR. Under ten minutes.

What it catches

Before launching a volunteer management platform, I ran both models over the full codebase as a deliberate security audit. The platform handles real member data for a community that’s been running for over 30 years.

Together they found ten problems. Some endpoints were open to any signed-in user instead of being locked to the right roles. Personal data was visible to the wrong access tier. Mutations had no CSRF validation, and sensitive actions had no audit logging. These were P0 and P1 access control issues, caught before the app went live with real data. Neither model would have found all ten on its own.

It isn’t perfect. On a redesign of this site, the OpenAI reviewer flagged a bunch of elements as never becoming visible to the user. It was wrong. An IntersectionObserver in a separate file handled that, and the model couldn’t see across files. I had to bypass the check to merge.

I’ll take the occasional false alarm over missing a real one.

The same idea, outside of code

Before I published a blog post arguing that progressives need to stop sitting out the AI conversation, I was nervous about the framing. A consultant telling his own industry to change is a good way to lose clients.

So I ran a two-agent debate. One Claude instance argued for publishing the post as written. The other had one job: find reasons it could backfire.

It found three. The post read like a consultant criticizing the people he works for. A claim about workforce displacement didn’t have strong enough causal grounding. And the newsletter signup at the bottom made the whole thing feel like a sales funnel.

I rewrote it with a new title, a new tone and a restructured argument, and moved the signup out of the body. The version that went live was a different post from the one I almost published.

If you want to try this

Create a GitHub Actions workflow with two parallel jobs. One calls OpenAI’s API with a code review prompt, and the other calls Anthropic’s. Each returns a pass or fail. Branch protection on main requires both to pass. That’s the whole system.

You don’t have to build it from scratch. Describe it to Claude, ChatGPT or whatever you use, and have it write the workflow YAML and the review prompts. I used Claude Code to build the system that reviews the code Claude Code writes. It’s recursive, and it works.

The specific tools matter less than the pattern: two reviewers, blind to each other, looking for different things.