Docs & Setup

From zero to a metered, capped, breaker-protected AI budget in a few minutes.

1. Run the proxy
2. Point your AI at it
3. Set budgets
4. The runaway breaker
5. The menu-bar widget
6. Providers
7. Every setting
8. Licence & lost keys

1. Run the proxy

TokenBrake runs on your own machine. One zip, zero dependencies, needs Node 24+. There is deliberately only one download and only one way to start it.

Download: tokenbrake-beta.zip
unzip it into your home folder so it lands at ~/TokenBrake
cd ~/TokenBrake && node proxy.mjs

You should see:

TokenBrake proxy live → http://localhost:8787  (point your AI's base URL here: /openai or /anthropic)
  runaway breaker: GUARD  ·  state: http://localhost:8787/breaker

Confirm it's alive at any time with curl http://localhost:8787/health.

It binds to 127.0.0.1 on purpose. The proxy is reachable only from your own machine. There's no shared secret to set, no port to firewall, and no network surface to get wrong — anyone who can reach it can already read your files.

See the breaker work before you trust it

Two commands, no API keys, no network, no money — both run against the same detection code that guards your traffic:

node demo-runaway.mjs      # simulates one agent stuck 02:00–08:00, nobody awake
node test-runaway.mjs      # 47 detection & breaker tests
node test.mjs              # 100 metering & pricing tests
node test-license.mjs      # 29 licence-verification tests

The demo prints the comparison the whole product exists for: $280.01 with a budget cap alone (23,334 calls, acted after 5.8 hours) versus $3.60 with the breaker (300 calls, tripped in 10 seconds).

2. Point your AI at it

TokenBrake is a drop-in proxy. Change one line — your provider base URL. Your provider API key still passes straight through to the real provider and is never stored.

OpenAI SDK

from openai import OpenAI
client = OpenAI(
    base_url="http://localhost:8787/openai/v1",
    api_key="sk-...your real key...",
    default_headers={
        "x-tokenbrake-agent": "support-bot",   # label this stream
    },
)

Anthropic SDK

from anthropic import Anthropic
client = Anthropic(
    base_url="http://localhost:8787/anthropic",
    api_key="sk-ant-...your real key...",
    default_headers={
        "x-tokenbrake-agent": "content-gen",
    },
)

What's an "agent"? The x-tokenbrake-agent header labels one stream of usage — a bot, a script, a project. Budgets and the breaker are both per agent, so a stuck summariser can be stopped without touching your support bot. Leave the header off and everything from that provider is lumped under the provider's own name.

3. Set budgets

Give each agent a monthly budget and a mode:

node set-budget.mjs support-bot 200 hard
node set-budget.mjs research-bot 50 soft

An agent with no budget set is metered but never capped. Budgets are monthly and reset with the period.

A budget cap is a lagging indicator and always will be — it cannot act until the money is already spent. If your ceiling is $400, a stuck loop will happily spend $400 and then stop. That limitation is exactly why the next section exists. Set budgets anyway; they're the backstop.

4. The runaway breaker

The breaker watches the shape of your traffic rather than the total, so it can act in seconds instead of at the cap. It's on by default.

What it looks for

ReasonWhat triggers it
loop≥80% of a rolling window (up to 60 seconds, minimum 12 calls) is the same request and the rate is ≥20 calls/min. Both, or it isn't a loop — so 12 identical calls in 10 seconds trips it, and a busy hour of varied ones never does.
burnSpend passes $5.00/minute, whatever the pattern.
error_storm≥50% of calls failing at ≥15 calls/min — a retry storm.
surge≥8× this agent's own learned baseline rate, and at least 30 calls/min.

Repetition, not volume, is the primary signal. A stuck agent sends the same request over and over; a legitimate batch job sends a lot of different requests. That asymmetry is the whole design — a fast batch job with 200 varied prompts passes straight through. A false positive that blocks real work costs more trust than a missed loop costs money.

Fingerprinting has two forms: a hash of the whole normalised request, and a hash of the model plus the last message only. The second catches the nastier shape — an agent appending to a growing conversation while asking the same question forever, so every request differs and nothing progresses. Only hashes are kept. Your prompt text is never retained.

It's a circuit breaker, not a kill switch

Closed → open → half-open. After the cooldown it lets exactly one call through to see whether the agent recovered. Recovered, it closes itself. Still stuck, it re-opens and backs off — 60 seconds, then 2 minutes, then 4, up to a 15-minute ceiling. Thirty minutes clean and it forgets the trip count entirely.

That self-healing is what makes it safe to leave switched on: a false trip costs you one cooldown, not a 3am page.

Fail-open is absolute. Every detection path is wrapped. If the breaker itself throws, your call goes through. It cannot take your production down.

Seeing and clearing it

node reset.mjs --status        # what's tripped, why, and for how long
node reset.mjs summariser      # clear one agent
node reset.mjs                 # clear everything

Or read the raw state at http://localhost:8787/breaker, which returns the mode, every agent's state, and the last 20 incidents as JSON.

You should rarely need reset.mjs — a tripped breaker half-opens on its own. It's the manual override for when you know better than it does, which you sometimes will.

Turning it down

TB_BREAKER=watch node proxy.mjs   # detect and log, never block
TB_BREAKER=off   node proxy.mjs   # disable entirely

Watch mode is the honest way to start if you're nervous. Run it for a week against real traffic, read /breaker, and see whether it would have tripped on anything you didn't want stopped. Then turn on guard mode.

5. The menu-bar widget (macOS)

Optional, and macOS-only — the proxy and breaker run anywhere Node does. The widget shows cloud API dollars and local-model electricity in one glance.

brew install swiftbar
# then open SwiftBar and choose ~/TokenBrake/swiftbar as its plugin folder

A 🔥 $… appears in your menu bar. Local models running through Ollama and friends are detected automatically — nothing to configure. Set your electricity rate with TB_CENTS_PER_KWH if 15¢/kWh isn't right for you.

6. Providers

TokenBrake meters eight providers including streaming and prompt caching. Most are OpenAI-compatible — point the OpenAI SDK at the matching path. Gemini uses Google's own wire format, so point the Google GenAI SDK's base URL at …/gemini.

ProviderBase URL to use
OpenAIhttp://localhost:8787/openai/v1
Anthropichttp://localhost:8787/anthropic
xAI / Grok…/xai/v1 or …/grok/v1
Groq…/groq/v1
DeepSeek…/deepseek/v1
Mistral…/mistral/v1
Google Gemini…/gemini (Google GenAI SDK)
OpenRouter…/openrouter/v1 (hundreds of models)
from openai import OpenAI
client = OpenAI(
    base_url="http://localhost:8787/groq/v1",   # or /xai, /deepseek, /mistral, /openrouter
    api_key="...your real provider key...",
    default_headers={"x-tokenbrake-agent": "grok-bot"},
)

The proxy forwards only to this allowlist, and strips any scheme or host a caller tries to smuggle into the path. Anything else is refused rather than fetched.

Pricing is estimated from provider-published rates and rounds up when uncertain, so a cap can't be quietly slipped. It's a safety brake, not a billing system of record — keep your provider-side limits on too.

How we keep the price book honest

A metering tool with stale prices is worse than no metering tool, because it's confidently wrong. So the price table carries the date a human last checked it against every provider's published pricing page, and test.mjs fails once that date is more than 90 days old. You can see both for yourself:

node -e "import('./lib/pricing.js').then(p=>console.log(p.VERIFIED_ON, p.priceBookAgeDays()+' days old'))"

Two known limits, stated rather than buried. Long-context tiers aren't modelled: OpenAI, Gemini and xAI all charge roughly double past a context threshold, and the table holds one rate per model — so very large-context calls under-estimate. Time-of-day pricing isn't modelled either: DeepSeek bills differently at peak and off-peak. Everywhere else the rule holds — when we're unsure, we round up, and an unrecognised model bills at the highest rate we know of rather than a comfortable guess.

7. Every setting

There is no config file. Everything is an environment variable, and every one of them is optional.

VariableDefaultWhat it does
TB_PORT8787Port the proxy listens on.
TB_BREAKERguardguard blocks while open · watch records only · off disables.
TB_BURN_PER_MIN5.00Dollars per minute that counts as a burn, regardless of pattern.
TB_CENTS_PER_KWH15Your electricity rate, for the local-model estimate.

8. Licence & lost keys

TokenBrake is source-available, under PolyForm Small Business 1.0.0. It's free to use — including at work — for individuals and for any company under 100 people and under $1M revenue. That covers almost everyone, and nothing is held back in the free version: no trial clock, no locked features, no key to enter.

Companies above that threshold buy one commercial licence, once — $249, one company, unlimited machines and agents, no renewal. Pricing has the details.

Redeeming a purchase

Buy on Gumroad, and you'll get a licence key on the receipt and by email. Paste it at tokenbrake.com/get and you'll get your TokenBrake key straight back. Set it as TB_LICENSE and restart:

TB_LICENSE="TB-…" node proxy.mjs

TokenBrake proxy live → http://localhost:8787
  runaway breaker: GUARD
  commercial licence: VALID · business · ref 9f2a1c4e7b8d · perpetual

It also appears at /health, as JSON, so you can point a monitoring check or an auditor at it.

Be clear about what that key is — it's proof, not a lock.

Nothing in TokenBrake is gated behind a licence. Every feature works in the free version, and the key is never consulted while your traffic is flowing. Setting it changes one line of startup output and one field in /health, and nothing else. An unlicensed install and a licensed one behave identically.

That is on purpose. This software sits in front of your production API calls. The day it starts refusing work over a licensing question is the day it stops being safe to install — so it never will. We would rather a company that owes us $249 quietly not pay than have one that did pay get woken at 3am by our licence check.

What the key gives you is the thing a company over the threshold actually needs: something verifiable to show that your use is licensed.

Lost your key?

Paste the same Gumroad key again. Your TokenBrake key is derived from your purchase rather than looked up in a database, so the same purchase always returns the same key. There is no support ticket to raise and no account to recover.

Verification is offline and permanent. The key is signed with Ed25519; TokenBrake carries only the public half, which can check a signature and never create one. So verification needs no network, ever — and your licence keeps working whether or not we're still here. Gumroad is the till, not the lock.

HomePricingFAQTermsPrivacy

Still stuck? Email willbgreen777@gmail.com — a Northjule product.