/goal vs /loop vs /schedule vs Ralph: Which Loop Do You Actually Need?
/goal vs /loop vs /schedule vs Ralph: Which Loop Do You Actually Need?
Four ways to make Claude Code run without you. They look interchangeable from the outside β "the agent keeps going" β but their stop conditions, lifetimes, and blast radii are completely different, and picking the wrong one is how you end up with a loop that either quits too early or never quits at all.
Here's the decision guide, with semantics verified against the official docs (all facts below are from code.claude.com/docs, checked 2026-07-01).
The one-table version
| | /goal | /loop | /schedule (Routines) | Ralph |
|---|---|---|---|---|
| Next turn starts when | previous turn finishes | interval elapses | cron fires / API call / GitHub event | previous process exits (fresh session) |
| Stops when | fast model confirms condition from transcript | you stop it, Claude ends it, or 7-day expiry | you pause it / daily run cap | your harness says so (cap, check) β *nothing built in* |
| Context | one continuous session | one continuous session | fresh clone per run | fresh context every iteration |
| Lives where | your terminal | your terminal (session-scoped) | Anthropic cloud, laptop closed | wherever your bash runs |
| Min interval | n/a (back-to-back) | 1 minute | 1 hour | n/a (back-to-back) |
| Built-in cap | none β write it into the condition | 7-day expiry, 50 tasks/session | daily per-account run cap | none β you MUST add one |
| Permission prompts | normal session rules | normal session rules | none at all (scoped by repo/branch/connectors) | whatever flags you pass |
| Best for | converge on a verifiable outcome | poll something that changes | recurring/event-driven jobs | grinding a backlog overnight |
Now the nuance, because the nuance is where loops die.
`/goal` β when there's a finish line
/goal <condition> runs turn after turn until the condition holds. The mechanics matter: after each turn, a small fast model (defaults to Haiku) reads the transcript and answers yes/no. "No" comes with a reason, which becomes guidance for the next turn. Under the hood it's officially "a wrapper around a session-scoped prompt-based Stop hook."
Two properties trip people up:
1. The evaluator cannot run commands or read files. It judges only what's in the conversation. So /goal the auth module is refactored is unenforceable, but /goal npm test exits 0 and npx tsc --noEmit is clean β run both and show the output works, because Claude surfaces the proof in the transcript.
2. There is no built-in turn cap. The official pattern is to write the cap into the condition itself: ...or stop after 20 turns. Conditions max out at 4,000 characters; one goal per session; /goal alone shows status including token spend; the evaluator's own cost is billed on the fast model and is typically negligible.
Headless works too: claude -p "/goal ..." runs the whole loop in one invocation.
Pick /goal when the outcome is binary and provable from command output: [fix-tests-and-lint](/loops/fix-tests-and-lint) is the archetype, [kill-flaky-tests](/loops/kill-flaky-tests) the harder cousin (exit condition: 10 consecutive green runs). More at [/type/goal](/type/goal).
`/loop` β when there's no finish line, just a pulse
/loop 20m check CI and fix anything red re-runs a prompt on an interval while the session stays open. Key semantics:
- Session-scoped. Tasks live in the current conversation, stop when you start a new one, and are restored on
--resumeonly if unexpired. - Seven-day expiry. Every recurring task self-deletes 7 days after creation β an intentional bound on forgotten loops.
- 1-minute minimum, and fires are jittery (up to 30 minutes late, or half the interval for sub-hourly). Never build a loop that assumes exact fire times.
- Self-pacing. Omit the interval and Claude picks the delay each iteration (1 minβ1 hr) based on what it saw, and can end the loop itself once work is provably done.
loop.md. A.claude/loop.mdreplaces the built-in maintenance prompt for bare/loopβ your project's default loop, versioned in git.
Pick /loop when you're reacting to external change rather than converging on a state: [ship-pr-until-green](/loops/ship-pr-until-green) polls CI and pushes fixes until it's green. Browse [/type/loop](/type/loop).
`/schedule` β when the laptop is closed
/schedule creates a Routine: prompt + repos + connectors, executed on Anthropic-managed cloud infrastructure (research preview; Pro/Max/Team/Enterprise). Calling it "cloud cron" undersells it β one routine can have a schedule, an HTTPS fire endpoint, *and* GitHub event triggers.
The safety model is structural, and you should know it before you rely on it: routines run with no permission prompts at all. Blast radius is contained by fresh clones (no local files), pushes restricted to claude/-prefixed branches by default, connector scoping, and a daily per-account run cap. Minimum schedule interval is 1 hour β sub-hourly polling belongs in /loop, not a routine.
Pick /schedule when the job recurs on a calendar or fires on an event and doesn't need your machine: nightly audits, morning triage, PR-opened reviews. Examples at [/type/schedule](/type/schedule).
Ralph β when you want brute force with amnesia
The [original Ralph Wiggum loop](/loops/the-original-ralph-wiggum-loop) is a bash while true around claude -p "$(cat prompt.md)". Fresh context every iteration; all memory in files. That amnesia is the feature β no context rot, no 200-turn drift β and the danger: Ralph has no built-in stop, cap, or expiry. None. Every guardrail is yours to add: a hard MAX_ITER, a programmatic success check (never let the loop grade its own homework), and a guardrails file the agent reads at start and appends learnings to at the end of each pass.
There's also a bashless variant β a Stop hook that re-injects the prompt each time the agent tries to end its turn: [stop-hook-ralph](/loops/stop-hook-ralph-deterministic-loop-without-bash). Same semantics, one session, still needs a hard cap by construction. Whole family: [/type/ralph](/type/ralph).
Pick Ralph when you have a backlog of independent items and a mechanical check per item, and you're willing to build the harness. If you're not, you don't want Ralph yet.
The 30-second decision
- Provable end state, one sitting? β
/goal(cap in the condition). - Watch something and react, this session? β
/loop(remember: 7-day expiry, jitter). - Recurring or event-driven, laptop closed? β
/schedule(1h minimum, no prompts β scope it). - Backlog to grind overnight, fresh context each pass? β Ralph (bring your own cap or don't run it).
They compose, too: a routine that fires on PR events can set a /goal inside the run; a Ralph iteration is just a headless session that could itself carry a goal. And whichever you pick, an unattended loop should be able to tell you it finished β ConnectMyEmail gives your agent an email lane so "notify me" isn't the hard part of the harness.
Still unsure? Describe the job in the [loop builder](/builder) β it picks the loop type from your goal and exit condition and generates the harness, budgets included. Then run the result through [/grade](/grade) before its first unattended night.