An AI agent often manages a desired state rather than completing a one-time task: a deployment should match its source, a queue should stay within policy, or a local index should reflect its inputs. The durable pattern is a reconciliation loop: observe the current state, compare it with an explicit desired state, apply the smallest safe correction, and observe again.

This is more reliable than asking an agent to “keep things working.” The loop makes drift visible and gives every correction a bounded decision path.

Separate observation from correction

Start with a read-only observation. Normalize the result into a small state record instead of passing raw logs through the whole loop:

Observed state
Target: <generic resource or collection>
Desired marker: <safe version, checksum, or policy label>
Actual marker: <safe observed value>
Invariant results: <pass | fail labels>
Drift: <none | recoverable | unsafe>

Only a known, recoverable drift should enter the correction step. Unknown errors, ambiguous ownership, and failed invariants should stop the loop and produce a blocker report. The agent should never infer that an empty or malformed observation means “everything is missing.”

Make corrections idempotent

A correction may be interrupted after it changes part of the state. Design it so that repeating the same operation converges on the same result rather than duplicating work. Prefer upserts, replacement of a named version, and operations keyed by stable identifiers over append-only mutations.

Before acting, the agent should know:

  • what resource it is allowed to change;
  • which desired marker it is applying;
  • what “already correct” looks like;
  • how to verify the postcondition; and
  • which failures are non-retryable.

If those answers are not available, stop at observation. A retry budget cannot make an unsafe mutation safe.

Bound the loop

A reconciliation loop needs explicit limits. Use a small correction budget, a time limit, and a no-progress rule:

Reconciliation contract
Observe: <read-only state query>
Desired: <version or invariant set>
Correct: <one safe, idempotent operation>
Verify: <postcondition query>
Budget: <maximum corrections or elapsed time>
No progress: stop if the observed marker does not change
Stop if: <ambiguous, unsafe, or non-retryable failure>
Receipt: <safe facts only>

After each correction, observe again rather than assuming success from the command result. If the marker does not move toward the desired state, stop. Repeating an ineffective action only increases risk and obscures the original failure.

Preserve a useful receipt

For unattended work, report the decision and bounded evidence—not the entire diagnostic stream:

Reconciliation receipt
Target: <generic target>
Desired: <safe marker>
Initial drift: <summary>
Corrections: <count within budget>
Final state: aligned | partially aligned | blocked
Verification: <postcondition labels>
Public-safe: yes
Next action: none | retry later | investigate

This receipt lets a later run distinguish “already aligned,” “corrected once,” and “stopped safely.” It also supports state-change-only alerting: quiet success when nothing changed, actionable notification when alignment failed or a boundary was reached.

Rule of thumb: observe first, correct once, verify again, and stop when the state does not make measurable progress.