Skip to content
zero2vibecodelearn vibe coding
Level 3 · Autopilot 8 min Reviewed by the author · Oct 15, 2026 Verified against Claude Code v2.1.292 · Oct 15, 2026Official docs: CLI reference, HeadlessSomething out of date? Tell us

Unattended runs with limits

An unattended run does only what you allowed in advance. So allow little and limit the rest — minimal permissions, a strict sandbox, turn and budget caps, no commits, and a cost estimate on a small slice.

Level 3 · 0 / 4 lessons0%
In this lesson

In the last lesson you ran Claude from a script. Now — a run that works unattended, for a long time, editing files. The core principle: a run like this does exactly what you allowed in advance. So allow little, and limit the rest.

Five limits

  1. Minimal permissions. The dontAsk mode denies anything that would have needed a question. Allow only the folders the task edits and the one command it runs.
  2. The sandbox. Let the system limit what the allowed commands can do — and do not let the run start if the sandbox is unavailable.
  3. Caps. --max-turns caps the turns, --max-budget-usd the approximate cost.
  4. A review gate. Deny git commit and git push. The result stays in the working tree, and you commit — after reading the diff.
  5. A cost estimate. First run a small slice of the task, and set the budget limit from that.

The limits file

It is handy to keep the limits in a separate file, for example .claude/bounded-run.json:

{
  "permissions": {
    "allow": ["Edit(./src/**)", "Edit(./test/**)", "Bash(npm test *)"],
    "deny": ["Agent", "Read(./.env)", "Read(./.env.*)", "Bash(git commit *)", "Bash(git push *)"]
  },
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "allowUnsandboxedCommands": false
  }
}
  • a deny on Agent stops Claude from handing work to a , which might have its own permission mode;
  • failIfUnavailable — do not start without the sandbox;
  • allowUnsandboxedCommands: false — do not retry a command outside the sandbox.

The run

claude -p "Add a test for one uncovered function in src/links.js" \
  --setting-sources project \
  --settings .claude/bounded-run.json \
  --permission-mode dontAsk \
  --model sonnet \
  --max-turns 15 \
  --max-budget-usd 2 \
  --output-format json

--setting-sources project leaves out your personal settings — for example, a permission saved with “Yes, and don’t ask again”. Only what you explicitly wrote into the limits gets in.

When a limit is hit, the exit code is non-zero, and subtype in the JSON explains why: error_max_turns or error_max_budget_usd. The total_cost_usd field is a client-side estimate, not your bill.

You are the review gate

After the run, read git status and git diff, including the limits file itself, run the tests yourself, and commit only what you accept. For a second opinion, ask a fresh Claude session to review the diff in a clean context.

Quick check

The run finished with subtype success and green tests. Can you push straight away?

Careful

Practice in the terminal

Limits in a minute

Check your understanding

Answered 0/3
Mode:

Why deny git commit and git push in the rules for an unattended run?

What is a sensible way to choose --max-budget-usd for a big task?

Why set failIfUnavailable to true in the sandbox settings for a run like this?

Finish the task in the terminal and answer the questions to complete the lesson.

📝 My notes

Saved automatically in this browser · shows up on the Notes page.

Task

Make sure a limit really stops a run: start a task with --max-turns 1 and look at why it stopped. Then run the same task with sensible turn and budget limits.

Tab complete · ↑ history · Ctrl+L clear · help commands

  • Not done: The turn limit stopped the run
  • Not done: A run with a budget limit
  • Not done: The run within the limits finished successfully

Lesson Q&A

Why deny git commit and git push in the rules for an unattended run?

That is the review gate — you read the diff yourself and commit only what you accept — Denying commit and push keeps the last step with you: the run's result sits in the working tree, and only what you have reviewed goes into history.

What is a sensible way to choose --max-budget-usd for a big task?

Run a small slice of the task first, see what it costs, and scale up with headroom — Running a slice gives you a real estimate. Multiply it by the size of the task and leave headroom — then the limit neither cuts the work short nor lets the budget run away.

Why set failIfUnavailable to true in the sandbox settings for a run like this?

So that if the sandbox cannot start, Claude Code refuses to run rather than working without it — By default, without a sandbox, commands simply run unprotected. For an unattended run it is better to fail than to quietly work without the boundary.

The run finished with subtype success and green tests. Can you push straight away?

Green tests do not tell you the changes are right. The review gate is you: read the diff, decide, commit. Push was denied by the limits on purpose.

Commands in this lesson

Terms in this lesson

Move between lessons with ← → · search with ⌘K

Written and reviewed by Mikhail Kuzmitskii