Loop completion needs user-confirmed terminal conditions, not model self-report
An agent saying “done” should never be the event that makes a task complete. Self-report is a useful proposal, but it is still generated text from the same uncertain process that performed the work. Completion needs a terminal condition defined outside the model, verified against resulting state, and confirmed by the user when the objective contains judgment the system cannot observe.
Naive loops usually expose one stop tool or ask the model whether the task is finished. That gives the model full control over both execution and acceptance. It may stop early because a tool returned a plausible message, continue after the objective has been met, or declare success while a write is pending, rejected, or applied to the wrong target. The failure is architectural: the worker is grading its own work with no independent contract.
I prefer a terminal-state machine with named outcomes: completed and verified, awaiting user confirmation, blocked, budget exhausted, cancelled, and failed with recoverable state. The model may request one of these transitions, but the harness authorizes it. Machine-verifiable tasks use predicates over authoritative state: the record exists, the tests pass, the destination received exactly one message, the expected files changed and unrelated files did not. Recovery tests should prove that interruption before verification cannot masquerade as completion.
User confirmation belongs where “done” is partly semantic. A research brief can satisfy a structural checklist and still miss the question. A design can render without expressing the intended hierarchy. An email draft can contain every requested fact and use the wrong tone. In those cases the runtime should enter awaiting confirmation with the artifact, evidence, and unresolved choices visible. Silence is not approval, and a timeout should become its own state rather than silently converting to success.
Confirmation does not mean asking the user after every step. The task contract should identify consequential checkpoints before execution: what can be verified automatically, what requires judgment, who may accept it, and what evidence they will see. Confidence should change the handoff, but confidence is a routing signal, not acceptance. High confidence may reduce review depth; it should not erase a required acceptance boundary.
Budgets are another legitimate ending, not merely an error. When time, tokens, money, privacy, or retry limits are exhausted, the loop should preserve the last verified checkpoint and report what remains. Budget exhaustion deserves a first-class terminal state because pretending an incomplete run failed opaquely invites a blind retry. A typed ending lets the user extend the budget, narrow scope, accept partial output, or stop.
The same state model prevents the idle-awaiting-permission trap. When an approval is required, the agent should checkpoint, release scarce runtime resources, publish the exact decision and deadline, and resume only from a matching authorization event. It should not keep reasoning in the background or reinterpret an unrelated reply as consent. Waiting is observable workflow state, not unfinished internal thought.
There is one precise concession: a bounded, deterministic, read-only lookup can complete automatically when its success predicate is exhaustive and the cost of a false positive is negligible. If the contract is “return the current value of this field” and the source responds with a validated record, explicit human confirmation adds ceremony. The claim applies when work changes state, composes uncertain steps, or asks for qualitative acceptance.
Durable execution makes tasks resumable; explicit terminal conditions make them finishable. I want every run to end with a typed state, supporting evidence, and a clear authority for acceptance. The model can explain why it believes the work is complete. The system—and sometimes the user—must decide whether that belief is enough.