Blog

Guardrails for coding agents: never its own reviewer

Scale review depth by task type rather than by agent confidence. What belongs in the CI pipeline and what a human has to read.

A coding agent must not sign off its own work. Verification belongs in an authority the agent does not control: deterministic gates in CI, and a human who reads the whole diff whenever existing code is touched. How deeply something is checked is decided by the task type, not by the agent’s confidence score.

Robert Pupel set out three rules we hold to in AI writes the code. Who writes the architecture? This article describes the mechanism underneath: which gates sit in the pipeline, what triggers them, and where a human cannot be replaced. Guardrails for coding agents are not a process document but code in the repository.

Three sources arriving independently at the same conclusion

Research, consulting and practice arrived from different directions at the same rule in 2026: an agent must not be its own reviewer.

The Thoughtworks Technology Radar Vol. 34 of April 2026 lists “Putting coding agents on a leash” as one of four themes. Their reasoning: because agents deliver better results, humans increasingly step out of the loop, and teams therefore start investing in harnesses. Thoughtworks is a consultancy that sells AI transformation projects, and declares the Radar itself to be practitioner opinion rather than empirical work.

Octomind, a test tooling vendor, removed self-verification from its own agent in August 2026. The sentence from the release that names the problem precisely: “a model that wants to be done has a way to look done: advance the checklist, mark tasks complete, close the plan.” An external plan manager has owned progress since then, and the agent has no access to that tool. This is a vendor’s account of itself, but one with a mechanism you can follow.

The third source is the most interesting, because it is countable.

What 932,791 agent-generated pull requests show

Since February 2026 there has been a defensible evidence base for statements about coding agents. The AIDev dataset (Li, Zhang, Hassan, arXiv:2602.09185) collects 932,791 agent-generated pull requests from 116,211 repositories belonging to 72,189 developers, produced by five agents: OpenAI Codex, Devin, GitHub Copilot, Cursor and Claude Code. Open, academic, with no declared vendor funding.

Building on it, Ferdous, Banik, Chowdhury and Shamim compared 7,191 agent-generated against 1,402 human pull requests from Python repositories and detected breaking changes through AST analysis (arXiv:2603.27524, submitted 29 March 2026). The result is counter-intuitive:

ContextBreaking change rate
Greenfield, agents3.45 %
Greenfield, humans7.40 %
Agents on refactoring6.72 %
Agents on chore changes9.35 %

On a green field, then, agents break compatibility less often than humans. The moment they touch existing code, the picture inverts. Precisely the opposite of what most teams instinctively guard against.

The confidence trap: why the self-assessment fails as a filter

A high confidence score from the agent says nothing about whether the pull request stays compatible. The same work by Ferdous et al. names this the “confidence trap”: pull requests with a high self-reported confidence score contain breaking changes regardless. The authors derive from it, in so many words, the need for stricter checking on maintenance work, “regardless of reported confidence score”.

That is the practically most important number of the year, because it destroys a widespread short circuit. Hanging merge gates on a self-assessment has made the agent its own reviewer, just with more steps.

If you are about to let an agent loose on an existing Go backend and are not sure which gates need to be in place: that is a 30-minute conversation, not a project. We look at the pipeline you have and say what is missing.

Review depth by task type, not by confidence

What the data implies is a matrix with two lanes. It replaces the question “how confident is the agent?” with the question “what does this pull request touch?”.

Task typeEvidenced rateAutomated gatesHuman review
Greenfield, new files, no existing code touched3.45 %Build, tests, govulncheck, lint, coverage thresholdRead the interface and the data model, not every line
Refactoring of existing code6.72 %plus gorelease against the last tag, rendered manifest diffFull diff, second pair of eyes
Chore, dependencies, build, configuration9.35 %plus lockfile diff, image digest pinning, manifest diffFull diff, second pair of eyes
Processing of personal data touchednoneeverything aboveMandatory, whatever the task type

The last row is not a finding from the data but Swiss law. Art. 7 DPA requires data protection by design from the planning stage, and Art. 2 DPO names traceability as one of four protection goals. A merge nobody has signed off by name does not satisfy that. What it means for the architecture is in A revDSG-compliant AI architecture.

What the two lanes look like in a CI pipeline

Assignment to a lane has to be deterministic and out of the agent’s reach. It must not depend on how the agent titled its pull request.

no

yes / unknown

Agent PR

Existing code
touched?

Greenfield lane

Existing-code lane

Build, tests, govulncheck

Build, tests, govulncheck

gorelease, Helm diff, lockfile diff

Review: interface, data model

Review: whole diff, two pairs of eyes

Merge

The commit type under Conventional Commits is a usable hint but not evidence: the agent writes the title. The hard criterion comes from the diff itself. Deleted lines mean existing code was touched.

# .github/workflows/agent-gate.yml
name: agent-gate
on: pull_request

jobs:
  lane:
    runs-on: ubuntu-latest
    outputs:
      lane: ${{ steps.choose.outputs.lane }}
    steps:
      - uses: actions/checkout@v7
        with:
          fetch-depth: 0
      - id: choose
        env:
          # Never interpolate the title directly into `run`: script injection.
          TITLE: ${{ github.event.pull_request.title }}
          BASE: ${{ github.event.pull_request.base.sha }}
        run: |
          case "$TITLE" in
            feat:*|"feat("*) LANE=greenfield ;;
            *)               LANE=existing ;;
          esac
          CHANGED=$(git diff --numstat "$BASE"...HEAD | awk '$2 > 0' | wc -l)
          if [ "$CHANGED" -gt 0 ]; then LANE=existing; fi
          echo "lane=$LANE" >> "$GITHUB_OUTPUT"

Unknown lands in the strict lane. That is the whole trick: the default is strict, not lenient.

Two gates that actually bite in Go and Kubernetes work

The existing-code lane needs checks that make compatibility breaks mechanically visible rather than leaving them to a review.

In a Go module, gorelease from golang.org/x/exp/cmd/gorelease does that. It compares the public API of the checked-out state against a base version and exits non-zero on incompatible differences from major version 1 onwards. That makes the study’s AST finding exactly what the gate measures.

  api-contract:
    needs: lane
    if: needs.lane.outputs.lane == 'existing'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          fetch-depth: 0
      - uses: actions/setup-go@v7
        with:
          go-version-file: go.mod
      - run: go install golang.org/x/exp/cmd/gorelease@latest
      - run: gorelease -base=latest

On the Kubernetes side the equivalent is the rendered manifest diff. Do not compare the chart, compare the result: an agent that renames a value leaves a harmless line in the chart and a missing environment variable in the deployment.

# Renders base and PR state and compares the result, not the source.
helm template svc ./chart > /tmp/new.yaml
git worktree add /tmp/base "$BASE_SHA"
helm template svc /tmp/base/chart > /tmp/base.yaml
diff -u /tmp/base.yaml /tmp/new.yaml

What the pipeline cannot catch

Static analysis alone is not a security gate. Firouzi and Ghafari held 1,080 LLM-generated code samples against a human-validated reference (arXiv:2602.05868, 5 February 2026): only 65 % of Semgrep’s and 61 % of CodeQL’s findings matched the reference. In aggregate both tools looked plausible; per sample they diverged considerably.

The need is real. Peng, Wang and Zhu found across 3,700 snippets from the LLMSecEval benchmark that 68.8 % violated at least one security requirement, rising to 79.1 % for hard-coded credentials (arXiv:2607.12089). Ma et al. report average vulnerability rates above 56 % across eight models (arXiv:2607.23088, poster). The absolute figures are not comparable between these works; the direction is consistent across more than a dozen independent studies.

What measurably helps is downstream repair rather than better prompts: Sriram, Pradhan and Saha combined compiler diagnostics, CodeQL and symbolic execution and reduced CodeLlama 7B’s security defects in C code from 49 % to 19 % (arXiv:2607.21641). So a repair pass belongs in the pipeline; a free pass drawn from it does not.

Separate planning from execution

The plan has to exist before the code and be signed off by a human. Boris Tane describes this as the most-shared working pattern there is: “The separation of planning and execution is the single most important thing I do”, and following from it, “never let Claude write code until you’ve reviewed and approved a written plan” (boristane.com, February 2026).

That is the interface between the agent and your team. An approved plan can be checked; a finished 2,000-line diff cannot. Where the plan contains an architecture decision it belongs in the repository anyway, see Decisions you can still understand in two years.

A word on context files, because a lot of effort drains away here: Gloaguen, Mündler, Müller, Raychev and Vechev of ETH Zurich evaluated AGENTS.md files systematically (arXiv:2602.11988, revised 23 June 2026). Finding: context files do not generally improve the success rate, and they raise inference costs by more than 20 %. Instructions are followed; repository overviews buy nothing. So write conventions and pitfalls into them, not directory trees.

What we advise against

Do not build a merge gate that only knows true or false. A single green tick across all task types is either too expensive for greenfield work or too cheap for maintenance, and usually both.

Do not use a second agent as the sole reviewer. A review agent is useful for structuring a diff and flagging candidates. It is not a verifier, because it shares failure classes with the agent it is checking, and because the chain then ends in a self-report again.

And the honest trade-off: the lenient greenfield lane lets errors through. The 3.45 % is better than the human figure, but it is not zero. Adopting this grading is a deliberate decision to move review effort where it statistically buys more. For a team of two with a prototype the whole apparatus is not worth it. For a product with external API consumers and a cluster in production it is.

Frequently asked

Why should agents be checked more strictly on maintenance than on greenfield work?

Because that is what the data shows. In the comparative study by Ferdous et al. across 7,191 agent-generated pull requests, the breaking change rate was 3.45 % on greenfield work, 6.72 % on refactoring and 9.35 % on chore changes. Maintenance presupposes knowledge of existing contracts, which is often only partially present in the context window. Greenfield work defines the contracts itself.

Can I use the agent’s confidence score as a merge criterion?

No. The same study describes a “confidence trap”: pull requests with a high self-reported confidence score contain breaking changes regardless. The score is a self-report from the system whose work is meant to be checked. Use criteria the agent does not influence instead: was existing code changed, does the public API break, does the rendered manifest change.

Is a security scanner in the pipeline enough as a gate?

Not as the only gate. Firouzi and Ghafari found across 1,080 validated samples that only 65 % of Semgrep’s and 61 % of CodeQL’s findings matched the human-validated reference. Scanners belong in the pipeline and their findings are hints. More effective is a downstream repair pass that combines compiler diagnostics with static analysis and re-checks the result.

How do I classify pull requests when the agent writes the title?

By the diff, not the title. A pull request that deletes lines has touched existing code and belongs in the strict lane. git diff --numstat gives you that in one line. The commit type under Conventional Commits remains a useful hint for humans but does not work as a gate, because the subject of the check sets it.


A walk through your pipeline, not through your strategy. Thirty minutes with one of our Go engineers: which gates you have today, which task types currently run through unchecked, and how much of that can be retrofitted in a week. No sales pitch.

Book a slot · Get in touch · How we build AI systems and agent infrastructure is under Artificial Intelligence & Machine Learning.

A conversation, not a newsletter

Let's talk about your system

If this article describes something you recognise, a conversation is the shortest route to an answer.

Let's talk