Learn AI Engineering
Lessons
← Loop Engineering

The Loop, Actually Running: A Real End-to-End Demo

Every piece from Lesson 1.1 to 2.5, in one real recorded session: a goal the hook starves, a loop that does the work, a merge the gate refuses, and a teardown you can check.

Last lesson ended on a warning: a loop you can stop is still a loop you haven't checked. Module 3 is about checking it. Before that, watch it run once, for real.

Every terminal you've seen in this course so far was drawn by hand. This one isn't. It is one real session in a small fixture repo, loop-engineering-demo, recorded and scanned for secrets. Where the run disagreed with an earlier lesson, the lesson was corrected.

The run has three acts:

  1. A goal-based run the hook blocks.
  2. A time-based loop that does the real work.
  3. A teardown you can check.

Act 1: a goal the hook starves

Everything the course built is already committed in the repo: the hook settings, the skill, and four small scripts. Two tests fail on every run. That's the bug.

For this take the cap is lowered, so you can watch it fire. Two shell calls, not forty:

$env:LOOP_CAP = "2"
claude

Then Lesson 1.2's goal, typed word for word:

/goal Fix the failing tests in tests/test_pricing.py. Done when pytest tests/test_pricing.py exits 0, having collected >0 tests, and the full suite has no new failures. Stop after 12 iterations. Stop at $5. Stop and ask on no progress.

The guard fires

About ninety seconds in, the third shell call is refused:

call 3 exceeds cap 2

That's the guard, the PreToolUse hook from Lesson 1.2, and there's no arguing with it.

It reports something else too: no progress. Same failure, same diff. That is 1.2's rule, kept in 1.3's state file, and written by the test run, not by the model. So the agent stops and asks how to go on.

Prose against the hook

When asked, the model agrees to end the goal. Then this, over and over:

Goal not yet met… continuing

The model agreed to stop. The goal's own check didn't. It runs straight past its own twelve iterations, because that limit was only words in the goal. Nothing enforces them.

What actually ends it is:

/goal clear

The hook stopped the work. A person stopped the goal.

What the state file kept

Outside the session, .loop/state.json tells the story. The run half: four shell calls, two that ran and two that were refused. The work half: unchanged, one. That half was written by the test run, and it outlives the session.

Act 2: isolate, then triage

Now Lesson 2.2. Each run gets its own worktree:

git worktree add ../loopdemo-pricing -b fix/apply-discount
Copy-Item .claude\settings.local.json ..\loopdemo-pricing\.claude\

The scripts come along because they're committed. One file doesn't: the local setting that enables the GitHub connector. It's git-ignored, so it has to be copied across by hand.

Then triage, run by a person, before any loop starts:

cd ../loopdemo-pricing
python .loop/triage.py

Five runs each. The retry test failed three of five, so it's flaky. The pricing tests failed five of five, so they're real:

FLAKY  3/5  tests/test_retry.py::test_retry_eventually_succeeds

The flaky test goes on the quarantine list.

A new session starts in the new folder. There is no state file there yet. The cap counter starts at zero, and from now on this worktree keeps its own no-progress record.

Act 2: the loop does the work

Now Lesson 2.1's command. It runs once right away, then daily:

/loop 1d "Check the repo for newly failing tests. Rerun each 3x to rule out flakiness. If a real failure remains, fix it and keep going until the suite passes, then push the branch (not master)."

First it asks where the work lives: this session, or the cloud. The answer here is this session only.

A minute later, its report. One cause, one line changed. The quarantined test it left alone, as the skill from Lesson 2.3 says to. The suite went green three times. Nothing went to master.

Opening the pull request

Asked to open a pull request through the GitHub connector, it opens PR #6. And it says what it didn't do: no reviewers, and no merge.

The one you can't take back

Now the irreversible step. Asked to merge, the agent checks CI first. There's one red run, caused by the quarantined test, which CI can't see as quarantined. It talks itself past that, and calls the merge tool anyway. Hold on to that for Module 3.

The gate from Lesson 2.4 refuses it:

I didn't merge PR #6. The project's .loop/gate.py hook blocks every merge from
me: "a person approves this one."

And the refusal is written down, in 2.4's approval queue, .loop/approvals.jsonl, as a line naming mcp__github__merge_pull_request. The loop never gets a yes. It gets a no, and a record.

Act 3: a teardown you can check

Then Lesson 2.5. List what's scheduled: one daily job, this session only. Delete it by its id. List again: no scheduled jobs.

An empty list isn't evidence, so the last step is the switch that needs no cooperation from the agent:

$env:CLAUDE_CODE_DISABLE_CRON = "1"

With that set in this shell, a new session has no /loop at all. Master hasn't moved.

Every piece, in one run

What you sawWhere it was built
A goal the hook can starve1.2, 1.3
Triage before any fix2.1
A worktree per run2.2
Conventions it follows unasked2.3
A gate before anything irreversible2.4
A loop you turned off2.5

What you haven't seen is the loop checking its own work. It said green three times, and we took its word for it.

After this lesson

You will be able to:

  • recognise each piece from Modules 1 and 2 in a real session, and say what it did there;
  • tell a hook-enforced stop from a prose one by what actually happened when the model agreed to stop;
  • explain why the worktree, the triage step and the local connector setting have to be set up by a person before the loop starts;
  • name the two gaps the gate leaves: it depends on an allow rule, and it does not cover gh pr merge in the shell.

What comes next

Stopping a loop is not the same as checking it. In Lesson 3.1 you spawn an independent checker as a sub-agent, and hand it a verification checklist for this repo.

Companion article

Every hook, script, and command in this course, written up and executed: How to build an agent loop in Claude Code