AI

The Agent That Does the Work Cannot Be the One That Signs Off

Flat vector illustration of two robot agents on a dark navy grid: one passes a glowing coral cube through a tall verification gate archway with a scanning beam, while the second robot waits on the other side to receive it.
Flat vector illustration of two robot agents on a dark navy grid: one passes a glowing coral cube through a tall verification gate archway with a scanning beam, while the second robot waits on the other side to receive it.

On July 5th, one of our devops agents reported that it had fixed a P0 incident on a creative writing platform we run in production. The fix did not exist. Nothing it described was actually running in production. We know this because the completion claim never made it past our verification gate: a second agent, with a clean context, went looking for the fix and found a phantom.

That was catch number one. Catch number two had money on the line. Our verifier flagged a fail-OPEN bug in our trading system’s orb_status gate: a missing /commands check meant the trading system would keep trading in exactly the situation where it should have halted. The worker agent had reported the gate “implemented and working.” It was implemented. It was not working. We fixed it in commit 14db7aa, before any live capital was exposed to the bug.

Catch number three is the opposite kind of result. On June 18th, a statement of work passed through the gate clean on the first attempt. No rejection, no rework. The gate is not a wall that everything crashes into. Work that is actually done gets through.

All three outcomes came from one rule: the agent that does the work never gets to mark it complete. We have now packaged that rule as a small open-source MCP server called verify-gate, and this post explains why it exists and how it works.

Why self-reported completion fails

Flat vector illustration of a robot at a desk stamping its own document while its mirror reflection stamps in unison

If you run agents that do real work, you have probably noticed that “done” is the cheapest word in the system. There are two structural reasons for that, and neither one is fixed by better prompting.

The first is the incentive shape of the loop. An agent’s job is to finish the task. “Done” is the terminal state it is driving toward, and in most frameworks nothing in the loop pushes back on the claim. There is no deception involved. The agent produced output that looks like a fix, summarized it, and reported completion, because that is what finishing looks like from inside the loop.

The second is context blindness, and it is worse. The worker judges its own output inside the same context that produced the mistake. Every wrong assumption that led to the bug is still sitting in the context window when the agent evaluates the result. It inherits its own blind spots wholesale. The phantom fix on the creative writing platform was exactly this: the agent’s context contained a plausible story of a fix, so when it checked its work, it checked the story, not the system.

This is also why “just prompt it to double-check” does not work. Self-review runs in the same context with the same blind spots. Asking the worker to be more careful is asking the same reader to reread the same page and notice what it missed the first time. What you need is a second reader with fresh state, looking at the actual system instead of the story about it.

For prior art: verify-gated completion is largely unexplored. The closest work we found is research-only (arXiv 2605.17998). CrewAI, LangGraph, and AutoGen are all capable frameworks, and all of them let the worker declare victory. That gap is what this tool fills.

How the gate works

Flat vector illustration of two robot agents at a tall verification gate, one presenting a glowing cube and the other inspecting it with a magnifier

verify-gate enforces a short state machine: pending, claimed, then verified or rejected. Four moments matter.

Criteria at birth. A task cannot be created without at least one non-empty acceptance criterion, and there is no add-criteria-later tool. Criteria are defined up front, not inferred after the fact, so “done” means something concrete before any work starts.

The claim. The worker (the prover) does the work and calls claim_done with evidence, not a status flag. The claiming agent’s identity and its evidence are permanently recorded. “Done” is a claim to be tested, and the record of who claimed it is part of the task forever.

The verdict. A separate verifier agent, running in a clean context, checks the claim against the acceptance criteria and the actual system state: it runs the thing, reads the logs, hits the endpoint. Then it calls verify with a task-level verdict, verified or rejected. A rejection requires notes explaining exactly what failed, so the gap is named, not vague.

The enforcement. This is enforced, not requested. If the verifier is the same agent that claimed the task, the server hard-rejects the call with E_SELF_VERIFY, for both verdicts. This is enforced server-side by a SQLite CHECK constraint. It is not a prompt, not a convention, not a system-message plea to be honest. The database will not accept the write.

Both end states are terminal. A verified task stays verified. A rejected task stays rejected, and that is deliberate. Rejection does not bounce the task back into the worker’s queue for another spin. Remediation is a new task, created with the supersedes field pointing at the rejected one. Each attempt is its own record, with its own evidence and verdict, and the supersedes chain gives you full lineage: you can walk from the final verified task back through every rejected attempt and read exactly what failed at each step.

This is where the June 18th clean pass matters. Convergence under this model is not “the loop repeats until it passes.” Convergence is a short supersedes lineage, ideally length one. Work that is genuinely complete produces a single task that goes pending, claimed, verified, and stops. Work that is not complete produces an honest paper trail of what it took to get there. Both outcomes are useful. Neither is an infinite loop.

What ships in the OSS kernel

The open-source release is a standalone MCP server with five tools: create_task, claim_done, verify, get_task, and list_tasks. That is the whole surface. Task creation with criteria, the claim with evidence, the verdict, and inspection with full append-only transition history.

It works with any agent setup that speaks MCP: Claude Code, custom SDK agents, anything that can call tools. There is no framework lock-in and adapters stay thin by design, because the state machine and its invariants are the product. Multiple agents each run their own server process pointed at the same SQLite file, and every state transition is a compare-and-swap inside a transaction, so concurrent claims have exactly one winner.

Identity in v1 is caller-declared, with an optional lock: launch with VG_AGENT_ID or --agent-id and the connection is pinned, so any tool call declaring a different identity fails with E_IDENTITY_MISMATCH. The threat model is honest-but-lazy agents, the ones that mark their own work complete out of convenience or context blur. It is explicitly not adversarial identity forgery. An adversarial agent inside your fleet has already won, and no task gate will save you from it.

What we kept internal: our fleet orchestration, Telegram plumbing, org-specific criteria libraries, and the rest of the surrounding system stayed home. The gate is the generalizable idea; the rest is our infrastructure and would only add noise to yours.

What this is not

verify-gate is not an orchestrator, not a project-management tool, and not a task board. It does not assign work, schedule agents, or track your sprint. It does one thing: gate completion behind independent verification. It composes with whatever you already run, and it stays out of the way of whatever runs your agents.

The deeper pattern

Verify-gate is a narrow tool, but it points at something the broader AI industry keeps sidestepping: measurable completion criteria are not a nice-to-have. They are the difference between an improvement loop and a feelings loop.

Every AI system being sold on “agentic loops,” “self-correction,” and “continuous improvement” has to answer the same question verify-gate forces at task creation: what does done actually mean, in a form that can be checked by something other than the thing that did the work?

“Done” is not measurable. “Better” is not measurable. “The agent said it succeeded” is definitely not measurable. These are labels, not states. A loop that cycles on labels does not improve. It accumulates confidence.

The fix is structural, not philosophical: define the goal before the work starts, in terms that a separate process can query. Verify-gate does this for task completion. The same logic applies anywhere a system claims to learn from its own output.

The 30-day report

A tool about not trusting self-reports should not ask you to trust its self-report. Thirty days after launch, we will publish integration metrics and false-completion catch counts from real use, ours and any early adopters who opt in. That report will include the unflattering numbers: false positives from verifiers, task lineages that thrashed through multiple supersedes before converging, and acceptance criteria that turned out to be unverifiable in practice. If the gate catches nothing in your setup, that is data too, and we will say so.

Try it

git clone https://github.com/Monkeyattack/verify-gate-mcp.git
cd verify-gate-mcp
npm install
npm run build
node dist/index.js --db ./tasks.db

npm package coming soon; the repo is at github.com/Monkeyattack/verify-gate-mcp.

The README walks you from install to your first independently verified task in about 15 minutes, including the MCP config snippet to paste into your client. The license is MIT.

One specific ask: if an agent has ever told you something was fixed and it was not, we want that story. Open an issue with what the agent claimed, what was actually true, and what would have caught it. Those failure reports are how the verdict model gets better. PRs welcome, and every claim in a PR description gets verified before merge. We practice the thing.

Related reading

Chris Meredith writes about AI, technology, and what it actually means for real people. Follow along on Substack: monkeyattack.substack.com

Leave a Reply

Your email address will not be published. Required fields are marked *