Shows your Claude and Codex plan usage limits (session / weekly windows, model-scoped limits, and time until each resets) where your system status icons live:
| Linux (Ubuntu) | macOS | Windows |
|---|
| OS | Where it appears | What it shows |
|---|---|---|
| Linux | Top bar / panel, next to Wi-Fi and sound (AppIndicator) | Icon + Claude 99% Codex 13% ; click for details |
| macOS | Menu bar, top right | Gauge icon + Claude 99% Codex 13% ; click for details |
| Windows | An empty spot on the taskbar, plus a tray icon | Claude 99% Codex 13% on the taskbar and a two-bar gauge icon; click either for details |
The dropdown lists every limit with its percentage and reset countdown, plus Refresh now, links to each provider's usage page, and Quit. Bars and icons turn amber at 75% and red at 90% (or whatever severity the provider reports). If a refresh fails, the last numbers are kept and marked stale.
There is also a floating always-on-top window (--widget) for desktops without a tray.
It reuses the logins that Claude Code (claude) and the Codex CLI ( codex) already store
on your machine, so there is nothing to configure. Credentials are only read, never modified, and each
token is sent only to the provider that issued it.
| Provider | Credentials read from | Endpoint |
|---|---|---|
| Claude | macOS Keychain Claude Code-credentials , else~/.claude/.credentials.json ($CLAUDE_CONFIG_DIR ) |
api.anthropic.com/api/oauth/usage |
| Codex | ~/.codex/auth.json ($CODEX_HOME ) |
chatgpt.com/backend-api/wham/usage |
| Bedrock | Your AWS credentials (profile, SSO, env vars), via boto3 | AWS Budgets, Cost Explorer, CloudWatch |
These are the same internal endpoints the official CLIs use for their /usage and /status
screens. They are undocumented and may change; if a provider shows an error after an update,
check the parser for that provider in usage_widget.py.
First log in to each CLI once with your subscription: claude → /login, and codex login.
Each installer puts the app where it belongs for the OS, starts it right away, and starts it again
every time you log in.
Download from the GitHub release (built by .github/workflows/build-installers.yml):
| OS | File | Notes |
|---|---|---|
| Linux (Debian/Ubuntu) | llm-usage-widget_<ver>_all.deb |
sudo apt install ./llm-usage-widget_*.deb . Starts right away for every logged-in user, and at login via/etc/xdg/autostart . |
| macOS | LLM-Usage-Widget-<ver>-macos-arm64.pkg (Apple Silicon) or-x86_64.pkg (Intel) |
Installs /Applications/LLM Usage.app plus a login LaunchAgent. Release builds are signed with a Developer ID and notarized by Apple. |
| Windows | LLM-Usage-Widget-<ver>-windows-setup.exe |
Per-user install, no admin rights needed. "Start automatically when I sign in" is ticked by default. The build is unsigned, so SmartScreen may warn: click More info → Run anyway . Uninstall fromSettings → Apps , theUninstall LLM Usage Widget Start Menu entry, or by runningLLM-Usage-Widget-<ver>-windows-uninstall.exe from the same release (add/VERYSILENT to skip the prompts). Settings in%APPDATA%\llm-usage-widget are kept. |
To uninstall the macOS package, open LLM-Usage-Widget-<ver>-macos-uninstall.pkg from the same release
(it asks for an administrator password), or run the copy of the uninstaller inside the app:
sudo "/Applications/LLM Usage.app/Contents/Resources/uninstall.sh"
Either one stops the widget for every logged-in user and removes the app, its LaunchAgent and the
package receipt. Settings in ~/Library/Application Support/llm-usage-widget are left in place.
On Debian/Ubuntu: sudo apt remove llm-usage-widget.
| OS | Install | Uninstall |
|---|---|---|
| Linux / macOS | ./install.sh |
./install.sh --uninstall |
| Windows | double-click install.cmd (orpowershell -ExecutionPolicy Bypass -File install.ps1 ) |
uninstall.cmd |
- Linux: copies to
~/.local/share/llm-usage-widget, adds an app-menu launcher and~/.config/autostart/llm-usage-widget.desktop. Uses the system Python's PyGObject and AppIndicator (preinstalled on Ubuntu; the script prints the package command for your distro if they're missing). On GNOME the AppIndicator extension must be enabled (the default on Ubuntu; elsewhere install "AppIndicator and KStatusNotifierItem Support"). KDE, XFCE, Cinnamon and others work out of the box, though some panels show only the icon, not the text label. - macOS: needs Python 3.9+ (python.org or Homebrew). Copies to
~/Library/Application Support/llm-usage-widgetwith its own virtualenv and registers~/Library/LaunchAgents/local.llm-usage-widget.plist. Logs go to~/Library/Logs/llm-usage-widget.log. - Windows: needs Python 3.9+ from python.org. Copies to
%LOCALAPPDATA%\llm-usage-widgetwith its own virtualenv and adds Start Menu and Startup shortcuts.
On macOS the first run may ask for Keychain access to Claude Code-credentials; choose Always Allow.
On Windows the numbers are drawn on the taskbar itself: left of the ^ arrow when there is room, otherwise in
the next empty gap (with centered taskbar buttons, usually left of Start), on two smaller lines if that is what
fits. It never covers taskbar buttons; if the taskbar is completely full it hides until there is room. Windows has
no API for text in the taskbar, so this is a small always-on-top window that follows the taskbar and steps
aside for full-screen apps and an auto-hidden or vertical taskbar. Turn it off with Show usage on the taskbar
in the menu. The tray icon may be tucked into the overflow (^) menu; drag it onto the taskbar to keep it visible.
/usr/bin/python3 usage_widget.py # Linux (system Python, for PyGObject)
python3 -m pip install -r requirements.txt # macOS / Windows: pystray + Pillow
python3 usage_widget.py # Windows: pythonw usage_widget.py (no console window)
Only one copy runs at a time; starting a second one exits immediately.
usage_widget.py # tray / top bar / menu bar (default)
usage_widget.py --widget # floating always-on-top window instead
usage_widget.py --widget --framed # ...with a normal title bar
usage_widget.py --once # print usage in the terminal and exit
usage_widget.py --interval 300 # refresh every 5 minutes (default 180 s, min 60 s)
Claude Code and Codex refresh their own tokens while you use them. If you haven't used one for a while, its access token may expire and the widget will say so. Open that CLI once and the widget picks up the new token on its next refresh. The widget deliberately does not refresh tokens itself, because rotating the refresh token would log the CLI out.
The Ubuntu AppIndicators extension shipped with GNOME 50 comes up half-broken at login: until it is
reloaded, apps that start after its initial bus scan get No such method "RegisterStatusNotifierItem"
and don't appear (this also hits Remmina, update-notifier, etc.). Apps already running during that scan
do appear, so starting the widget at login usually works. install.sh detects the broken state and
reloads the extension once so the icon appears immediately. If the icon is missing, reload it by hand:
gnome-extensions disable ubuntu-appindicators@ubuntu.com && gnome-extensions enable ubuntu-appindicators@ubuntu.com
The GitHub Actions workflow builds every installer on its own OS. Push a tag matching __version__ in
usage_widget.py (e.g. v1.0.0) to build them and attach them to a release, or run the workflow
by hand to download them as build artifacts. To build locally on each OS:
packaging/linux/build-deb.sh # Linux → dist/*.deb
python3 -m pip install pyinstaller -r requirements.txt
packaging/macos/build-pkg.sh # macOS → dist/*.pkg
powershell -File packaging\windows\build.ps1 # Windows → dist\*-setup.exe (needs Inno Setup 6)
To sign the macOS build locally, set CODESIGN_IDENTITY (a "Developer ID Application" identity) and
INSTALLER_SIGN_IDENTITY ("Developer ID Installer"). The app is signed with the hardened runtime and a
secure timestamp, which is what notarization requires. Then notarize and staple the pkg:
xcrun notarytool submit dist/*.pkg --keychain-profile <profile> --wait
xcrun stapler staple dist/*.pkg
In CI, the macOS job signs, notarizes and staples the pkg when these repository secrets are set. A tag release fails without them:
| Secret | Contents |
|---|---|
MAC_CERT_P12_BASE64 /MAC_CERT_PASSWORD |
The Developer ID Application certificate and private key, as a base64-encoded .p12 , and its export password |
MAC_INSTALLER_CERT_P12_BASE64 /MAC_INSTALLER_CERT_PASSWORD |
The same for the Developer ID Installer certificate |
AC_API_KEY_P8_BASE64 /AC_API_KEY_ID /AC_API_ISSUER_ID |
An App Store Connect API key (the base64-encoded .p8 ), its key ID and issuer ID, used bynotarytool |
The workflow Authenticode-signs LLMUsageWidget.exe and the setup .exe with
Azure Trusted Signing (the same setup as
Virux), timestamps both, and checks the signatures before up. A tag build fails rather than
publish an unsigned installer; a manual run without the secrets builds unsigned with a warning.
It needs these repository (or organization) secrets:
| Secret | What it is |
|---|---|
AZURE_TENANT_ID |
Entra ID tenant of the app registration that signs |
AZURE_CLIENT_ID |
That app registration's client ID |
AZURE_CLIENT_SECRET |
A client secret for it; also how the workflow decides whether to sign |
AZ_TS_ENDPOINT |
The Trusted Signing account's regional endpoint, e.g. https://eus.codesigning.azure.net |
AZ_TS_ACCOUNT |
Trusted Signing account name |
AZ_TS_PROFILE |
Certificate profile name |
The app registration needs the Trusted Signing Certificate Profile Signer role on the account.
Publisher name only, no address. Windows shows the certificate's common name, the validated
organization name ("Aleph Void LLC"), as the publisher in SmartScreen, the UAC prompt and the file's
Digital Signatures tab. Create the Public Trust certificate profile with Include street
address and Include postal code both unticked (the default) so the certificate carries no
address. City, state and country are always part of a Public Trust certificate's details and can't
be removed. packaging/windows/verify-signature.ps1 fails the build if a signature is invalid,
not timestamped, or its certificate includes a street address or postal code. Run it on a
downloaded installer to check it yourself:
powershell -File packaging\windows\verify-signature.ps1 .\LLM-Usage-Widget-<ver>-windows-setup.exe
The release's -windows-uninstall.exe is signed the same way. The uninstaller that Inno Setup
writes into the install folder at install time is not signed. It runs without elevation
(the install is per-user), so Windows doesn't show a publisher prompt for it.
If Claude Code or Codex runs on Amazon Bedrock instead of a subscription, there are no session or weekly limits to show. Instead the widget adds a Bedrock section that shows:
- Budget: spend against anAWS Budget as a percentage bar that resets with the budget period. This only appears if you name a budget (see below).
- This month: month-to-date spend for every service with "Bedrock" in its name, from Cost Explorer.
Third-party models such as Claude are billed as Marketplace services named like
Claude Sonnet 4.5 (Amazon Bedrock Edition), and these are included. - Tokens today: input and output tokens since local midnight, from CloudWatch. This covers both the
bedrock-runtimeendpoint (AWS/Bedrock) and the OpenAI/Anthropic-compatiblebedrock-mantleendpoint (AWS/BedrockMantle).
The section turns on automatically when Claude Code's settings set CLAUDE_CODE_USE_BEDROCK
(or an ANTHROPIC_BASE_URL containing bedrock), or when a base_url in ~/.codex/config.toml points at
Bedrock. The AWS profile and region come from the same place: AWS_PROFILE and AWS_REGION in Claude
Code's env block, or the region in Codex's base_url. In that case the Claude or Codex section
is hidden if that CLI has no subscription login. To override any of this, add a bedrock entry to
config.json in the widget's config folder (~/.config/llm-usage-widget/ on Linux,
~/Library/Application Support/llm-usage-widget/ on macOS, %APPDATA%\llm-usage-widget\ on Windows):
{
"bedrock": {
"profile": "work",
"regions": ["us-east-1", "us-west-2"],
"budget": "bedrock-monthly",
"cost_explorer": true,
"cost_interval": 21600,
"metrics_interval": 900
}
}
Use "bedrock": true to turn the section on with the defaults, or false to hide it.
This needs boto3: it is in requirements.txt and in the macOS and Windows packages. On Linux, run
sudo apt install python3-boto3 (or install it for the system Python another way). The IAM identity
needs ce:GetCostAndUsage, cloudwatch:GetMetricData, and, for a budget, budgets:ViewBudget and
sts:GetCallerIdentity. If a permission is missing, only that row shows an error. If the credentials
have expired (for example an SSO session), the section says to run aws sso login.
Cost: Cost Explorer charges $0.01 per request and its data only updates a few times a day, so spend
(and the budget) is fetched at most every cost_interval seconds (6 h by default, about $1.20 a month).
Token counts are fetched every metrics_interval seconds (15 min). Both are cached in
bedrock-cache.json next to config.json, so restarts don't refetch them, and Refresh now doesn't
bypass the cache either. Billing data can lag by a day or more, so don't treat this as a spending alarm.
Write a fetch_<name>() that returns a ProviderUsage and add it to PROVIDERS.
MIT. See LICENSE.