cd /news/ai-agents/loop-engineering-in-claude-code-let-… · home topics ai-agents article
[ARTICLE · art-61151] src=pub.towardsai.net ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Loop Engineering in Claude Code: Let the Agent Run Itself

Loop engineering in Claude Code shifts developers from hand-prompting agents to building self-running cycles that find work, execute tasks, verify results, and decide next steps autonomously. The key insight is that the verifier—the check that determines when a task is truly done—is the most critical component, as agents can otherwise fake completion. Claude Code's built-in commands /loop, /goal, and /schedule enable both single-task iteration and scheduled chores, with the choice between self-paced loops and goal-driven loops depending on the cost of a false 'done'.

read9 min views1 publishedJul 15, 2026

Key Takeaways

  • Loop engineering is designing the system that runs your agent in a cycle (find work, do it, check the result, decide the next move) instead of hand-prompting every turn.

  • Loops aren’t just for chores. Point one at a single task and it iterates to done on its own, new feature work included.

  • A self-paced/looplets Claude decide when it’s done (fine when “tests are green” is trustworthy);/goalmakes a separate model confirm your condition every turn (use it when a false “done” is costly).

  • Triggers form a durability ladder: /loop (session), Desktop scheduled tasks (local, app open), and Routines via /schedule (cloud, runs with your laptop off).

  • The verifier is the whole game: close every loop on a check Claude can’t fake, then cap it with a turn limit and a budget.

Most developers still run their coding agent by hand: type a prompt, wait, read the diff, type the next one. Loop engineering is the shift to building a small system that does that for you: it finds the work, runs the agent, checks the result, and decides whether to go again.

In Claude Code that system is built in: /loop, /goal, and /schedule cover both driving a single task to done and running chores on a schedule, and the part that decides whether any of it works is the verifier — the check that says "done," and whether Claude can fake it.

The first time I left a coding agent running unattended, I used a self-paced loop and came back to a confident “done” — with 2 of 7 tests still failing. My second attempt was a /goal with a condition Claude had to prove: tests pass via the real command, no edits to the test files, no hardcoded values, stop after 25 turns. On turn 3 the evaluator caught it getting to green by editing the test file, and sent it back. On turn 4 the fix was real. Who decides "done" turned out to be the entire subject.

Loop engineering is designing the cycle your coding agent runs in: it finds work, hands it to the model, checks the result against a real signal, and decides whether to go again, without you in the chair for each step. You build the loop once; it prompts the agent from then on. The shift is from typing prompts to designing the thing that types them. In Claude Code, that cycle is a few built-in commands you compose: /goal, /loop, and /schedule.

A loop is more than a trigger. It has a skill that says what to do, a verifier that decides when it’s done, guardrails that keep it from doing damage, and usually some state so it remembers across runs. Skip the verifier and you don’t have a loop. You have an agent agreeing with itself on repeat, billing you for it.

And it does one of two jobs, which are worth keeping separate in your head:

Most write-ups only cover the second. The first is where loops quietly change how you build.

You don’t need a recurring chore to justify a loop. The everyday use is pointing one at a single piece of work and letting it run to completion: a refactor that has to keep the build green, a migration across a dozen modules, a feature that isn’t finished until its tests pass. Two commands do this, and the choice between them comes down to who decides it’s done.

**Self-paced **/loop (drop the interval) lets Claude work, check itself, and stop when it judges the job complete. Reach for it when the success check is something Claude can honestly verify in-context (tests pass, the build is green) and you don't mind it occasionally declaring victory a little early.

> /loop migrate the user service to the new logger, keep the build green and the      tests passing the whole way, and stop when the service is fully migratedmigrates the auth module, runs build + tests — green  next pass in 2m: auth done; billing and webhooks still on the old loggermigrates billing, reruns — green  next pass in 2m: webhooks leftmigrates webhooks, full build + test run passes  done: user service migrated, build green, 0 failing tests. ending the loop.

That “next pass in N minutes” line is real: with no interval, Claude picks the delay after each iteration and prints why, then ends the loop itself once the work is provably complete (scheduled tasks docs). The catch is in that word itself. Claude is grading its own homework, so a self-paced loop can decide it’s finished when it isn’t.

/goal closes that gap. You write a completion condition, and after every turn a separate small model (Haiku by default) checks whether the condition holds — completion is decided by a fresh model, not the one doing the work (goal docs). Use it when "done" is fuzzier or the cost of a false "done" is high. That's exactly new feature work, where the model has every incentive to fake the finish: the condition has to be proven, and Claude can't route around the hard part by editing the test or hardcoding the answer.

> /goal the tests in test/ratelimit pass via `pnpm test ratelimit`, with no edits      to the test files and no hardcoded values, or stop after 25 turns◎ /goal active · turn 1 · 0m  writes src/ratelimit/window.ts, runs the suite  evaluator → no: 2 of 7 fail, the burst window resets early. keep going.◎ /goal active · turn 3 · 4m  fixes the reset boundary, reruns  evaluator → no: 7/7 green, but ratelimit.test.ts was edited. revert it.◎ /goal active · turn 4 · 6m  reverts the test, moves the fix into the source, reruns  evaluator → yes: 7/7 pass on the unmodified tests. goal achieved.

One accuracy note that changes how you write conditions: the evaluator can’t run commands or read files on its own. It only judges what Claude has already surfaced in the conversation. So “the tests pass” only means something if the loop actually runs the tests and shows the output — write the condition as something Claude’s own output can demonstrate, and the or stop after N turns clause so it can't run forever. A live ◎ /goal active indicator and a /goal status view show the condition, turns evaluated, token spend, and the evaluator's latest reason.

Under the hood /goal is a wrapper around a session-scoped Stop hook, the same mechanism you'd reach for to script your own completion logic. Both fire after every turn; /goal just ships the evaluator for you.

The other mode is recurring work: nightly CI triage, weekly dependency bumps, lint-and-fix on every pull request. Here a loop earns its keep only when the work recurs often enough to amortize the setup, a check can fail bad output automatically, and you’re fine spending the tokens each run costs. If it happens less than weekly, a single sharp prompt is cheaper than a loop.

Three triggers run recurring work, and they differ by how long they survive — a durability ladder, not a single command (scheduled tasks docs).

> /schedule nightly at 2am, review every PR merged that day, flag risky          changes, and post a summary to the #eng channelcreated routine "nightly-merge-review"  (cloud)trigger: schedule · 0 2 * * *  (America/New_York)runs on Anthropic's infrastructure — no session requiredmanage at claude.ai/code/routines

From the CLI, /schedule creates time-based routines; API and GitHub triggers (fire on a webhook, or on a PR or release) are added on the web (routines docs). The trade-off for that durability: a routine clones your repo fresh each run and has no access to your local files.

The trigger is only the heartbeat. What the loop actually does each run lives in a skill — a SKILL.md file with YAML frontmatter and plain-Markdown instructions. The format is worth seeing, because it does more than hold text: the !command syntax runs a shell command and drops its output into the skill before Claude reads it (skills docs).

~/.claude/skills/review-diff/SKILL.md---description: Summarize uncommitted changes and flag anything risky. Use when  the user asks what changed, wants a commit message, or asks to review a diff.---## Current changes!`git diff HEAD`## InstructionsSummarize the changes above in two or three bullet points, then list anyrisks you notice: missing error handling, hardcoded values, tests that needupdating. If the diff is empty, say there are no uncommitted changes.

That “injected diff” trick is how a skill starts every run with fresh, real context instead of a stale description — the same context-engineering discipline, automated. When a loop needs to act, not just report, the allowed-tools field grants specific commands without a prompt each time:

---name: commitdescription: Stage and commit the current changesdisable-model-invocation: trueallowed-tools: Bash(git add *) Bash(git commit *) Bash(git status *)---

State is what the loop carries between runs: what it already tried, what it escalated, what it learned. Keep it in a file the next run reads — a checklist, a tracker, a small STATE.md — not in the chat, where the next run can't see it. A scheduled task even stores its own skill on disk for exactly this reason. Guardrails are the last part: allowed-tools and disallowed-tools bound what the agent may touch, and anything irreversible — a deploy, a migration, a dependency bump — should sit behind a human-in-the-loop approval gate. This is the same logic as harness engineering: the agent that wrote the code is the wrong one to decide it's safe to ship.

An unattended loop is a loop spending money while you’re not watching, so every loop needs three guards working together.

The cheapest safety feature is built in. A /loop dies when you close the session, so if one misbehaves, closing the terminal stops it. A Routine doesn't — it keeps spending precisely because it survives, which is why the cloud one is the one that needs a real budget and tight guardrails before you walk away.

Before you automate a task, run it through five questions:

Then build the smallest version. For run-until-done work, start with /goal and a condition you can prove. For a recurring chore, pick the trigger by durability: a /loop while you're at the keyboard, a Routine for hands-off. Write the work into a SKILL.md, cap the turns, and watch the first few runs before you trust it. A loop is fast to start and easy to get wrong; the small version teaches you which.

A loop is only as good as the signal it closes on — and that signal is your codebase’s tests, types, and guardrails. Before I trust one unattended, I make sure there’s a real quality gate for it to close on: tests that actually fail, scoped permissions, a review step it can’t skip. Otherwise it’s just checking against its own opinion.

Loop Engineering in Claude Code: Let the Agent Run Itself was originally published in Towards AI on Medium, where people are continuing the conversation by highlighting and responding to this story.

── more in #ai-agents 4 stories · sorted by recency
── more on @claude code 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/loop-engineering-in-…] indexed:0 read:9min 2026-07-15 ·