qvib.pro
RU
Loop Until Dry: Bounded AI Agent Cycles

Cycles: How the Engine Drives Work to a Result (loop-until-dry and the Iteration Cap)

In short

A cycle is a bounded loop of "do it → check → fix the class of problem → check again" that the engine runs on its own, but with hard brakes. There are two levels, and it matters not to confuse them: loopUntilDry in orchestration is the review loop around the prisms (while a critical/block finding exists, fix it and re-judge with the affected angles only; in Quest the maximum is 4 iterations, and past the cap it escalates to the owner), and a separate builder-level cycles layer covers long-running work cycles. The key rule is to fix the class of problem, not the individual symptom. Safety catches protect against spinning forever, and this article walks through them along with how the layer looks in the configurator and when to use it.

What it is

A cycle is a bounded loop of "do it → check → if it isn't done, fix the class of problem → check again." The engine runs it on its own, but with hard brakes so it doesn't spin forever. The spec has two levels of this mechanic, and it's important not to confuse them.

Находка BLOCKот призмыПочини КЛАССgrep всех местПере-судтолько затронутыеСухо?нет criticalДальшек сдачене сухо · кап 2 круга → отчёт
The "fix the class → re-judge" cycle, until dry — with a hard cap

Level 1 — orchestration.loopUntilDry (the review loop)

This is the loop around prism review. While a critical/block finding exists, fix and re-judge. It's exported into the package as a literal recipe text:

On BLOCK — fix the CLASS of problem (not the individual symptom) and re-judge with the affected angles ONLY. Repeat until dry (no critical/block), at most N iterations; past the cap, escalate to the owner.

In Quest, maxIterations: 4. The key phrase is class of problem: don't patch one symptom, fix the whole category and re-check with the affected angles only.

Level 2 — engine.cycles[] (general bounded loops)

Status. engine.cycles[] is a builder layer: supported by the schema and the exporter, but not part of the base flagship Quest seed yet (in development for the flagship). Level 1 (loopUntilDry, maxIterations: 4) is in Quest and works out of the box; level 2 is what you add yourself in the configurator when you need broader loops. Everything in this section describes the shape of the layer, not the behavior of the package you bought.

It's a separate primitive for broader scenarios, with five kinds: until-goal, for-each-work-item (a pass through the backlog), refine-until-quality, retry-with-backoff, reconcile-config. Here maxIterations is a required field with no default, capped at 12. That's deliberate: a loop without a hard ceiling can spin forever on a weak model, so "you can't describe a cycle without naming its limit."

2
levels of the mechanic: loopUntilDry and engine.cycles[]
4
maxIterations of the review loop in Quest — out of the box
5
kinds of cycle in the engine.cycles[] layer
12
maxIterations ceiling; the field is required, with no default

Three safety catches against runaway

  1. The counter comes from a file, not from memory. The recipe says it outright: count iterations from the ledger file .engine/cycles/<name>.count, NOT from memory — "memory lies about the counter." Each round: increment the file → do the work → run an executed verify.
  2. A token budget is mandatory. The schema rejects a spec on save if it has cycles[] but no permissions.budget.tokensSoftCap. Formally: "a loop without a token cap can burn unbounded cost on a weak model."
  3. The STOP rule. Hit maxIterations OR the token budget → STOP and escalate to the owner. "Don't keep spinning the cycle just in case."

There's protection for the neighbors too: a cycle has offLimits — paths the loop never touches, so a runaway cycle can't trample adjacent work.

When to use the cycles layer

  • for-each-work-item — run a backlog of N tasks through to verify-green on each.
  • reconcile-config — bring configs and services to the desired state (this kind is mandatory if the spec contains setup.systemConfig — otherwise the save is rejected).
  • refine-until-quality — polish an artifact until it clears the bar.

What it looks like at the builder layer

The example below shows the shape of the engine.cycles[] layer — how it's described in the configurator. This isn't a base Quest scenario (out of the box there's only level 1, loopUntilDry); it's what an engine does once you've added cycles to it.

Input: a backlog of 3 bugs, an engine with engine.cycles: [{ name: 'backlog', kind: 'for-each-work-item', maxIterations: 6 }] and tokensSoftCap: 400000.

What the engine does with this layer (literally following the recipe in the package):

  1. Creates .engine/cycles/backlog.count = 0.
  2. Round 1: increment → .count = 1. Takes bug #1, fixes the class, runs verify (npx tsc --noEmit, npm test). Green — locked in.
  3. Round 2 → .count = 2. Bug #2. A test fails — it fixes it and re-verifies until green.
  4. Round 3 → .count = 3. Bug #3. Done.
  5. The backlog is empty (the for-each goal is met), so the cycle ends at 3 of 6 iterations, normally.

The alternative outcome (an important one): if bug #2 refused to be fixed and .count reached 6, the engine stops at the cap and writes an honest report — "hit maxIterations on bug #2, here's what's left" — rather than pretending everything was fixed. It stops the same way if tokens cross 400000.

Result: three bugs closed with an executed verify on each; the iteration counter is objective (read from a file); cost is held by the budget; and on something unsolvable you get an escalation, not an infinite loop.

Two outcomes of one cycle (cap maxIterations = 6)
Normal: backlog empty
3 of 6
Bug won't be fixed
6 of 6
At the cap — STOP and an honest report to the owner ("hit maxIterations, here's what's left"), not a simulation of success. The same STOP applies when the 400,000 token cap is crossed.

Honest caveat

First the status: level 1 (loopUntilDry) is in the base Quest; level 2 (engine.cycles[]) is a builder layer and isn't in the flagship seed yet (in development). The section on the five kinds of cycle and the worked example apply to an engine you added that layer to yourself.

Now the boundary of the guarantee. The ledger discipline and the STOP rules are ADVISORY prose (an instruction to the target model), because a counter in a file doesn't block an exit code by itself. What's ENFORCED here is only the verify commands inside a round that carry a real exit code (tests, tsc, the linter). The token cap and the iteration cap, as schema rules, block building an invalid engine — but at execution time compliance rests on following the recipe.