Dako's AI Builder Notes
System
Color theme
Changsha HubOffline
大可 Dako
大可 Dako大可 DakoAI Builder · Agent PractitionerTurning AI into working software. Practical notes on agent engineering, vibe coding, and commercial delivery.
Platform links coming soon
"Stopped" is five different things, each needing its own confirmationModel stream endThis request got an end signal — it may be truncationTool batch returnsTools stopped ≠ the turn stopped; the model still reads resultsTurn endResults delivered, nothing pending, inbox emptyDriver idleNo next turn for now, still wakeable by a followupGoal endPersistent state settles: complete / blocked / pausedRecord each layer's end reason separately; idle is not completion
Tools stopping does not mean the round stopped; idle does not mean done.

Loop Engineering: Admission and Stopping

A loop is not a prompt on a timer: seven admission conditions, five layers of stop semantics, one inbox continuation rule. Idle is not done.

A loop is not "a prompt on a timer." A scheduled call has no persistent cursor, no idempotency key, and no independent verification; when it fails it can neither resume nor be audited — it does not constitute a loop. Real loop engineering answers two question groups at once: what earns the right to loop (admission), and what counts as stopped (stop semantics). while (hasToolCalls) is enough in a demo and not enough in production: the end has to be confirmed separately at several different places.

The harness owns one run; the loop owns many

Draw the boundary first. The harness defines the capabilities, constraints, and recovery of a single run; the loop manages triggering, state, verification, and continued improvement across runs. A complete loop takes five steps: Discover → Execute → Verify → Persist → Schedule — find work, execute, verify the result, persist state outside the conversation, schedule again dsh-pi-stop.

Two hard rules sit inside it: execution state lives outside the conversation (in-memory state dies with the process), and every work item carries a stable idempotency key (re-triggering the same item must not duplicate side effects). The loop is also forbidden from editing its own P0 — letting it rewrite its own approval rules and safety boundaries hands the brakes to the accelerator agent-trend-2026.

Seven admission conditions; miss one and you step back

Condition Requirement
Recurrence The task appears periodically or is triggered by stable events
Verifiability Results are auto-checkable, readable from environment state, or gated by a human
Actability The agent has controlled read, modify, test, and deliver capabilities
Recoverability Execution can be isolated, retried, rolled back, stopped
Economics Per-round cost and cost-per-success are budgetable
Governability There is an owner, permissions, audit, a kill switch, an escalation path
Sedimentability A failed loop should still leave fixtures, rules, or skills — not just a chat log

If any critical condition is missing, fall back to a single-run agent, a workflow, or a human process. This table is the same kind of instrument as the gates in When Multi-Agent Actually Pays: not a discouragement, but a demand that you answer every row before you build. Past admission sits a second question — what goes inside the loop and how it breaks, covered in Loop Engineering: The Control Surface and Its Failure Modes.

"Stopped" is five different things

One real incident lays all five layers on the table: an agent takes a ticket and creates a PR, then hits a 504 — the page shows no PR, but the server may have created one; a blind retry might create a duplicate PR, and stopping right there might bury a real failure; the PR exists but CI is still queued — does "the model said done" count as done dsh-pi-stop?

At moments like that, "stopped" has to be confirmed layer by layer: (1) model stream ended — only means this request received an end signal, which could be max-tokens, an error, or a cancel; (2) tool batch returned — tools stopping does not mean the turn stopped, the model still has to read the results; (3) turn ended — tool results delivered, no pending replies, inbox empty; (4) driver idle — no next turn for now; (5) goal ended — persistent state settles to complete / blocked / paused. Idle is not done — the outer goal driver's next check may still send a followup and wake it back up. When everything goes smoothly the layers are indistinguishable; the moment a 504, a cancel, a process crash, and a queued CI land together, the logs cannot say "which layer stopped here," and recovery turns into guessing.

Continuation goes through a message queue, not merged booleans

Several plugins and hooks all want to say "not yet" — how do you merge that? Boolean callbacks are the worst answer: a pile of should_continue flags fighting each other, nobody able to say who continued the run and when. The right design routes continuation intent through a message queue: a plugin that wants to continue writes a message to the next step's or turn's inbox, and the core loop rereads the inbox after the stopping hook, then decides stop or continue dsh-pi-stop.

Two payoffs: multi-plugin continuation needs no boolean merging, and every continuation intent leaves an auditable record — when something breaks you can find "which plugin slipped one more message in after the turn ended." This is the same design as events consumed only at safe points: the queue is read at boundaries, never mid-execution.

Record end reasons separately; truncated arguments are not executable

Each layer's end reason is recorded independently, in six kinds: completed / blocked / max-tokens / aborted / error / interrupted. The two easiest to confuse: aborted is voluntary cleanup after a cancel; interrupted is the state the recovery layer fills in after the process vanished — side-effect audit and retry decisions differ completely, and mixing them leads you to "retry the PR that may already exist." Turn-level end reasons survive to the turn's end: step 1 hit max-tokens and later steps finished the work, and the turn still records max-tokens; watching only the last step reads a truncation as success dsh-pi-stop.

One more safety line for writes: max-tokens truncation must happen before tool argument parsing. A half-finished JSON that a parser completes and a schema validates may already mean something else — once a write's side effect lands, there is no taking it back. When state is unclear, stop first and do not retry blind; that judgment returns to classify failures before counting them: classification first, and only then does the retry decision have grounds.

References

  1. When Should an Agent Loop Stop? Two Answers from DSH and Pi
  2. Agent Development Guide: too many technologies, what should you learn?