
Stop Runaway Agent Bills: Use --max-turns and total_cost_usd to Cap and Track Every Claude Code Run
Chris Harper
3 min read
Jul 10, 2026 · 20:05 UTC
TL;DR: --max-turns N exits the agent loop after N turns so it can't spiral; --output-format json returns total_cost_usd in the result so you know exactly what every automated task cost — wire them together and your CI never surprises you with an unexpected bill.
Running Claude Code headlessly in a pipeline is powerful, but two failure modes bite teams early: (1) the agent gets stuck retrying a bad approach and burns through turns and tokens, and (2) nobody knows what any individual task cost until the monthly invoice arrives. Two flags fix both.
--max-turns — the hard stop
claude -p "refactor the payment module" \
--max-turns 10 \
--output-format json \
--allowedTools Edit,Read,Bash \
--permission-mode dontAsk
--max-turns 10 means the agent completes at most 10 turns (a tool call + response counts as one turn). When the limit hits, Claude summarizes what it completed and exits — it doesn't leave you with partial, half-applied edits. Good defaults by task type:
| Task | --max-turns |
|---|---|
| Single-file refactor | 5–8 |
| Multi-file feature | 10–15 |
| Security scan / read-only analysis | 3–5 |
| Open-ended research | 20+ |
Too low and Claude can't finish; too high and a confused agent runs up cost. Start conservative and tune up.
total_cost_usd — per-task spend tracking
With --output-format json, the envelope Claude prints to stdout includes the cost field:
result=$(claude -p "write unit tests for auth.ts" \
--max-turns 8 \
--output-format json \
--allowedTools Read,Bash,Write \
--permission-mode dontAsk)
cost=$(echo "$result" | jq -r '.total_cost_usd')
session=$(echo "$result" | jq -r '.session_id')
text=$(echo "$result" | jq -r '.result')
echo "Session $session | Cost: \$${cost}"
echo "$text"
A cost-alert wrapper
#!/usr/bin/env bash
# agent-run.sh — run a Claude Code task with cost ceiling
PROMPT="$1"
MAX_TURNS="${2:-10}"
ALERT_THRESHOLD="${3:-0.25}" # alert if task exceeds $0.25
result=$(claude -p "$PROMPT" \
--max-turns "$MAX_TURNS" \
--output-format json \
--permission-mode dontAsk 2>&1)
cost=$(echo "$result" | jq -r '.total_cost_usd // "0"')
if (( $(echo "$cost > $ALERT_THRESHOLD" | bc -l) )); then
echo "COST ALERT: \$${cost} exceeds threshold of \$${ALERT_THRESHOLD}" >&2
fi
echo "$result" | jq -r '.result'
Usage: ./agent-run.sh "review the PR for security issues" 5 0.10
Logging for cost attribution
For CI pipelines, log session_id and total_cost_usd to your observability tool (Datadog, Grafana, or even a flat log file). After a week you'll see which task types cost most and can tune --max-turns accordingly. A task that should take 3 turns but is configured for 20 will keep finding new ways to spin.
Sources: Run Claude Code programmatically — Claude Code Docs · Claude Code CI/CD Automation Guide — hidekazu-konishi.com · Claude Code Headless Mode CI/CD Playbook — Code With Seb