Reviewer-gates: Trading speed for correctness with Claude

Reviewer-gates: Trading speed for correctness with Claude

How I use reviewer-gates to make Claude’s output meet my code standards: open-source PRs, a demo, and the real cost in time

Does this sound familiar? That’s what coding with AI looks like when you actually care about the code it produces:

Claude conversation

Working with an AI agent can feel like working with a junior who ships as fast as possible without caring whether the code is good. While a junior improves over time, an agent can ignore the same instruction ten times in the same conversation.

The usual move is to write these rules into CLAUDE.md or a skill. It isn’t enough; those are suggestions the model is free to ignore, not gates.

So I stopped repeating myself and found a way to enforce the rules instead. I call these “reviewer-gates”: strict checks that block the agent from marking work as complete until they pass. When I catch a new offending pattern, I don’t argue with the agent. I add a rule, and it never gets through again.

By now I have 50+ PRs built this way where I’m very satisfied with the result.

The workflow

My goal was to turn a request into a spec, hand it to a developer, and refuse to call the work “done” until a set of reviewers pass.

Workflow flowchart

A reviewer file covers one area and holds many rules (coding patterns, frontend, database, etc). A new file adds an area/reviewer. A new rule is usually a new section in an existing file.

Each reviewer runs as its own agent. A dedicated reviewer with a single job beats asking the developer agent to review its own work. It brings fresh context, an adversarial stance, and no incentive to defend code it just wrote.

The way I run it is by describing what I want to a Claude Code session that can read my code, so the spec is grounded in what’s actually there. Then Orca (a headless plan-code-review CLI) runs the developer-and-reviewers loop. It does exactly this out of the box, with reviewers as plain Markdown files. Its flows are written in Scala, so it drops cleanly into my stack (Orca itself is language-agnostic, and the reviewers are just rules).

What a rule looks like

Take the enum complaint from the top. Instead of repeating it, I wrote a reviewer for it once:

---
description: Domain values that are one of a fixed set are typed enums, not bare `String`s
files: server/src/main/scala/net/wiringbits/.+\.scala
---

A domain value whose set of valid cases is fixed and known (status, kind, role,
mode, type) should be a typed enum. The compiler then rejects invalid values and
keeps exhaustive matches honest.

**Flag** a new `String` field, parameter, or return type in the domain model whose
value is really one of such a closed set, and a place that matches on its contents
with string literals instead of enum cases.

Not: free-form text (names, descriptions, messages), or identifiers that happen to
be strings (ids, keys, tokens).

Now the gate catches it before I ever open the PR, and further down I’ll show how to derive rules like this from your own PR history.

How I organize and run them

Each reviewer is one Markdown file under .orca/reviewers, scoped by its files pattern so it only runs on the changes it cares about. Adding a rule means dropping in another file, nothing else.

I don’t run Orca by hand either. A small script, claude/implement.sc, drives the loop, and I let a Claude Code session dispatch it. In practice I describe the feature to Claude, and Claude kicks off the developer-and-reviewers run for me.

The catch is speed

Every PR now takes 30 to 120 minutes. That annoyed me at first, until I changed how I work around it:

  • I dispatch several features concurrently instead of babysitting one.
  • Those minutes are better spent elsewhere than reviewing code I’d reject anyway (which can be exhausting).

It’s a real trade, so it’s worth being honest about when it pays off. Reviewer-gates earn their cost on a long-lived codebase where you keep re-asserting the same opinions. For a throwaway prototype or a small bugfix, I skip them (the overhead isn’t worth it).

Ideas to optimize the speed are welcome

See it in action

Here is the whole loop running on real work. I ship two features this way, and in the second I hit a couple of new offending patterns and encode them into new reviewer rules on the spot.

Remember I said this takes a while? I skipped the wait times in the video.

The resulting PRs:

  • Feature 1: #48
  • Feature 2: #49
  • Workflow improvement, not in the video: #50

Bootstrap reviewers from your PR history

You don’t have to write every reviewer by hand. If your repo already has a solid history of human review comments, this prompt points an agent at it, mines the conventions your reviewers actually enforced, and writes a starting set of reviewer files. It takes a few minutes, and the patterns are useful even if you don’t adopt the whole approach.

A note on where these came from. The reviewer files linked in this post weren’t generated. That project has no team or PR history to mine, so I added each rule by hand the first time a Claude PR committed the offense. The prompt below instead reads a repo’s existing PR review history and drafts reviewer rules from the feedback that keeps recurring. I built it with Claude and tuned it against repos I own that do have real reviews.

Show the prompt

Conclusion

These reviewer-gates turn “please stop doing that” into a rule the agent can’t talk its way past. It’s the same loop you’d run with a junior, except the feedback sticks the first time, because it’s code, not conversation.

The price is speed, and I pay it gladly. My attention moves off spotting the same silly issues and onto the work that actually needs a human.

Found a mistake or want to suggest an edit? View the source of this post on GitHub .