Loop Engineering: Maker, Checker, Breaker
A safe agent loop separates three jobs: making the work, checking the evidence, and stopping the run. Let one model own all three and confidence quietly becomes control.
The draft was wrong, the review was glowing, and both came from the same agent.
That failure is easy to create. Ask an agent to produce an answer, then ask it whether the answer is good. The second prompt feels like verification, but the same model is still looking through the same eyes. It remembers the intent behind every weak choice. It is unusually sympathetic to its own shortcuts.
I have seen this pattern in code, architecture notes, and research. The maker says, “Done.” The reviewer says, “Comprehensive and well-structured.” A test, a missing source, or a human with fresh eyes finds the hole in minutes.
The problem is not that models cannot review. They can. The problem is role collapse: one actor is doing the work, defining success, interpreting the evidence, and deciding whether it gets another attempt.
Loop engineering separates those powers.
Three jobs, not one clever agent
The smallest useful control structure has three roles:
- Maker: produce a candidate.
- Checker: decide whether the candidate meets the contract.
- Breaker: decide whether the loop may continue.
A human sits outside the cycle for decisions the loop is not allowed to make.
These roles can be different programs, different agents, or different layers of one system. What matters is that their authority is separate.
The maker should not rewrite the rubric after seeing its score. The checker should not quietly repair the artifact it is judging. The breaker should not accept “one more try” just because the maker sounds close.
The maker owns the attempt
The maker’s job is creative and local: take the current goal, state, tools, and constraints, then produce the next candidate.
Good maker instructions are specific about the output but do not reveal every detail of the held-out check. If the maker knows the exact scoring tricks, it can optimise for the appearance of success instead of the outcome.
Give the maker:
- the goal and current state;
- the permitted tools and write boundary;
- the output contract;
- the evidence it must return;
- the budget for this attempt.
Do not give it the right to declare the entire loop complete. “I finished” is a claim submitted to the checker.
The checker owns the verdict
The checker asks a colder question: what evidence would make this candidate safe to accept?
The best checker rail is layered.
Start with deterministic gates
Run the checks that do not care how persuasive the candidate sounds:
- schema validation;
- compilation;
- tests;
- lint and policy checks;
- link validation;
- allowlists and security rules;
- required fields and provenance.
If a candidate cannot pass the objective floor, do not spend a model call debating its style. Reject it cheaply and return useful evidence to the maker.
Then apply the rubric
Some work cannot be reduced to a boolean test. A design may need to be coherent, a research note may need balanced coverage, and a blog may need a strong argument rather than merely valid Markdown.
Use a rubric with observable dimensions. “High quality” is not a dimension. “Every material claim has a source, the opening creates a concrete tension, and each section advances the argument” is.
Keep the scoring criteria stable during the run. A moving rubric turns iteration into negotiation.
Use a second model where judgment is genuinely needed
An independent checker can catch omissions and contradictions the maker misses. Diversity helps: a different model, persona, context, or temperature is more likely to make a different error.
But independence is not magic. A second model is still weaker evidence than a passing executable check. Put machine judgment after deterministic evidence, not instead of it.
The breaker owns permission to continue
The checker says whether the latest candidate passed. The breaker decides what happens next.
That distinction matters because failure does not automatically justify another attempt.
candidate = maker.run(state)
verdict = checker.evaluate(candidate)
if verdict.passed:
return complete(candidate, verdict)
if verdict.denied:
return terminate(candidate, verdict)
if budget.exhausted() or verdict.requires_human:
return handoff(candidate, verdict)
state = record_failure_and_prepare_next_attempt(candidate, verdict)
A breaker should understand at least four stop conditions:
Budget exhausted
Maximum attempts, tokens, money, or wall-clock time. A loop without a cost ceiling can turn a small problem into an expensive ritual.
No measurable improvement
If the score has plateaued, another mutation is not automatically progress. For hill-climbing loops, keep a candidate only on strict improvement. “Different” is not “better.”
Repeated failure class
Three attempts failing for the same missing permission or unavailable dependency are not three creative failures. They are one blocked condition repeated. Stop and surface the blocker.
Consequence requires a human
Production changes, external communication, destructive actions, money movement, or policy exceptions should suspend at a precise gate.
The loop is not failed while a person is deciding. It is waiting.
That state deserves its own name because it changes how the system behaves. A failed run may be terminal. A waiting run should preserve its exact candidate and approval request, then resume after the decision. It should not regenerate a slightly different artifact and assume the old approval still applies.
Approval belongs to the exact thing a human saw.
A checker is not a critic
This was an important correction in my own thinking. I used to picture the checker as a senior reviewer writing comments. That is only part of the job.
A useful checker returns a machine-actionable verdict:
passrevisewith evidencedenyawaiting_human
It should also return the failing criteria and the evidence used. That gives the next iteration something firmer than “make it better.”
For example:
{
"verdict": "revise",
"failed": ["source_coverage", "acceptance_test"],
"evidence": {
"uncited_claims": 2,
"test": "test_resume_after_approval",
"exit_code": 1
}
}
The maker can act on that. The record can preserve it. The breaker can count it. A dashboard can explain it.
“Needs improvement” does none of those things.
One practical pattern: gate, score, escalate
For consequential work, I use this order:
- Gate: remove candidates that fail objective checks.
- Score: compare survivors against a stable rubric.
- Escalate: ask a stronger model or a human only when evidence cannot settle the decision.
This keeps the expensive judgment focused on the small set of cases that deserve it. It also makes failure legible. The candidate did not lose because another model “felt better.” It failed the build, missed a source, scored below the threshold, or reached a decision reserved for a person.
Design your first bounded loop
Take one task you already repeat and write four lines:
- Maker: who produces what artifact?
- Checker: what independent evidence must pass?
- Breaker: what exact limits end iteration?
- Human: what decision can the loop never make alone?
If one actor currently owns all four lines, split the authority before you add more autonomy.
The goal is not to make agents distrust themselves. It is to stop confidence from becoming permission. A capable maker and a skeptical checker help, but the breaker is the component that lets you leave the room because it knows when the next attempt is no longer deserved.
Next in the series: State, Recovery, and the Right to Continue - how a loop survives restarts without repeating side effects or learning from the wrong signal.