[FEATURE]: per-session spend cap for interactive sessions (--max-budget-usd is print-mode only)
What
Interactive sessions have no way to cap cumulative spend or token usage. The caps that do exist — --max-budget-usd, --max-turns / CLAUDE_CODE_MAX_TURNS — work only for non-interactive (claude -p) runs. In an interactive session, the per-request env vars (MAX_THINKING_TOKENS, CLAUDE_CODE_MAX_OUTPUT_TOKENS) bound a single request, auto-compact frees context but not spend, account-level spend limits pause the whole account rather than one session, and /usage / statusline / OTEL only report.
Market precedent: Codex CLI already ships a per-session budget
OpenAI Codex has features.rollout_budget in config.toml:
[features.rollout_budget]
enabled = true
limit_tokens = 100000
reminder_at_remaining_tokens = [50000, 25000, 10000]
sampling_token_weight = 1.0
prefill_token_weight = 1.0
From the implementation (openai/codex → codex-rs/core/src/rollout_budget.rs) and the published config reference:
- Token-weighted (
output × sampling_token_weight + non-cached input × prefill_token_weight), not USD — Codex has no dollar budget either; cost metrics in the TUI are an open request (openai/codex#38721). - Flag-gated, marked "under development" by
codex features list. - Soft: reminders injected into the conversation at thresholds; on exhaustion only a signal to the caller — no tool-call denial, no session stop. Runaway burn still happens there (openai/codex#41831: 1.26M tokens in 12 no-op turns).
- Its published config reference lags the implementation (openai/codex#36705 — the documented key doesn't even parse).
| | print-mode cap | interactive per-session cap | hard stop |
|---|---|---|---|
| Claude Code | --max-budget-usd (USD) | none | — |
| Codex CLI | — | features.rollout_budget (tokens, flag-gated) | soft reminders only |
Interactive stuck tool loops make this gap expensive on both platforms (openai/codex#41831; same failure mode reported here as #82104). Claude Code's --max-budget-usd is already a stronger primitive than Codex's token weights — it just isn't reachable interactively.
Current workaround
A custom PostToolUse hook that parses transcript_path, sums accumulated usage from the JSONL, and emits {"continue": false} at a threshold. It works, but every user re-implements the same transcript parser just to compare one number against a threshold — the very number --max-budget-usd already tracks in print mode.
Ask
- Interactive parity for the budget machinery — a flag, setting, or env var (e.g.
CLAUDE_CODE_MAX_SESSION_BUDGET_USD, or accepting--max-budget-usdinteractively). On reaching the cap, stopping the session — or requiring explicit user confirmation to continue — both seem reasonable. A hard stop or human-in-the-loop gate would also go one step beyond Codex's soft reminders. - Or/and: include cumulative session cost and token totals in hook input, so threshold hooks don't need to re-parse the transcript on every call.
Environment
- Claude Code 2.1.278, macOS (Darwin 25.6.0)
Related open issues: #85422 (token-burn circuit breaker — broader design; this ask is the narrower "reuse the existing print-mode cap interactively"), #73307 (loop permission gate), #82104 (runaway subagent burn after kill).
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
One thing I found building in this area: a hook can't enforce this in interactive sessions, because hooks see tool calls and never the model calls where the tokens go. What I could do was measure it. I wrote a replay that reads Claude Code's session files and prices every response, and on two months of my own sessions the costliest single session came to about $450 at API list prices. Knowing that number per session is most of what a cap needs.
What limit would you set: tokens, dollars or turns, and per session or per day?
It is depends on the developer. To limit somehow is better then none.
Agreed. If I had to pick one default, it would be dollars per day: it's the number that shows up on the bill, and a day is short enough that a runaway loop costs you a day, not a month.