DEV Community

Cover image for Prevention, Not Recovery: What I learned building a tool to restrain AI coding agents
Ian Smith
Ian Smith

Posted on • Originally published at iansmith.github.io

Prevention, Not Recovery: What I learned building a tool to restrain AI coding agents

Got AI-generated bugs? Slop in your diffs? You are not alone.
slopstop is a Claude Code plugin that
replaces the prompt-and-hope loop with a prevention-oriented one. Work starts from a ticket — scoped and test-anchored —
before any implementation exists. It does not merge until several independent
passes have tried to find slop in it. The bet: prevention is cheaper than
recovery.

The problem with reviewing slop out

Most of the tooling around AI-written code is recovery tooling. It looks at a diff
that already exists and hunts for what is wrong with it. That is useful, and
slopstop uses these types of tools, but in conjunction with various other
analysis and adversarial agents. By the time slopstop invokes a code-review
tool, we should have prevented the really expensive mistakes like adding
new abstractions, out-of-scope implementations, or vacuous testing.
The review tools can, and are, victimized by code-writing agents because the
agent leaves a working program (with tests?) but the shape is the one the
agent chose. Put another way: Have you ever seen a code review agent say, "Throw
this whole thing away and do something simpler"?

Tests that pass are the interesting case. The common, sad failure mode of
AI-generated tests is that they are reverse-engineered from the implementation:
the agent reads the code it just wrote and writes assertions describing it. Those
tests pin the current behaviour, bugs included, and pass vacuously forever. A
review pass will not catch that. The tests are green. The diff is clean. The code
is wrong.

What slopstop does instead

The effort moves earlier — before the implementation exists.

Failing tests for what the ticket requires. /slopstop:plan writes the tests
first, from the ticket's stated behaviour rather than from any code. They have to
be red, and red for the right reason, before implementation starts. Every work
item in the plan is anchored to a named test turning green. slopstop commits
the state with the red tests and no implementation before work on the
implementation begins.

A written Definition of Done and scope boundary. Also drafted up front, in
plain language, on the ticket. You can see it is working when Claude stops
and asks "would you like me to spin out a new ticket for this out-of-scope
task?"
instead of quietly widening the diff. The definition of done section of
a slopstop ticket is the only way a ticket's implementation can be merged: "Are
all the definition of done conditions met?"

A simplify pass before the commit exists. /slopstop:pr runs a simplify pass
over the uncommitted changes — over-engineering, dead code, needless abstraction —
while removing them is still free. We use Claude's own simplify
pass
for this
(a cleanup-only review that applies its fixes without hunting for bugs), so this
is a "review type" pass.

A complexity gate that catches what simplification misses. slopstop computes
cyclomatic complexity for every function in the diff, using
lizard — and installs it for you if it isn't already
there. It warns above 10 and fails above 15. This catches a specific AI failure
mode: instead of factoring a problem into small pieces, the agent stuffs
everything into one function with a dozen branches. A human reviewer might wave
that through because the tests pass. The complexity gate will not.

A review pass that checks itself. There is an automated code review that is
performed on every ticket's implementation. slopstop will verify each finding
reported by the code review, and sorts what can be verified into should-fix /
could-fix / skip. Findings that do not hold up against the code are refuted in
writing rather than dutifully applied.

It scales past one ticket

Preventing slop does not mean working alone. /slopstop:design interviews you
about an idea, or just some random thoughts, until things are sufficiently clear
about what you want and how you want it done that we can write a Product
Requirements Document and a Charter for the idea you sent into /slopstop:design.

/slopstop:tickets cuts a ticket tree from it and hands the tree to an
adversary that tries to break it. The adversary checks every ticket created
against the PRD and Charter generated by /slopstop:design and if it finds
anything that doesn't match up, it rejects the ticket tree with a reason.

/slopstop:run drives parallel headless agents,
one per ticket, each isolated in its own git worktree, across multiple model
tiers — where every tier's work is checked by the tier above it. Weaker models
cost less but trigger more rounds of correction — the usual money-for-time trade.

The guarantees that hold for one ticket hold for the fleet: frozen tests with
tamper checks, independent handoff verification before any branch is integrated,
and a human gate at every stage boundary.

What it looks like when it catches something

Claims about adversarial verification are cheap, so there is a
transcript. One
real run: a five-sentence feature description turned into seven merged PRs by a
fleet of deliberately underpowered agents, read in time order, quoting the
transcript at every point where the process caught something.

Among the catches: a design interview that finds a contradiction between two of the
human answers seventy seconds apart. An adversary that rejects a ticket tree because
the lock it specified would not actually have locked — and proves it with a
forty-trial experiment. An implementing agent that reported success, exited
cleanly with a green tree, and had done nothing at all. And a final adversary that
re-ran the suite, confirmed the code was correct, and then found that the
orchestrator's own report had fabricated a violation against one of its own
agents — followed by a public retraction on the ticket.

That last one is the one to sit with. The process caught its own supervisor lying.

Try it

The walkthrough shows numerous examples of slopstop catching code errors, catching
ticket problems, and most importantly, human design errors. It is worth reading
in full.

Install slopstop:

/plugin marketplace add iansmith/slopstop
/plugin install slopstop@slopstop
Enter fullscreen mode Exit fullscreen mode

Then start from a ticket:
/slopstop:start <ticket>.

GitHub: github.com/iansmith/slopstop

Questions about the approach or the adversary catches? I'm in the comments.

Top comments (1)

Collapse
 
alexshev profile image
Alex Shev

Prevention is the right word here. Recovery sounds comforting until the agent has already overwritten a file, touched credentials, or shipped a change based on a bad premise.

The best restraints feel boring: scoped filesystem access, explicit approval gates, diff review, and commands that fail closed. They slow down the wrong actions much more than the right ones.