Essay
The agent said “done.” The system disagreed.
I wanted to see if “check your work” could be more than a prompt. So I built a workflow that just refuses to continue when the result doesn't pass.
I've been thinking a lot about a small distinction that gets more important as agents become more autonomous.
You can ask an agent to verify its work.
Or you can build the system so the next step literally cannot happen until verification passes.
Those sound similar. They're not.
The first is a prompt.
The second is infrastructure.
The sticky note problem
Telling an agent "check your work before proceeding" is a little like putting a sticky note on someone's monitor.
Usually they'll follow it. Sometimes they won't.
Here's the part that bothers me: the system can't tell those cases apart. Whether the agent checked, skipped the check, or graded its own homework generously, the workflow looks exactly the same from the outside. Compliance is a behavior, not a property.
A gate is different. It's more like the next door stays locked until the required proof exists. Nobody has to remember anything. The door just doesn't open.
Prompt
The note asks. Nothing checks. The flow never stops.
Gate
The bar opens for one thing only: an acceptable signed Outcome.
I wanted to know whether an agent could literally be prevented from continuing. Not discouraged. Prevented.
The smallest version I could build
I wanted to see how small we could make that idea, so we built a three-step workflow on Cloudflare Workflows:
- do the work
- get a signed Outcome from Spoolis
- take the consequential action
If the Outcome is missing or doesn't satisfy the policy, the workflow stops.
Not because the agent decided to be careful.
Because the runtime won't let it continue.
The work in this case is the same dataset from 100 delivered, 97 counted: 100 company rows, three of them broken on purpose, verified as 100 units at $1.00 each against a pinned recipe.
When I ran it, verification came back the way it should: 97 accepted, 3 rejected with per-unit reasons, $97.00 of $100.00 earned, all on a signed receipt.
The gate
97 of 100 accepted
requireOutcome(... allowPartial: true)
This workflow's policy accepts earned partial outcomes, so the final step went ahead with the 97 accepted units and handed back the 3 rejected ones for re-dispatch.
So far, so cooperative. The interesting run is the other one.
Watching the door stay locked
I set up a second, stricter version: three units, two pass, one fails, and this time the policy is all or nothing.
Verification came back partial, honestly: 2 accepted, 1 rejected, signed receipt and all. Real work happened. Most of it was even good.
And that was it. Two of three passed, but this workflow required all three, so the next step never ran.
The door stays locked
2 of 3 accepted · policy required all 3
Outcome verdict partial doesn't satisfy the gate.
The runtime didn't negotiate with the agent or ask it to reconsider. It just stopped.
The consequential step never executed. There's no prompt I could have written into the agent that changes this, because the agent isn't the one being asked. The runtime checked the receipt, the receipt didn't satisfy the policy, and the door stayed locked.
Same code, same verifier, different policy. The caller decides what's acceptable. The runtime enforces it.
My first instinct was a bigger thing than this
When I started sketching this, my instinct was to build something substantial: an SDK, a package, wrappers for each framework.
Then I noticed the gate itself is about forty lines and has no framework in it. It checks three things: a receipt exists, the verdict is acceptable under the caller's policy, and a partial outcome carries earned value if partials are allowed at all. Anything else throws.
That's deliberately boring. The same function works as a workflow step guard, as a beforeToolCall hook that keeps a consequential tool unavailable until an acceptable Outcome exists for the delegated task, or as plain middleware in any stack. Copy-paste it. There's nothing to install.
I think that's actually what I like about it. The gate isn't a new framework. It's just a small rule at the point where something consequential is about to happen.
Why the Outcome has to be signed
There's a version of this where the gate checks the agent's own self-report, and it's worthless. The whole reason the door can be trusted to stay locked is that the proof isn't the worker's own "done." It's produced under the judging authority both sides agreed to.
The gate's input is a signed verification result produced under the agreed judging authority, with per-unit verdicts and reasons, so a different system can check it later without reconstructing the whole transaction. The workflow persists it as a durable step result, so a retry replays the same receipt instead of re-verifying.
I wrote recently about paying $20 for work where the payment was verifiable and the work wasn't. This is the other half of that thought. Once verified work produces a signed, portable object, the object can do jobs the agent's word never could. Gating a workflow is the simplest one.
What this doesn't prove
The usual honesty section, because it matters:
- This was our own demo against our own service. It proves the mechanism works, not that anyone wants it.
- Most runs used the keyless sandbox, whose receipts are demo-labeled and expire. We ran the production paid path once, for a real fee of half a cent, and that run minted the permanent receipt linked above.
- Cloudflare Workflows is one runtime. I picked it because durable steps make the persistence part free, but the pattern is the point: any system with a step boundary or a tool seam can hold the same gate.
Try it
The sandbox is keyless: the quickstart gets you a signed Outcome in a couple of minutes, and requireOutcome is small enough to read in one sitting. The full workflow from this essay, both scenarios and the evidence, is public at spoolis-outcome-gate-demo.
The agent can still say "done."
The system just doesn't have to believe it.