The Loop That Wouldn't Die
💥 The problem: Our loop-design skill described Claude Code's
/loop from folklore, and loops built on folklore stop too early or never stop.🔬 The method: We pulled the real
/loop implementation out of the Claude Code 2.1.201 binary and checked every claim against it.🔧 The result: 17 findings fixed in good-loop v1.1.0, including the stop instruction almost every interval loop prompt is missing.
/loop is Claude Code's way of running the same job on repeat: polish something until it passes, or check something every few minutes. We maintain a skill called good-loop that interviews you and designs those loop prompts properly.
A routine audit of that skill hit an uncomfortable question: how do we know any of our claims about /loop are true? The docs are thin, the harness has moved underneath us before, so we went to the one source that cannot be wrong.
We Read the Binary Instead of the Docs
Claude Code ships as one compiled executable with the /loop logic minified inside it. A string hunt with grep -a finds the readable text, and a short Python script dumps the raw bytes around each hit.
That surfaced the actual tick reminder wording, the argument parser, the feature flags, and the scheduling machinery. Every claim below comes from version 2.1.201 of the shipped binary, not from a guess.
| Audit fact | Value |
|---|---|
| What we audited | good-loop, our skill that designs /loop prompts |
| Source of truth | Claude Code 2.1.201 executable |
| Method | grep -a string hunt + Python byte-offset dumps |
| Audit rounds | 2 |
| Findings | 17, all fixed |
| Skill version | 1.0.0 → 1.1.0 |
How Does /loop Actually Work?
/loop runs one of two machines. With an interval, Claude Code converts it to a cron expression and arms a recurring job that re-enters the same session until the job is deleted. Without one, the agent self-paces by scheduling its own wake-ups and stops by declining to reschedule.
A cron job is a standing timer that fires on a schedule, the same mechanism servers use for maintenance tasks. The part that surprises people: nothing about it stops on its own.
/loop 4m <prompt> submitted
↓
⏰ interval converted to a cron expression, recurring job armed
↓
🔔 tick: the job fires into the SAME session
↓
🤖 agent works, replies, waits
↓
🔔 next tick fires (and the next, and the next...)
↓
🏁 terminal state reached: agent must DELETE the cron job
↓
✅ only then does the loop end
An interval loop is a burglar alarm, not a kitchen timer. A kitchen timer rings once and is done; a burglar alarm keeps ringing until someone cuts the wire. Your prompt must tell the agent to delete the recurring cron job at the finish line, or the loop outlives its purpose.
Self-paced mode is politer. The agent schedules each next wake-up itself, a keepalive re-pokes it if it goes quiet, and the loop ends once it declines twice (the binary calls this "keepalive budget exhausted").
Both modes also age out eventually through a maximum-age backstop. That is a safety net, not a plan.
Your Prompt Only Fires Once
Tick one injects your full prompt. Every later tick sends a short reminder that literally tells the agent to work the tasks "established earlier in this conversation".
That works because the loop lives in one continuing session. But long sessions get summarized, and a flag in the binary (tengu_loop_noop_fold) lets uneventful ticks be folded out of working memory entirely.
Quiet poller ticks are precisely the ones that get folded. So a check counter that lives only in the conversation dies quietly, and your hard cap dies with it.
The log file is the ship's logbook. Watches change and memories blur on a long voyage, but the logbook survives every shift. A loop that appends one line per pass to a file can always prove how many passes have happened; a loop that trusts its own memory cannot.
The Parser Eats Your Last Sentence
The argument parser has three branches, checked in order. A leading token like 4m becomes the interval; otherwise a trailing "every N minutes" clause is stripped out of your prompt and becomes the interval; otherwise the loop self-paces.
Branch two is the footgun. End a self-paced prompt with "check again every 5 minutes" and you have silently armed a 5-minute cron, with that sentence deleted from the prompt.
Click each command to parse it the way /loop does:
Five Minutes Is the Worst Interval
Claude's prompt cache (the short-lived store that makes re-reading a long conversation nearly free) lives for five minutes. A tick that lands inside that window re-reads the session cheap and fast; a tick that lands outside pays for the whole context again.
So a 5-minute interval is precision-engineered to miss the window on every single tick. Four minutes stays warm; ten or more accepts the miss in exchange for fewer firings.
| Interval | Cache when the tick lands | What each tick costs |
|---|---|---|
4m | still warm | cheap cached re-read, fastest response |
5m | expired, every time | full re-read of the whole session, every tick |
10m+ | cold, by design | full re-read, but half the ticks or fewer to pay for |
Pick 4m or less to stay warm, or 10m and up to fire less often. Never 5m: it is the round number everyone reaches for, and it is the one the cache is guaranteed to have just expired on.
The File Form: loop.md
Recent builds carry a native file form. Run bare /loop (or /loop 10m with no prompt) and it reads your loop tasks from a loop.md file, up to a 25,000-byte cap with a truncation warning.
The file gets injected once and referred back to afterwards, and you can edit it mid-run. It sits behind a feature flag, so pasting the prompt inline remains the guaranteed path.
your-project/
loop.md << bare /loop reads tasks from here (25k cap)
.claude/
loop.md << or from here, project-scoped
/loop, edit it while the loop runs.What Changed in good-loop v1.1.0
All 17 findings shipped as one release. The biggest class was stop instructions, because a prompt that says "STOP" does not delete a cron job.
The skill's core question survived the audit untouched: before any loop ships, ask how could the agent declare DONE without actually achieving what you wanted? Every answer becomes a verification check, the same audit habit we apply to our own quality loop.
Do
- End every terminal branch with "STOP the loop by deleting the recurring cron job".
- Log one line per tick to a file, and count the hard cap from the file.
- Put the interval first:
/loop 4m <prompt>. - Write long prompts to
loop.mdand run bare/loop.
Don't
- Trust the conversation to remember pass counts: quiet ticks get folded.
- End a self-paced prompt with "every 5 minutes": the parser strips it into an interval.
- Pick a 5m interval: it pays a full re-read on every tick.
- Skip the hard cap because the loop "should" stop on its own.
One honest gap: the exact instruction /loop gives the model when it arms a cron loop hides behind a minified variable our string hunt could not resolve. So designed prompts now spell the stop step out themselves instead of trusting the built-in wording.
Want your skills audited against reality?
Every Godmode skill gets checked against the harness as it actually behaves, binary included.
See the skills Read the previous audit