Set Up a Self-Running Loop That Prompts the AI for You

This page installs a loop in your own Claude Code that lets the AI decide what to do next and keeps running on its own. Paste the one-shot prompt below into Claude Code once, and Claude creates the four files it needs (memory, roles, loop) and runs the first round with your confirmation. On 2026-10-23 we ran each part on Claude Code 2.1.223 and fixed the errors we found. The results are in "What we checked by actually running it". For the background and the idea behind it, see What is a self-running loop.

Updated 2026-10-23: fixed loop.sh skipping every task after the first, replaced a hook example that blocked nothing, changed how the plan JSON is read, and added when to use /goal plus our test results.

loop.sh or /goal: which to use

If you only need one session to keep working until one completion condition holds, Claude Code's built-in /goal is enough. Use the loop.sh on this page when you want to separate the role that decides from the role that builds, cap the cost of each call, or keep every plan as JSON.

How /goal works is from the official page "Keep Claude working toward a goal" (checked 2026-10-23). Because the evaluator only reads the conversation, both /goal and loop.sh need a task whose completion shows up as a test or build result; otherwise there is nothing to stop on.

First, be clear about where this applies

This works for tasks whose results a machine can verify, such as coding. Three conditions must hold.

Tasks whose right answer is a matter of taste, such as judging prose quality, fail the first condition, so do not put them on this loop.

Just paste this into Claude (one-shot setup)

Copy the whole prompt below and paste it once into Claude Code opened in your target project. Claude creates the memory file, the role agents, and the loop itself, confirms the goal and verification command with one question, then runs the first round. Press "Copy" at the top right to grab the full text.

You are the setup agent that installs a "self-running loop" into this repository.
Create the following four files, then explain how to use them. Each file body is separated by ━━━.

First, ask me exactly one question (if unanswered, proceed with the example values):
- The goal of this loop, in one sentence
- The verification command that checks completion mechanically (tests / build / smoke run)

━━━ File 1: CLAUDE.md (project root) ━━━
# Project assumptions

## What we are building
(1-2 lines. e.g. an internal FastAPI server)

## Rules
- Match the existing code style. No unrequested refactoring
- Minimal changes. Don't touch unrelated files
- No destructive ops (delete, DROP, force push)

## Verification commands (used as the loop's pass/fail check)
- Tests: e.g. pytest -q
- Smoke: e.g. start uvicorn app.main:app --port 8999 & then curl -sf localhost:8999/health

## Off-limits
- app/secrets/ , .env , production config

━━━ File 2: .claude/agents/planner.md ━━━
---
name: planner
description: Decides the next small, independent task toward the goal
tools: ["Read", "Grep", "Glob", "Bash(git log:*)", "Bash(git diff:*)", "Bash(ls:*)"]
model: opus
---
You are the planner. You do not write code.
Inspect the current state of the repo and pick the next independent, small tasks toward the goal (at most 3).
Each task must include a verification command that checks completion mechanically.
If the goal is already met, set done to true.

━━━ File 3: .claude/agents/worker.md ━━━
---
name: worker
description: Implements one task and verifies it before finishing
tools: ["Read", "Edit", "Write", "Bash"]
model: sonnet
---
You are the implementer. You implement only the single task you are given.
After implementing, you must run the given verification command and fix any failures before finishing.
Do not touch files outside scope. Do not claim completion while verification fails.

━━━ File 4: loop.sh (repository root) ━━━
#!/usr/bin/env bash
set -euo pipefail
GOAL="${1:?usage: loop.sh \"<goal in one sentence>\"}"
MAX_ITERS="${MAX_ITERS:-8}"
BUDGET="${BUDGET:-5}"
SCHEMA='{"type":"object","properties":{"done":{"type":"boolean"},"tasks":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"prompt":{"type":"string"},"verify":{"type":"string"}},"required":["title","prompt","verify"]}}},"required":["done","tasks"]}'
for ((i=1; i<=MAX_ITERS; i++)); do
  echo "---- iteration $i / $MAX_ITERS ----"
  envelope=$(claude -p "Goal: $GOAL. Inspect the current state and emit the next independent tasks (at most 3) as JSON. If everything is done, set done:true." --agent planner --output-format json --json-schema "$SCHEMA" --max-budget-usd "$BUDGET") || true
  plan=$(echo "$envelope" | jq -c '.structured_output // empty')
  [ -z "$plan" ] && { echo "No planner output: $(echo "$envelope" | jq -r '.subtype // "unknown"')"; exit 1; }
  [ "$(echo "$plan" | jq -r '.done')" = "true" ] && { echo "Done"; break; }
  echo "$plan" | jq -c '.tasks[]' | while read -r t; do
    prompt=$(echo "$t" | jq -r '.prompt'); verify=$(echo "$t" | jq -r '.verify')
    echo "= $(echo "$t" | jq -r '.title')"
    claude -p "Implement this task: $prompt . When done, you must run this to confirm and fix it if it fails: $verify" --agent worker --permission-mode acceptEdits --max-budget-usd "$BUDGET" < /dev/null
  done
done

━━━ Finally ━━━
List the four files you created and run chmod +x loop.sh.
Then run only the first iteration after confirming with me, and show the result.
Do not run fully autonomously from the start. Keep the cost cap (--max-budget-usd) and iteration cap (MAX_ITERS) in place.

That single paste is all you need.

What this one-shot prompt does

When you paste it, Claude reads the text as "instructions plus embedded file bodies" and creates three things in your project.

After creating them, Claude asks you one question about the goal and verification command, then runs only the first round, with your confirmation. It does not run fully autonomously from the start. The ━━━ markers are file separators and part of the instruction — leave them in when you paste.

What you need to run it

Keeping it running after the first round

Once setup is done, you drive it. Start with ./loop.sh "your goal in one sentence". Cap it with the iteration limit MAX_ITERS and the cost limit BUDGET (USD per call), e.g. MAX_ITERS=3 BUDGET=2 ./loop.sh "...". Press Ctrl-C to stop. A call that hits the cost cap stops slightly past the cap.

What we checked by actually running it (2026-10-23)

Conditions: macOS, Claude Code 2.1.223, jq 1.7.1, an empty git repository. To keep costs down we ran the tests with --model haiku; six calls cost $0.464 in total. This machine's ~/.claude/settings.json already allows the python3 and grep commands, and the results below are under that condition.

The cost cap stops a call after it is exceeded, so a call can spend more than the cap. On this machine the first call wrote about 34,000 tokens to the cache (loading the global settings and CLAUDE.md), which alone went past $0.10. Set BUDGET too low and the planner stops before it answers at all.

For commands your settings.json does not allow, the official page "Run Claude Code programmatically" (checked 2026-10-23) says shell commands still need --allowedTools under acceptEdits. In such an environment, add your verification command to the worker call, for example --allowedTools "Bash(pytest *)".

How it works, piece by piece (for hand-building or customizing)

The sections below explain what the one-shot prompt creates, file by file. The full file bodies are in the one-shot prompt, so here we cover only the decisions that matter.

Step 1: Fix the memory (CLAUDE.md)

What you write in CLAUDE.md at the project root is loaded automatically every session, so every agent in the loop shares the same assumptions. The key is to write the "verification commands" as commands you can actually type. If they are vague, the AI moves on believing it is done. If your project has type checks, add a line such as mypy app/.

Step 2: Split the roles (subagents)

Put one file per role under .claude/agents/ and scope each role's permissions with the tools field in the frontmatter. The planner gets only Read, Grep, Glob, and read-only commands such as git log, so no file changes during planning. The worker gets Edit and Bash and runs the verification command itself. model is opus for the planner and sonnet for the worker. You can drop the worker to haiku to save money; whether that increases the number of fix-and-retry rounds is not something we measured.

Step 3: Run it (the loop runner)

This script has the planner emit the next tasks as JSON, then runs each one through the worker with verification. It stops when done:true comes back or the iteration cap is reached.

#!/usr/bin/env bash
set -euo pipefail

GOAL="${1:?usage: loop.sh \"<goal in one sentence>\"}"
MAX_ITERS="${MAX_ITERS:-8}"      # iteration cap (runaway brake)
BUDGET="${BUDGET:-5}"            # cost cap per call (USD); a call stops after it passes the cap, so it can overshoot a little

# JSON schema that constrains the planner's output
SCHEMA='{"type":"object","properties":{
  "done":{"type":"boolean"},
  "tasks":{"type":"array","items":{"type":"object","properties":{
    "title":{"type":"string"},
    "prompt":{"type":"string"},
    "verify":{"type":"string"}
  },"required":["title","prompt","verify"]}}
},"required":["done","tasks"]}'

for ((i=1; i<=MAX_ITERS; i++)); do
  echo "──── iteration $i / $MAX_ITERS ────"

  # 1) Let the AI decide what to do next (read-only, structured output)
  envelope=$(claude -p "Goal: $GOAL
Inspect the current state and emit the next independent tasks (at most 3) as JSON. If everything is done, set done:true." \
    --agent planner \
    --output-format json \
    --json-schema "$SCHEMA" \
    --max-budget-usd "$BUDGET") || true

  # Schema-conforming output lands in .structured_output; the field is missing when a cap stopped the call
  plan=$(echo "$envelope" | jq -c '.structured_output // empty')
  if [ -z "$plan" ]; then
    echo "No planner output: $(echo "$envelope" | jq -r '.subtype // "unknown"')"; exit 1
  fi
  if [ "$(echo "$plan" | jq -r '.done')" = "true" ]; then
    echo "Goal reached. Exiting."; break
  fi

  # 2) Implement and verify each task, one at a time
  echo "$plan" | jq -c '.tasks[]' | while read -r t; do
    title=$(echo "$t"  | jq -r '.title')
    prompt=$(echo "$t" | jq -r '.prompt')
    verify=$(echo "$t" | jq -r '.verify')
    echo "▶ $title"
    # Without < /dev/null, claude -p reads the remaining task lines and every task after the first is skipped
    claude -p "Implement this task:
$prompt

When done, you must run this to confirm the result and fix it if it fails:
$verify" \
      --agent worker \
      --permission-mode acceptEdits \
      --max-budget-usd "$BUDGET" < /dev/null
  done
done

Usage is one line.

chmod +x loop.sh
./loop.sh "Raise auth test coverage to 80%"

Deciding "what to do" is the planner's job, not yours. What you write shrinks to one sentence of goal, plus the loop itself.

Step 4: Brakes (stop runaways and cost)

Left alone, a loop keeps running and the bill keeps climbing. Stop it three ways.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command",
            "command": "jq -r '.tool_input.command // empty' | grep -qiE 'rm -rf|git push --force|drop table' && { echo 'Blocked a dangerous command' >&2; exit 2; } || exit 0" }
        ]
      }
    ]
  }
}

The old version of this page read the input from an environment variable, $CLAUDE_TOOL_INPUT. According to the official "Hooks reference" (checked 2026-10-23), the input arrives on stdin and no variable by that name exists. With the old example the variable stays empty, so even rm -rf goes through.

Start the worker's permissions at --permission-mode acceptEdits (edits auto, everything else confirmed) and widen to dontAsk or bypassPermissions only once you trust it. Do not reach for --dangerously-skip-permissions.

Copy-paste: instruction prompts

For trying the same flow inside an interactive session, without the script.

Keep going until a condition holds (/goal)

/goal pytest -q passes and git status shows no unintended changes. Stop after 20 turns

Make the planner decide what's next

You are the planner. Do not write code.
Goal: "__your goal__"
Inspect the current state of the repo and list the next independent, small tasks (at most 3),
each with a verification command.
If the goal is already met, just answer "done".

Make the worker implement and self-verify

Implement only the following task (do not touch anything out of scope):
__task__
When finished, run this, paste the result, and fix it if it failed before saying done:
__verification command__

Self-run one round (mini loop)

Run one cycle of "inspect state → decide the next single task → implement → verify".
If verification passes, ask me in one line whether to proceed to the next cycle.
For cost and safety, keep each cycle to a single concern.