The verification loop
A bugb run is a loop over one repository: annotate, export, synthesise goals, probe, write back, report — then rotate the perspective and do it again. This page explains what each step contributes and, more importantly, how the loop decides to stop.
This is not an argument that you need a loop. One pass of guardlink and one
cxg pentest is a perfectly reasonable thing to run, and it is cheaper. The
argument here is about what a single pass cannot tell you.
Why once is not enough
Section titled “Why once is not enough”A single pass answers “which of the threats I could see today are exploitable”. The loop exists because that set moves:
- Annotation is not exhaustive. An agent reading a repository from one perspective finds one set of threats. From another perspective it finds others — see Lenses.
- A confirmed finding changes the map. Proving one control absent makes reachable a second thing that was previously guarded.
- Probing fails for reasons that are not answers. A dead session or an unreachable target produces no evidence, and no evidence is not a result. Only a later round can turn that into one.
What a round does
Section titled “What a round does”The journal of a real two-round run, with the goal attempts collapsed:
p00 preflightp10 envp20 authr0/p40 exportr1/p30 annotater1/p40 exportr1/p50 synthesizer1/p60 pentest → goal g-1-01 … g-1-08, attempts 1–2 eachr1/p70 writebackr1/p80 reportr2/p30 annotater2/p40 export…The three p00–p20 steps run once. Everything from p30 runs per round.
| Step | Contributes |
|---|---|
p00 preflight |
versions and capabilities of the tools it will drive |
p10 env |
the target environment, from its recipe |
p20 auth |
sessions for each identity |
r0/p40 export |
a baseline export, before any round runs |
p30 annotate |
an agent annotates the repository under this round’s lens |
p40 export |
guardlink’s SARIF for what the model now says |
p50 synthesize |
exposures become goals — scope, actor, preamble, mechanism, baseline, success |
p60 pentest |
cxg runs each goal, concurrently, retrying with a mutated approach |
p70 writeback |
confirmed findings become @confirmed annotations in the source |
p80 report |
ledger, summary, advisories |
Round 0’s export is the step most often overlooked, and it matters most in a repository that has been annotated before. Without it, round 1 would count an existing backlog of 100 annotations as 100 things it had discovered. With it, round 1 measures only what it added.
Every step is journalled, which is what makes bugb resume exact: a run
interrupted in r2/p60 resumes there, and r1 does not re-execute.
Goals are mostly not AI
Section titled “Goals are mostly not AI”A goal is assembled from six slots, and five of them are deterministic: the scope comes from the exposure and its resolved route, the actor from the lens and the seeded identities, the preamble from the environment recipe, the mechanism from the SARIF message verbatim, and the success condition from the vulnerability class. Only concrete exploit bodies and unresolved routes need an agent, batched into one call per round.
The preamble is the slot worth understanding. If a target needs a CSRF handshake and the probe does not perform it, every mutating request is rejected, the vulnerable code is never reached, and the run reports the mitigation as holding. That is a false negative shaped exactly like a clean result. Putting the handshake in the recipe — written once per target — is what keeps it out of the agent’s hands.
How a run stops
Section titled “How a run stops”Three ways, each recorded with its reason.
Converged. Consecutive healthy dry rounds, up to the depth the plan set. A round is dry when it found nothing new. It is healthy when nothing degraded it.
Every lens retired. The run has nothing left to look from. A run tracks this
per lens, in lenses.json, alongside the counters it decides on:
{ "lens_id": "unauth", "attempts": 1, "uses": 0, "new_exposures": 0, "confirmed": 0, "consecutive_dry": 0, "last_round": 1, "retired": false, "retired_reason": ""}A budget ceiling. Rounds, goals, or agent calls.
The distinction that carries the weight is healthy. A round degraded by timeouts or dead sessions is neither dry nor productive — it is neutral, and it neither advances nor resets the streak, because its emptiness proves nothing.
A run that degrades repeatedly halts and says so:
- **Status** — halted (2 consecutive degraded rounds; results are not trustworthy until the underlying failure is fixed)What it costs
Section titled “What it costs”- Time. The real run above spent roughly 87 minutes over two rounds, mostly
in
p60: eight goals per round, twelve attempts in round 1 and sixteen in round 2, because a goal that fails is retried with a mutated approach. - Agent calls. Annotation, environment-recipe authoring, goal enrichment and write-back are all agent-driven, and the annotate phase runs every round.
- Traffic against the target. Real exploit traffic, repeatedly, under several identities.
- Repeated annotation of your source. Every round has an agent editing the repository on the run branch.
--rounds, --max-goals and --fast are the levers. --fast cuts to one
template per goal and one retry, which is the right trade for a repeat run and
the wrong one for discovery.
Related
Section titled “Related”- Lenses — what rotates between rounds, and why the order is fixed.
- Verdicts and the ledger — what a round is allowed to conclude.
- Run the loop unattended — driving it.

