Step 1 - Write the loop contract
Start with a short contract. Put it somewhere the agent can read every cycle, for example .agent/loop-contract.md.
# Loop contract
Goal: Migrate the checkout to a working blog article system.
Done: Articles render, navigation links work, lint/build pass, and changes are committed.
Stop when: A test requires missing credentials, a destructive migration is needed, or the goal changes.
Evidence required: changed file list, route URLs, lint/build output, and final git status.
Keep this file boring. It should not contain every preference you have ever had. It should contain the contract that matters for this run.
Step 2 - Create a state file
The loop needs a place to write what happened. JSON is useful when scripts read it; Markdown is useful when humans read it.
{
"goal": "publish agent loop blog articles",
"status": "in_progress",
"cycle": 3,
"completed": ["found content renderer", "created article draft"],
"nextAction": "run lint and fix failures",
"blockers": [],
"evidence": [
"content/tutorials/claude-code-loop-engineering-guide.md",
"npm run lint"
]
}
The state file is not a diary. It is the smallest durable record another agent needs to continue.
Step 3 - Make each cycle small
A practical loop cycle looks like this:
- Read the contract and state file.
- Inspect only the files needed for the next action.
- Do one scoped edit or one scoped investigation.
- Run the narrowest useful verification.
- Update the state file.
- Decide whether to continue, revise, or stop.
If a cycle cannot be summarized in one sentence, split it.
Step 4 - Add a reviewer gate
The reviewer prompt should be stricter than the worker prompt. It should ask for defects, missing proof, bad assumptions, and overreach.
Review this cycle as a release gate.
Check:
- Does the diff match the loop contract?
- Are there unrelated changes?
- Did tests actually run?
- Are there hidden assumptions that need user approval?
- Is the next action concrete?
Return:
- pass or fail
- required fixes
- evidence that supports the decision
For code changes, the reviewer should prefer file and line references. For content changes, it should check source attribution, originality, titles, summaries, and reader usefulness.
Step 5 - Make proof part of the output
The loop should not say "done" because it edited files. It should say "done" when proof exists.
Useful proof types:
- lint, typecheck, unit test, and build output;
- browser or simulator screenshots for UI work;
- route checks for generated pages;
- changed file list;
- final
git status --short; - commit hash after commit.
This is where loop engineering becomes more than prompt engineering. The agent is not rewarded for sounding done. It is rewarded for making done observable.
Step 6 - Decide how the loop stops
A good stop condition is specific:
- stop if a command needs credentials that are not available;
- stop if the next step would overwrite unrelated user work;
- stop if the task requires a product decision;
- stop if verification reveals a pre-existing failure outside the requested scope;
- stop when the done definition passes.
Avoid vague stop conditions like "when the agent feels confident." Confidence is not a control plane.
Step 7 - Integrate the loop into daily development
You do not need a large framework at first. Start with three files:
| File | Purpose |
|---|
.agent/loop-contract.md | Defines goal, done, stop, and proof |
.agent/run-state.json | Stores current cycle and next action |
.agent/reviewer.md | Defines the release gate |
Then add a script only after the manual loop proves useful. The script can rotate state files, spawn agents, collect proof, and fail closed when required evidence is missing.