Real-time budget monitor dashboard for Claude Code token usage
Project description
BudMon — Budget Monitor for Claude Code
Real-time desktop dashboard that monitors your Claude Code token usage, quota utilization, burn rate, and costs.
Why BudMon?
Claude Code users on the Max plan have a token budget that resets every 5 hours and every 7 days. Exceeding the budget means being rate-limited or blocked. The problem: Claude Code shows no real-time feedback on how fast you are consuming your budget.
BudMon fills this gap. It captures the rate-limit headers from every API response and visualizes them as a live dashboard. You can see at a glance:
- How much of your 5h and 7d quota is used
- How fast you are burning through it
- When the quota resets
- Whether you will run out before the reset
- How much you are spending in dollars
BudMon runs as a standalone window alongside Claude Code. It requires no API keys, no network access, and no external services. All data is read locally from files that Claude Code writes during operation.
Features
- 5h / 7d Quota Bars — progress bars with configurable warning (default 75%) and alarm (default 90%) thresholds
- Burn Rate — consumption rate in %/hour (5h) or %/day (7d), color-coded
- Expiry Estimate — predicted time when the quota runs out, with date for 7d
- Reserve — time difference between predicted expiry and next reset (positive = safe, negative = will run out)
- Countdown Ring — circular timer showing either time to reset or time to expiry (whichever comes first)
- Last Request / Total Requests — token breakdown per turn and cumulative (input, output, cache create, cache read)
- Cost Display — dollar cost per request and cumulative, based on model-specific token prices
- Cache Ratio Sparkline — historical graph of cache hit ratio with average
- Multi-language — German and English, switchable at runtime, auto-detects system language
- Model Presets — Opus, Sonnet, Haiku token prices, or custom
- Dark Theme — terminal-inspired dark color scheme, consistent across all UI elements
- HiDPI / 4K Support — automatic DPI scaling on Windows, Linux, and macOS
- Window Position Memory — remembers its last position, reopens there (with screen bounds check)
- Configurable — all thresholds, prices, language, and refresh rate via INI file
Supported Platforms
| Platform | Status | Notes |
|---|---|---|
| Linux (X11) | Full support | Primary development platform. Tested on Ubuntu 24.04. |
| Linux (Wayland) | Should work | tkinter runs under XWayland. Screenshot tools may differ. |
| macOS | Should work | Retina scaling handled natively by tk. |
| Windows | Should work | DPI awareness via ctypes/shcore. Wrapper is .cmd instead of shell alias. |
Requirements
- Python 3.10+ with tkinter
- Claude Code (CLI version, installed via npm)
- Node.js (comes with Claude Code)
Installing tkinter
tkinter is included with most Python installations. If missing:
| OS | Command |
|---|---|
| Ubuntu / Debian | sudo apt install python3-tk |
| Fedora | sudo dnf install python3-tkinter |
| Arch | sudo pacman -S tk |
| macOS (Homebrew) | brew install python-tk |
| Windows | Reinstall Python with "tcl/tk" option checked |
Installation
From PyPI (recommended)
pip install budmon
From source
git clone https://github.com/weilhalt/budmon.git
cd budmon
pip install .
Development install
git clone https://github.com/weilhalt/budmon.git
cd budmon
pip install -e .
Setup
BudMon needs a small interceptor to capture rate-limit data from Claude Code's API responses. Run the setup once after installation:
budmon --setup
This does three things:
-
Installs the interceptor (
~/.claude/budmon-interceptor.mjs) — a read-only Node.js fetch wrapper that captures response headers and token usage. It never modifies outgoing requests. -
Creates the
claude-budmoncommand:- Linux/macOS: shell alias in
.bashrc/.zshrc+ wrapper in~/.local/bin/ - Windows:
.cmdwrapper in a PATH directory
- Linux/macOS: shell alias in
-
Creates a desktop entry (Linux only) so BudMon appears in your application menu.
If you already have an interceptor
If you are already using cache-fix-preload.mjs or a similar community
interceptor that writes ~/.claude/usage-limits.json, BudMon will detect
it automatically. No additional setup needed — just run budmon.
Usage
Step 1: Start Claude Code with the interceptor
claude-budmon
This is identical to running claude, but with the interceptor loaded.
Use it exactly as you would use claude — all arguments are passed through.
Step 2: Start the dashboard
In a second terminal (or from your application menu):
budmon
The dashboard opens and starts polling for data every second. On first start without data, it will offer to run the setup automatically.
Day-to-day workflow
- Always start Claude Code via
claude-budmoninstead ofclaude - Start
budmonwhenever you want to monitor your budget - BudMon runs independently — you can start and stop it at any time
What each display shows
Quota Bars (5h and 7d)
Two horizontal progress bars showing your current quota utilization as a percentage. Threshold markers at the configurable warn and alarm levels.
- Green — below warning threshold (default <75%)
- Yellow — between warning and alarm (default 75-90%)
- Red — above alarm threshold (default >90%)
Reset
The time when your quota window resets, with a countdown. For 7d, includes the date (e.g. "Fri. 04.04. 13:00").
Expiry
Estimated time when your quota will run out at the current burn rate. Shown in cyan (normal), yellow (warning), or red (alarm).
Reserve
The difference between expiry and reset. Positive means you have time to spare. Negative means you will hit the limit before the reset.
- +2 h 30 min — safe, 2.5 hours of headroom
- -45 min — will run out 45 minutes before reset
Burn Rate
Your consumption speed. For 5h: percent per hour. For 7d: percent per day. Displayed in white text.
Countdown Ring
A circular timer positioned over the 5h quota bar. Shows either:
- RESET (green) — counting down to quota reset
- EXPIRY (yellow/red) — counting down to quota exhaustion (if earlier than reset)
Last Request / Total Requests
Two columns showing token breakdown:
- Requests — number of API turns
- Since — when the session or tracking started
- input — input tokens (user messages, system prompts)
- output — output tokens (assistant responses)
- cache_c — cache creation tokens (first time a prompt is cached)
- cache_r — cache read tokens (subsequent uses of cached prompts)
- Cost — dollar amount based on model prices
Cache Ratio Sparkline
A line graph showing the historical cache hit ratio. Higher is better (and cheaper).
- The current ratio is shown as a large percentage
- The average is shown next to it
- A dashed line marks the 50% threshold
- The dot at the end of the line is color-coded (green/yellow/red)
CLI Options
budmon Start the dashboard
budmon --setup Install the Claude Code interceptor
budmon --uninstall Remove the interceptor and aliases
budmon --statusline Output for Claude Code status line
budmon --statusline on Activate status line in Claude Code
budmon --statusline off Deactivate status line
budmon --version Show version number
budmon --help Show usage information
Status Line
BudMon can display a compact status line at the bottom of Claude Code, showing quota usage, burn rate, and costs — using the same data and calculations as the GUI dashboard.
Activate
budmon --statusline on
This writes a statusLine entry to ~/.claude/settings.json. Restart
Claude Code to apply.
Deactivate
budmon --statusline off
Configure
The status line elements, their order, and the maximum width are
configurable in ~/.claude/budmon.ini:
[statusline]
# Elements shown left to right. Those that don't fit are dropped.
elements = cwd, model_info, 5h_bar, 7d_bar, countdown_5h, reserve
# Maximum character width
max_width = 80
Available elements:
| Key | Example | Description |
|---|---|---|
cwd |
~/.DEV/.BUDMON |
Working directory |
model_info |
[Opus 4.6 (1M context)] |
Active model from Claude Code |
5h_bar |
5h ████░░░░ 47% |
5h quota bar with percentage |
7d_bar |
7d ██░░░░░░ 23% |
7d quota bar with percentage |
countdown_5h |
↓2h14m |
Time until 5h reset |
countdown_7d |
↓3d12h |
Time until 7d reset |
cost |
$1.42 |
Session cost in USD |
burn_5h |
⚡18%/h |
5h burn rate per hour |
burn_7d |
⚡42%/d |
7d burn rate per day |
reserve |
+1h12m |
Time margin before quota reset |
cache |
⊞72% |
Average cache hit ratio |
tokens_in |
→125k |
Cumulative input tokens |
tokens_out |
←42k |
Cumulative output tokens |
requests |
#28 |
Total request count |
model |
opus |
Active model from config |
Colors are used sparingly: yellow at the warning threshold (default 75%),
red at the alarm threshold (default 90%). All other text is neutral to
blend with any Claude Code /color setting.
Configuration
All settings are stored in ~/.claude/budmon.ini. This file is created
automatically on first run with commented defaults. You can edit it:
- Via the dashboard: Settings > INI
- Or manually with any text editor
Config file structure
[general]
# Language: "auto" (detect from system), "de", "en"
language = auto
# Dashboard refresh interval in milliseconds
refresh_ms = 1000
[model]
# Model determines token prices: opus, sonnet, haiku, custom
model = opus
[prices]
# Only used when model = custom. Uncomment to activate.
# Prices per 1M tokens in USD.
#
# price_input = 15.0
# price_output = 75.0
# price_cache_read = 1.5
# price_cache_create = 18.75
[thresholds]
# Quota warning/alarm (percent)
quota_warn_pct = 75.0
quota_alarm_pct = 90.0
# Cache ratio warning/alarm (0.0 - 1.0)
cache_warn_ratio = 0.50
cache_alarm_ratio = 0.20
# Burn rate safe/warning (percent per hour)
burn_safe_pct_h = 15.0
burn_warn_pct_h = 25.0
[window]
# Window position (managed automatically)
geometry =
Model presets
| Model | Input | Output | Cache Read | Cache Create |
|---|---|---|---|---|
| Opus | $15.00 | $75.00 | $1.50 | $18.75 |
| Sonnet | $3.00 | $15.00 | $0.30 | $3.75 |
| Haiku | $0.80 | $4.00 | $0.08 | $1.00 |
Prices per 1M tokens in USD. Select via Settings > Model or in the INI file.
For custom prices, set model = custom and uncomment the values in [prices].
Menu
Logs
- Session Log — opens the current session's per-turn token log
- History Log — opens the persistent history across all sessions
- Folder — opens the log directory in the file manager
Settings
- Language — switch between German and English (rebuilds UI)
- Model — select Opus, Sonnet, Haiku, or Custom (updates prices immediately)
- INI — open the configuration file in the system text editor
Help
- User Guide — opens the built-in help file (in the current language)
- About — version, author, license, homepage, runtime info
How it works
BudMon consists of two independent parts:
1. Interceptor (budmon-interceptor.mjs) — headers only
A Node.js module loaded via NODE_OPTIONS="--import ..." when starting
Claude Code. It hooks into the global fetch() function and:
- Captures rate-limit headers from every
/v1/messagesAPI response (e.g.anthropic-ratelimit-unified-5h-utilization) - Writes headers to a local JSON file — never sends data anywhere
The interceptor is strictly header-only (since v1.1.0): it returns the original Response object unmodified. It never accesses, wraps, or transforms the response body or stream.
2. Transcript reader
Claude Code writes a JSONL transcript file for each session at
~/.claude/projects/<project-hash>/<session-id>.jsonl. BudMon reads
the token usage data (message.usage) from these files:
- Per-turn token counts (input, output, cache create, cache read)
- Cumulative totals (summed incrementally)
- Session start time and turn count
This is completely non-invasive — BudMon reads files that Claude Code writes anyway, without any interception or modification.
3. Dashboard (budmon)
A Python/tkinter desktop application that:
- Combines header data (quota) with transcript data (tokens)
- Calculates burn rate, expiry time, and reserve
- Renders all data as a dark-themed GUI with progress bars, sparklines, and a countdown ring
- Falls back gracefully if either source is unavailable
Data files
All data is stored in ~/.claude/:
| File | Written by | Content |
|---|---|---|
usage-limits.json |
Interceptor | Rate-limit headers (quota percentages, reset timestamps) |
projects/<hash>/<id>.jsonl |
Claude Code | Transcript with per-turn token usage (message.usage) |
budmon.ini |
BudMon | Configuration |
Privacy
BudMon captures only technical metadata from Claude Code API responses:
- Rate-limit headers (quota percentages, reset timestamps)
- Token counts (input, output, cache read, cache create)
- Timestamps of API calls
BudMon does not capture:
- Message content (prompts, responses, tool calls)
- API keys or authentication tokens
- Personal information
- File contents or code
All data stays local in ~/.claude/. BudMon has no network access —
it never connects to any server, sends no telemetry, no analytics, no crash
reports. The interceptor operates entirely within the Claude Code Node.js
process and writes only to local files.
The interceptor source code is included in the package
(budmon/interceptor.mjs) and can be audited at any time.
Security
The interceptor is header-only (since v1.1.0). It hooks into globalThis.fetch
to read rate-limit headers, but:
- It never accesses the response body or stream
- It never modifies outgoing requests (no payload changes, no header injection)
- It never blocks or delays requests or responses
- It returns the original Response object — no wrapping, no cloning
- It fails open — any error in the interceptor is silently caught, ensuring Claude Code continues to work normally
Token usage is read from Claude Code's own transcript files, which Claude Code writes independently. BudMon never interferes with Claude Code's data processing.
The interceptor is loaded via Node.js NODE_OPTIONS="--import ...", a standard
mechanism. It only runs when you explicitly start Claude Code via claude-budmon.
Compatibility
BudMon reads rate-limit headers from the Anthropic API, which follow a stable
documented format (anthropic-ratelimit-unified-*). Token usage is read
from Claude Code's own transcript JSONL files (message.usage).
When Claude Code updates: The interceptor (headers) should continue to work as long as Anthropic does not change their API header format. The transcript reader depends on Claude Code's internal JSONL format — if this changes, token details may be unavailable while quota bars continue to work.
- Check if
~/.claude/usage-limits.jsonis still being written (headers) - Check if transcript JSONL files exist in
~/.claude/projects/ - Try
budmon --uninstallfollowed bybudmon --setupto reinstall - File an issue at the project repository
When Anthropic changes quota windows: The 5h and 7d windows are read from the API headers, not hardcoded. If Anthropic changes the window sizes, BudMon will adapt automatically.
Troubleshooting
Status "WAIT", all values "--", footer shows "Waiting for data..."
This is the normal startup state. BudMon is waiting for Claude Code to deliver data. This is not an error if BudMon was started before Claude Code.
If the state persists after Claude Code is running:
-
Was
budmon --setuprun? Check: does~/.claude/budmon-interceptor.mjsexist? If not: runbudmon --setup. -
Was Claude Code started via
claude-budmon? Onlyclaude-budmonloads the interceptor. A plainclaudedoes not write data for BudMon. -
Was at least one message sent? The interceptor writes on the first API response. Before the first turn, the data file does not exist yet.
-
Does the data file exist? Check:
ls -la ~/.claude/usage-limits.jsonIf it exists but is old: Claude Code was likely started without the interceptor. Restart viaclaude-budmon. -
Had data before but not anymore? The Claude Code session was ended. Start a new session via
claude-budmon.
Token details show "--" but quota bars work
Quota bars come from the interceptor (rate-limit headers). Token details come from Claude Code's transcript JSONL files. If the transcript cannot be found (e.g. the project directory name convention changed), token details are unavailable while quota monitoring continues to work.
Dashboard shows quota bars but token details are "--"
This is normal for a brief moment. Rate-limit headers are written immediately when the API responds, but token counts are written after the streaming response completes. There is a short window where quota bars work but token details have not arrived yet.
If it persists: Claude Code must have been started via claude-budmon.
A regular claude session does not load the interceptor.
Burn rate / expiry / reserve show "--"
Burn rate requires two things:
- The quota percentage must be above ~0.01% (no calculation if nothing was consumed)
- The reset timestamp must be present in the API headers
If reset is shown but burn rate is not: the quota utilization is too low to calculate a meaningful rate. This resolves itself after more usage.
Window opens at wrong position
- Delete the
geometryline in~/.claude/budmon.inito reset to center - Or edit it via Settings > INI
Setup says "Compatible interceptor found"
- You already have a working interceptor (e.g.
cache-fix-preload.mjs) - No additional setup needed — just run
budmon
Uninstall
budmon --uninstall
pip uninstall budmon
budmon --uninstall removes:
~/.claude/budmon-interceptor.mjs- The
claude-budmonalias from.bashrc/.zshrc - The wrapper script in
~/.local/bin/ - The
.desktopfile (Linux)
Data files in ~/.claude/ are not removed.
Project structure
budmon/
__init__.py Package + version
__main__.py Entry point for python -m budmon
cli.py CLI argument handling (--setup, --statusline, etc.)
config.py INI-based configuration singleton (section-aware)
dashboard.py Main tkinter GUI class
data.py Data loading, calculations, formatting
i18n.py Internationalization (JSON language files)
interceptor.mjs Node.js fetch interceptor (installed by --setup)
models.py Constants, dataclasses, color functions
platform.py HiDPI detection, file viewer
setup.py Setup/uninstall logic + status line activation
statusline.py Compact ANSI output for Claude Code status line (15 elements)
transcript.py Reads token data from Claude Code transcript JSONL
widgets.py Canvas drawing, UI builder functions
budmon.default.ini Default configuration template
lang/
de.json German strings
en.json English strings
help/
help_de.md German user guide
help_en.md English user guide
icons/
budmon.svg Application icon (Lucide "activity", MIT)
budmon-*.png Pre-rendered icon sizes (16-256px)
Contributing
Contributions are welcome. Please:
- Fork the repository
- Create a feature branch
- Run
pytestbefore submitting - Open a pull request with a clear description
Code style: Python 3.10+, type hints, no external dependencies (stdlib only).
Credits
- Icon: Lucide "activity" icon (MIT License — compatible with GPL-3.0, included with permission)
- Interceptor approach inspired by community work on claude-code#42052
License
GPL-3.0 — see LICENSE
Copyright (c) 2026 weilhalt
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file budmon-1.1.0.tar.gz.
File metadata
- Download URL: budmon-1.1.0.tar.gz
- Upload date:
- Size: 85.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
740d7e0f2979af7d6f048b613ab34f69a3e2631928125f18f6bb29ec728231a7
|
|
| MD5 |
b5a9703dc3e90e482d4a3bb1c2695124
|
|
| BLAKE2b-256 |
bf01388b4b7d71bb9116f7a66ee445d87da58db212b20d19c3c6acc8b35bfa74
|
File details
Details for the file budmon-1.1.0-py3-none-any.whl.
File metadata
- Download URL: budmon-1.1.0-py3-none-any.whl
- Upload date:
- Size: 73.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3db8b3bc619dafb0577eb4f07d0364a8e89967d7333b46a662152e2b7e73c206
|
|
| MD5 |
c6f7df1cf8661f422723d41c2adb839f
|
|
| BLAKE2b-256 |
c59439de4b428528ea89a5150fb5067f8b0f561d139a70ba6993b451e54db3d1
|