AI agent loops can produce an output, run some checks and move on without establishing that the result actually satisfies the task. The problem gets worse when the same generator writes the work, checks it and decides when it is done.
Say you ask an agent to modify an API and add tests. It writes the implementation, creates the tests, runs them, sees green results and declares the task complete. If the tests missed part of the requirement, the loop has no reason to stop and question the result.
In this tutorial, you'll add a verification step to that loop. You'll build the verifier as a Bit component, give it a four-value done condition and wire it into a TypeScript agent loop. You'll then export the component to a Bit scope so you can reuse it across projects.
Before you begin
Make sure you have:
A bit.cloud account with access to Hope AI. Head to bit.cloud/signup if you don't have one.
Bit installed through BVM. Run
npx @teambit/bvm installif you haven't installed it yet.A Bit workspace. You can use an existing workspace or initialize one with
bit init --default-scopemy-org.my-project.Basic TypeScript knowledge. You should be comfortable reading typed function signatures, imports and switch statements.
What is missing from your current loop
Your loop has no mechanism to catch bad output before it continues. The generator declares the task done and the loop moves on, whether the output is correct or not.
This is the same failure AgentField describes with agents that write both the implementation and its tests. The tests can pass because the generator created the checks that determine whether its own work passes. That is the generator checking its own homework, not verification.
The structural problem is your done condition. It is usually binary: the task is complete, or it is not. The generator evaluates the output, picks one of those two states and the loop continues.
A verifier separates those responsibilities. The generator produces the output. The verifier decides whether that output satisfies the condition you defined before the loop started.
What a verification loop actually does
A verification loop gives your agent a separate decision-maker. The generator produces the output, while the verifier receives that output and evaluates it against a done condition defined before the loop starts.
Instead of returning only true or false, your verifier returns one of four outcomes:
| Verdict | What it means | What the loop does |
|---|---|---|
| NO | The output failed the condition. | Retry with the verifier's reason as context. |
| YES | The output passed the condition. | Continue to the next step. |
| MAYBE | The verifier cannot determine whether the output is correct. | Pause and send it for human review. |
| IFF | The output is correct only if a named dependency is satisfied. | Check that dependency before continuing. |
This four-value model comes from Addy Osmani's work on owning the outer loop. It gives your loop more useful information than a binary done condition because not every output falls neatly into pass or fail.
The important part is the separation. Your verifier gets the generator's output and the condition it needs to evaluate. It does not get the generator's reasoning or rely on the generator's claim that the work is complete.
That gives you a loop where the component producing the work is not the component deciding whether the work passed.
Build the verifier component
A verifier component takes agent output and a done condition, then returns a verdict and a reason. To build it, open Hope AI and enter this prompt:
Build a TypeScript Bit component that verifies agent output against a done condition.
The component should:
- Define a DoneCondition type with four values: NO, YES, MAYBE, IFF
- Define a VerificationResult type with a verdict and a reason string
- Export a verify() function that takes an output string and a condition and returns a VerificationResult
- Isolate signal extraction from the verification logic
- Be pure and deterministic: the same input always produces the same result
Hope AI scaffolds the component into several files, some of which include:
done-condition.ts: theDoneConditiontype, runtime values and a type guardverification-result.ts: theVerificationResulttype with verdict and reasonsignals.ts: lexical signal extraction from the output text onlydone-verifier.ts: a thin dispatcher with one pure branch per condition
Below is an example code of the signals.ts which is used to enforce the isolation between the generator and the verifier:
export type Signals = {
empty: boolean;
completion: boolean;
failure: boolean;
uncertainty: boolean;
qualification: boolean;
evidence: boolean;
};
Each signal maps to a pattern group. completion fires on words like "done", "finished" or "all tests passed." failure fires on "error", "blocked" or "unable to." evidence is the strictest: it looks for test counts, exit codes, file paths and code blocks. An output that claims completion without triggering evidence will never return YES under the IFF condition, no matter how confident the language sounds.
Once you're satisfied with the code, click "Start review" in Hope AI. This creates a change request and triggers Ripple CI (Bit's built-in component CI/CD pipeline) to build and test the component automatically. Here's what a successful build looks like:
Once the build passes, click "Release" to publish the component to your scope on bit.cloud. This is what makes the verifier installable in any other project.
Wire the verifier into your existing loop
If you're following along with this tutorial, create a new Bit component to serve as the agent loop we're using to demonstrate the wiring:
bit create module agent/loop
If you already have an existing loop in your Bit workspace, skip this step and work directly with your existing component.
With your loop component ready, install the verifier. If you're working in a Bit workspace, run:
bit install @your-username/your-scope.verify.done-verifier
Replace your-username and your-scope with your actual bit.cloud username and scope name.
If you're working outside a Bit workspace, configure your .npmrc to point to the Bit registry first:
@your-username:registry=https://node-registry.bit.cloud
Then install via npm:
npm install @your-username/your-scope.verify.done-verifier
Then import the done-verifier into your workspace so the loop component can consume it locally:
bit import your-username.your-scope/verify/done-verifier
Bit lands the verifier at your-scope/verify/done-verifier and links it into node_modules as @your-username/your-scope.verify.done-verifier, ready to import.
Here's what the loop looks like before the verifier is wired in. The generated stub has no done condition and no evaluation:
export function loop() {
return 'hello world';
}
Open agent-loop/agent/loop/loop.ts and replace it with this:
import { verify, type DoneCondition, type VerificationResult } from '@your-username/your-scope.verify.done-verifier';
export type Step = (iteration: number, feedback?: string) => string;
export type LoopResult = { output: string; iterations: number; verification: VerificationResult };
export function loop(step: Step, condition: DoneCondition, maxIterations = 5): LoopResult {
let output = '';
let feedback: string | undefined;
let verification: VerificationResult = { verdict: 'NO', reason: 'Loop has not run yet.' };
for (let iteration = 1; iteration <= maxIterations; iteration += 1) {
output = step(iteration, feedback);
verification = verify(output, condition);
switch (verification.verdict) {
case 'YES':
return { output, iterations: iteration, verification };
case 'NO':
feedback = verification.reason;
continue;
case 'MAYBE':
return { output, iterations: iteration, verification };
case 'IFF':
return { output, iterations: iteration, verification };
}
}
return { output, iterations: maxIterations, verification };
}
The loop takes three arguments: a step function that produces output on each iteration, a DoneCondition defined before the loop starts and an optional maxIterations cap. On every iteration it passes the step output to verify() and branches on the verdict.
YES exits immediately and returns the output. NO sets feedback to the verifier's reason and continues to the next iteration, so the step function receives a specific signal about what failed rather than starting blind. MAYBE returns immediately for human review without continuing the loop automatically. IFF returns the result to the caller, which is then responsible for resolving the qualification before deciding whether to continue. The verifier signals that the output is conditionally correct but does not extract the dependency itself.
The feedback parameter is what makes NO useful beyond a simple retry. The step function receives the verifier's reason on the next call, which means the generator has context about why the previous attempt failed. Without that, NO is just a counter.
The verifier runs outside the step function's context. It receives only the output string and the condition, nothing from prior iterations or the step function's internal state.
To confirm the wiring works, run:
bit test agent/loop
The four tests cover each verdict branch. YES confirms the loop stops on the first iteration when the output satisfies the condition. NO confirms the verifier's reason carries into the next iteration as feedback and the loop exhausts maxIterations if never satisfied. MAYBE confirms the loop stops immediately and returns for human review. IFF confirms the loop stops immediately and returns the result to the caller when the output is conditionally correct. Resolving the qualification is the caller's responsibility.
Release and install across projects
With the verifier wired into your loop, tag the agent loop component and release it to your scope. Run:
bit tag --message "add verification loop to agent"
You'll see output confirming the component was tagged at version 0.0.1:
Then export to your scope on bit.cloud using this command:
bit export
You'll see Bit indexing the component and confirming a successful push:
After you run bit export, Ripple CI picks up the push and runs the build and test pipeline automatically. Here's what a successful build looks like:
With the agent loop live on bit.cloud, any project can install it with a single command:
bit install @your-username/your-scope.agent.loop
Your loop now has a second opinion
Before this tutorial, your generator had two jobs: produce the output and decide whether the work was done. When the same context performs both jobs, a passing result does not tell you that the work actually satisfied the condition.
The verifier changes that. It runs independently, sees only the output and the condition, and returns one of four verdicts before the loop decides what happens next. NO gives the generator a reason to retry. YES lets the loop continue. MAYBE pauses for review. IFF surfaces a result that needs its qualification resolved.
That separation is not a quality-of-life addition. The verifier is the part of the loop responsible for deciding whether the output satisfies the condition in the first place.
The verifier is now versioned on bit.cloud and ready to reuse across projects. If you're running agent loops without a separate verification step, create a scope and add one to your next loop.





Top comments (3)
Generator-verifier same-model is the part that bites hardest. The model that wrote the code grades its own homework with the same blind spots that produced the bug. What helped me: the verifier gets a different context - only the requirement text and the output, never the reasoning that produced it. Reasoning anchors the check toward 'what I meant' instead of 'what was asked'. 30 minutes is honest; the loop is small, the discipline is the cost.
This resonates hard — the generator-verifier same-model trap is exactly where
we lost two days debugging what looked like "model hallucination" but was
actually silent context truncation. Ollama accepted 6k-token GraphRAG
extraction prompts against a 2-4k default window, didn't error out, just
returned dumber entity graphs. No exception, no contract violation I could
catch programmatically: only a slow quality drift.
What saved us was boring LLMOps: an independent verifier that logged token
counts in/out on every call and alerted when context headroom crossed 80%.
The verifier saw only the output metadata, never the generator's reasoning —
which is exactly your point about context isolation. Rule since then: any
limit a service enforces silently is a bug in its docs, not in your client.
The 4-value verdict model (NO/YES/MAYBE/IFF) is interesting. How do you
handle MAYBE in production — human review queue, or escalation to a stronger
model? We're still debating whether "I don't know" should block the pipeline
or trigger a fallback.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.