Budget Caps

Stop runaway AI agent spend before it happens. Set a daily cap and let RelayPlane handle the rest.

What Budget Caps Do

AI agents can rack up hundreds of dollars in API costs in a single session. A bug in a loop, an unexpected context explosion, or a forgotten background process can drain your budget overnight. RelayPlane's budget cap tracks spend in real time and enforces a daily limit at the proxy: block, downgrade, or warn, your choice, before costs spiral.

Set a Daily Cap

One command. It writes the budget block below into ~/.relayplane/config.json, and a running proxy reloads it within seconds:

1relayplane cap set --day 10

The same thing by hand, which is also the only config schema the proxy reads for budgets:

1// ~/.relayplane/config.json
2{
3 "budget": {
4 "enabled": true,
5 "dailyUsd": 10, // hard daily limit in USD (API-equivalent cost)
6 "dailyCapUSD": 10, // the same number the BudgetTracker reads; cap set writes both
7 "onBreach": "block" // "block" | "warn" | "downgrade"
8 }
9}

Or set it for one run with an environment variable:

1RELAYPLANE_DAILY_CAP_USD=10 relayplane start
The cap is checked before a request is forwarded, using the prompt size at the target model's price. The request that would push today's spend past the cap is the one that gets blocked, not the one after it.

From the Dashboard

The local dashboard at localhost:4100/dashboard has the same controls under guardrails: daily cap, on-breach action, and the KILL button, which halts all routed traffic (see below). Changes persist to the config file and take effect immediately.

Verifying Your Budget

relayplane budget status asks the running proxy what it is enforcing right now:

1$ relayplane budget status
2
3šŸ’° Budget Status (live proxy on :4100)
4 Enabled: āœ…
5 Daily: $3.4200 / $10 (34.2%) āœ… ok
6 Hourly: $0.1200 / $10 (1.2%)
7 On breach: block

The same numbers are at GET /control/budget, and per-day history with a per-model breakdown at relayplane budget history.

What Happens When the Cap Triggers

RelayPlane applies budget.onBreach:

block (what cap set writes)

The request is not forwarded. The client gets 429 with body { "type": "budget_exceeded", "error": "Budget limit exceeded. Request blocked." } and header x-relayplane-budget-exceeded: daily-cap. Each block is recorded as a kill (relayplane kills). Use this when any overage is unacceptable.

downgrade

The request goes through on a cheaper model from the configured ladder (budget.ladder / downgrade in config). Agents keep running at reduced cost.

warn

The request goes through unchanged. A breach alert fires and the dashboard shows the overage. This is an anomaly ceiling, not a hard stop.

Caps hold under concurrency. Each admitted request reserves its estimated cost (prompt plus its max_tokens, up to 4096 output tokens) before it is forwarded, so requests in flight count against the daily, hourly, per-session and per-run caps straight away. The reservation becomes the real cost when the response lands and is released if the call fails or the client disconnects.

Caps count API-equivalent cost. Claude Code Max plan traffic is flat-rate, so for Max-only installs the cap is an anomaly ceiling rather than a real-money limit. Real money is protected on API-key and OpenRouter traffic.

Halting Everything

A cap limits spend. The kill switch stops it:

1relayplane kill # every /v1 request now gets 503 kill_switch_active, nothing is forwarded
2relayplane resume # lift it
3
4# same thing over HTTP (and what the dashboard KILL button calls)
5curl -X POST localhost:4100/control/kill -d '{"all":true}'
6curl -X POST localhost:4100/control/resume

relayplane disable is different: it turns routing off and puts the proxy in passthrough, so traffic still flows to your providers and still costs money.

Next Steps