How do I set a spend limit for Claude Code or Codex on my own API key?
Run npx github:henrikdukefoss/runawayguard --limit 5 --upstream anthropic, then start your agent in a second terminal with its base URL set to http://127.0.0.1:8402. The small local proxy prices every response at API list prices and answers new requests with HTTP 402 once $5 is spent, so the agent stops.
$ npx github:henrikdukefoss/runawayguard --limit 5 --upstream anthropicSource on GitHub ↗Node 18 or newer, no dependencies, no account.
Made by Standard Compute. Plans from $19/mo →
$ npx github:henrikdukefoss/runawayguard --limit 1.50 --upstream anthropic --offline
runawayguard 0.1.0
proxy http://127.0.0.1:8402 -> https://api.anthropic.com
limit $1.50 per session, warning at $1.20, then HTTP 402
prices LiteLLM (bundled), 2026-10-13
Point your agent at the proxy, for example:
Claude Code ANTHROPIC_BASE_URL=http://127.0.0.1:8402 ENABLE_TOOL_SEARCH=true claude
Ctrl+C stops the proxy and prints a summary.
14:02:08 claude-haiku-5-5 812 in 38 out $0.0001 $0.00 0%
14:02:17 claude-opus-5-5 40.6K in 1.8K out $0.2376 $0.23 15%
14:02:58 claude-opus-5-5 48.1K in 2.3K out $0.1019 $0.33 22%
14:03:35 claude-opus-5-5 60.7K in 3.9K out $0.1536 $0.49 32%
14:04:27 claude-opus-5-5 66.9K in 1.2K out $0.0688 $0.56 37%
14:04:31 claude-haiku-5-5 1.5K in 61 out $0.0002 $0.56 37%
14:05:37 claude-opus-5-5 81.9K in 4.5K out $0.1794 $0.74 49%
14:06:15 claude-opus-5-5 90.5K in 2.8K out $0.1166 $0.85 57%
14:07:26 claude-opus-5-5 106.8K in 5.1K out $0.2033 $1.06 70%
14:08:10 claude-opus-5-5 116.2K in 3.3K out $0.1362 $1.19 79%
14:09:08 claude-opus-5-5 130.0K in 4.9K out $0.1912 $1.38 92%
runawayguard: over 80% of the $1.50 session limit used.
14:09:43 claude-opus-5-5 137.8K in 3.0K out $0.1263 $1.51 101%
runawayguard: $1.50 session limit reached. New requests are blocked with HTTP 402.
runawayguard: blocked POST /v1/messages (HTTP 402).npm run sample: a local fake API with made-up usage, shown as api.anthropic.com. No real requests were made. Swipe sideways for full lines.Point your agent at the proxy
Anthropic clients take the base URL without /v1, OpenAI clients with it. Start runawayguard with the --upstream shown on each tab.
$ ANTHROPIC_BASE_URL=http://127.0.0.1:8402 ENABLE_TOOL_SEARCH=true claudeClaude Code turns MCP tool search off for any base URL other than api.anthropic.com, so ENABLE_TOOL_SEARCH=true turns it back on. Settings checked against each agent's docs or source in October 2026. Roo Code, Aider and Pi are in the README.
What happens at the limit?
The limit is checked before each request. Once it is reached, new requests to /v1/messages, /v1/chat/completions and /v1/responses get this answer, here with --limit 5, and are never sent upstream.
{
"type": "error",
"error": {
"type": "spend_limit_reached",
"code": "spend_limit_reached",
"message": "runawayguard: $5.00 session limit reached ($5.03 spent). Restart runawayguard with a higher --limit to continue."
}
}Anthropic and OpenAI clients both read the body as an error. The official SDKs obey x-should-retry: false and do not retry a 402 on their own. Model lists and count_tokens still pass, and Esc in Claude Code cancels the upstream request too.
What leaves your machine?
- Requests
- From your agent to runawayguard on 127.0.0.1, then to the upstream you chose. The only other request fetches LiteLLM's public price list, at most once a day.
--offlineskips it. - API keys
- Forwarded as they are. Never stored, printed or logged.
- Prompts and responses
- Never written anywhere. Each response is read in memory for its usage numbers, then dropped.
--logfile- Time, method, path, status, model, token counts and cost per request. Nothing else.
What it does not catch
- Unpriced models
- A model missing from the price list is counted in tokens but adds $0 to the limit, with a notice the first time. A response without usage is not counted either. Prices are never guessed.
- Requests in flight
- Allowed to finish, so the total can end a little above the limit, as in the sample: $1.51 of $1.50.
- Not supported yet
- WebSocket transports, which it refuses, the Gemini API, Bedrock and Vertex endpoints, and batch APIs. Requests to other paths pass through unmetered.
- One upstream
- Each proxy forwards to one API. Run two on different ports for Anthropic and OpenAI.
Options
| Option | What it does |
|---|---|
--limit <usd> | Stop at this many dollars, for example 5 or 12.50. Required unless --dry-run |
--upstream <url> | The API to forward to. anthropic, openai and openrouter are shortcuts for their API URLs |
--per <period> | session (default): since runawayguard started. day: the local calendar day, kept across restarts |
--warn-at <ratio> | Print a warning at this share of the limit, default 0.8. 0 turns it off |
--port <n> | Local port, default 8402. 0 picks a free one |
--log <file> | Append one JSON line per request with model, token counts and cost |
--dry-run | Meter and warn, never block |
--offline | Use the bundled price table and download no prices |
--no-color | Plain terminal output |
The proxy listens on 127.0.0.1 only and writes everything to stderr. Ctrl+C stops it and prints the summary.
Questions
Does the limit work with a Claude Pro or Max login?
The traffic still goes through the proxy, but it is billed to your subscription, not at the list prices runawayguard shows. The limit is meant for API-key billing: set ANTHROPIC_API_KEY before you start Claude Code.
Why does Codex need a config.toml entry instead of OPENAI_BASE_URL?
Codex ignores OPENAI_BASE_URL. Its built-in openai provider has an openai_base_url setting, but it tries a WebSocket connection first, which runawayguard refuses because it cannot meter it, and Codex falls back to HTTP only after its retries. A provider entry with wire_api = "responses" uses HTTP streaming from the start.
Can I set a daily limit instead of one per session?
Yes, add --per day, for example npx github:henrikdukefoss/runawayguard --limit 20 --per day --upstream openai. The day's total is kept in ~/.local/state/runawayguard/spend/ and survives restarts. Every runawayguard on the machine adds to the same day, so an Anthropic and an OpenAI proxy share one daily budget. It resets at local midnight.
How close is the total to my provider's bill?
runawayguard reads the usage each response reports and prices uncached input, output, cache reads and 5-minute and 1-hour cache writes at their own LiteLLM list rates, with long-context rates over the model's threshold. Discounts, credits, batch pricing and server-side tool fees such as web search are not applied. Your provider's invoice is the final word.
Does it work with OpenRouter or Aider?
OpenRouter, yes: use --upstream openrouter. Aider through a proxy streams OpenAI-style chat completions without asking for usage, so runawayguard cannot price them and says so. Use Aider with an Anthropic model through ANTHROPIC_API_BASE, or add stream_options.include_usage in .aider.model.settings.yml as the README shows.
Already on a flat plan?
Standard Compute, which makes runawayguard, sells flat monthly plans that stop at a compute budget on the server with the same HTTP 402, so you may not need a local limit.