burnclock / AI budget visibility Live on PyPI

Know how long your AI budget lasts.

Your providers will tell you what is left. They will not tell you how long it lasts. burnclock reads their balances and your own usage records, then shows burn per day, days of paid runway, and the date your budget runs out.

Install from PyPI See the table

Free and open source, MIT licensed. Python 3.12+. Read-only: burnclock never tops up, spends, or changes anything on a provider account.

  • 6providers
  • 1command
  • 0writes
The burnclock dial showing an example reading of 7.0 days of runway, with a 42.80 dollar balance and 6.10 dollars burned per day

The gap

A balance is not a runway.

A number in a console tells you what remains. It does not tell you what happens next.

01 / SCATTER

Six consoles, six numbers

DeepSeek, OpenRouter, Moonshot, xAI, MiniMax, and fal each keep their own balance page. You check them one at a time, usually after something stalls.

02 / RATE

The rate is the missing half

Forty dollars is two days at twenty a day, or two weeks at three a day. The balance alone cannot tell you which one you are looking at.

03 / FAILURE

A revoked key reads like zero

If the only check is a balance, a dead key and an exhausted account look the same. One needs a new key. The other needs money.

04 / ANSWER

One table, three answers

Balance, burn per day, days of paid runway, and the projected date your monthly budget line is crossed. Per provider, from the numbers your own account returns.

The command

One command, one honest table.

Run it with no arguments. burnclock prints every configured provider and stops guessing.

$ burnclock

┌────────────┬───────┬───────────┬──────────┬───────────────┐
│ Provider   │ State │ Balance   │ Burn/day │ Runway (paid) │
├────────────┼───────┼───────────┼──────────┼───────────────┤
│ DeepSeek   │ OK    │ 42.80 USD │ 6.10     │ 7.0 d         │
│ OpenRouter │ EMPTY │ -0.09 USD │ 8.08     │ -             │
└────────────┴───────┴───────────┴──────────┴───────────────┘

$ burnclock badge
DeepSeek $42.80 · 7.0d
$ burnclock

DEEPSEEK      OK
  balance     42.80 USD
  burn/day     6.10
  runway       7.0 d

OPENROUTER    EMPTY
  balance     -0.09 USD
  burn/day     8.08
  runway       -

$ burnclock badge
DeepSeek $42.80 · 7.0d
Example output from a synthetic account. Real readings come from your own keys and local usage records.

What the columns say

  • STATEOK, LOW, CRITICAL, EMPTY, KEY_REJECTED, PERMISSION_DENIED, NO_API, NOT_QUERYABLE, ERROR, or UNREACHABLE.
  • BALANCEThe provider's own number, in its own currency. Never estimated from spend.
  • BURN/DAYComputed from your usage records. It is your actual rate, not a price list.
  • RUNWAYPaid days left at that burn. A dash when the provider cannot support the calculation.

If a provider cannot answer, its row says so. burnclock never turns a failed request into a zero balance.

What you get

Built for the question, not the dashboard.

A small tool with a narrow job: tell you where the budget stands, and make the answer usable in a terminal, a prompt, or a script.

Runway

Runway with a date

Balance, burn per day, days of paid runway, and the projected date your monthly budget line is crossed. Set a monthly budget per provider; preview any change with --dry-run before it writes.

Budgets are optional. Without one, burnclock still reports balance, burn, and runway; the budget line only adds a crossing date.

Failure

Dead keys, named

A rejected key is not an empty account. Distinct states tell you whether to rotate a key, fix a scope, or add funds.

KEY_REJECTED PERMISSION_DENIED EMPTY UNREACHABLE

Each state has a different next action. The table never collapses them into one error.

Surfaces

Where you already look

A one-line badge for zsh, tmux, or the Hermes desktop status bar. It reads a cached file, so your prompt never waits on a network call.

~/.cache/burnclock/badge.txt DeepSeek $42.80 · 7.0d

Automation

Built to be scripted

status --json returns a stable envelope. Exit codes separate internal errors, usage, config, auth, threshold, and unreachable, so cron jobs and agents can act on the result.

--json --min 25 --min-days 3 exit 4 = auth

Coverage

Six providers today. The edges are explicit.

Two balance APIs are verified against live accounts. Four more are documented and ship disabled until their response shapes are verified. Nothing is guessed.

Providers, balance sources, and verification status
ProviderBalance sourceVerification
DeepSeekGET /user/balanceLive-verified
OpenRouterGET /api/v1/key + /creditsLive-verified
MoonshotGET /v1/users/me/balanceDocumented, off by default
xAIManagement API prepaid balanceDocumented, off by default
MiniMaxaccount/query_balance or token_plan/remainsDocumented, off by default
falaccount/billingDocumented, off by default

Providers without a balance API still get an honest row: NO_API for spend-only records, NOT_QUERYABLE for console-only accounts. A failed request is ERROR or UNREACHABLE, never $0.

Why it exists

Built for our own burn.

We run agent fleets on metered APIs. The question that kept interrupting the work was not "what is my balance?" It was "how many days does this budget have left?" The consoles answered the first question and left the second one to arithmetic, at the worst possible moment.

burnclock started as a local script that read provider balances, joined them to the usage records Hermes already kept, and printed one table. It ran on the same machine as the agents. It still does.

The rules came from that use: never write to a provider, never store a key in config, and never turn a failed request into a number. The output is an estimate, and it says so.

Top up on purpose, not in a panic.

Install burnclock, point it at the keys you already use, and see your real runway in one command.

Install with pipx

$ pipx install burnclock

or: uv tool install burnclock

Install from PyPI

Free and open source. Estimates, not billing truth.