Skip to content

akitaonrails/ai-usagebar

Repository files navigation

ai-usagebar

Waybar widget and tabbed TUI for AI plan usage across Anthropic Claude, OpenAI Codex/ChatGPT, Z.AI (GLM), OpenRouter, DeepSeek, and Kimi.

This started as a Rust port of claudebar and stays drop-in compatible with it. It keeps the minimalist Pango-bordered tooltip, Omarchy theme auto-detection, and flock-protected OAuth refresh, then adds five more vendors and a proper testable codebase instead of one long shell script.

Waybar widget showing cld 29% · 1h 12m in the top-right, with the hover tooltip showing Claude Max 20x session/weekly/sonnet/extra-usage progress bars

Features

  • Per-vendor Waybar modules with the same JSON shape as claudebar.
  • Tabbed TUI (ai-usagebar-tui) with Tab/h/l switching, per-tab refresh, and 60-second auto-refresh. Native ratatui widgets fill the available terminal width and keep the vendor tabs visually consistent.
  • Optional local Claude Code context monitor in the TUI, with a bounded, compaction-aware view of recent session input-context usage.
  • Native desktop integrations for GNOME Shell and the macOS menu bar, with selectors for Anthropic, OpenAI, Z.AI, OpenRouter, and DeepSeek.
  • Scroll-to-cycle on the bar: wire on-scroll-up / on-scroll-down, and one bar item cycles through your enabled vendors.
  • Config-driven primary vendor: set [ui] primary once; the widget shows that vendor by default and the TUI opens on its tab.
  • Local testing tools: --pretty renders ANSI-colored terminal output (auto-detects TTY), and --watch N re-renders every N seconds.
  • Drop-in claudebar compatibility with the same flags (--icon, --format, --tooltip-format, --pace-tolerance, --format-pace-color, --tooltip-pace-pts, --color-*) and {placeholders}.
  • Always exits 0, because Waybar hides modules that don't.
  • Atomic cache writes + flock, so multi-monitor Waybar instances can coexist without API stampedes.
  • Separate transient and hard errors: DNS/timeout failures show a quiet Loading…; HTTP 4xx/5xx errors put the code in the tooltip.
  • Live API smoke tests: make smoke hits the real undocumented endpoints and catches schema drift early.

Install

Arch (AUR)

Two packages. Pick one:

yay -S ai-usagebar-bin    # prebuilt binary from GitHub Releases (fast, ~5s install)
yay -S ai-usagebar        # compiles from source (~30-60s, hermetic)

The -bin variant downloads the same x86_64 ELF that CI built and tested. The source variant compiles locally with your toolchain. Both install identical binaries to /usr/bin/. If you already have one installed, switch with yay -S the other package; pacman handles the swap through conflicts/provides.

Other Linux / macOS (crates.io)

cargo install ai-usagebar                # compile from source (needs rustup)
cargo binstall ai-usagebar               # download prebuilt binary (needs cargo-binstall, no rustup)

cargo binstall fetches the same x86_64 / aarch64 Linux tarball the AUR -bin package uses. Both install ai-usagebar + ai-usagebar-tui to ~/.cargo/bin/.

From source

cargo build --release
sudo make install                  # → /usr/local/bin
# or
make install PREFIX=$HOME/.local   # → ~/.local/bin

Windows

The Waybar widget is Wayland-only and does not apply to Windows. The ai-usagebar-tui binary, however, runs natively, and ai-usagebar --json / --pretty work too (handy for feeding a custom tray/widget). Build with a standard Rust toolchain:

cargo build --release
# binaries land in target\release\ai-usagebar.exe and ai-usagebar-tui.exe

Credentials are read from the Windows user profile rather than $HOME: %USERPROFILE%\.claude\.credentials.json (Anthropic) and %USERPROFILE%\.codex\auth.json (OpenAI Codex). Run the official claude / codex CLI once on Windows to populate them, exactly as on Linux/macOS. API-key vendors work unchanged via environment variables or config.toml.

Authentication

Each vendor authenticates a little differently. Anthropic and OpenAI use OAuth credentials that their official CLIs already wrote to disk, so no env vars are needed. Every other vendor uses an API key. You can pass those through env vars or, if you don't source secrets in your shell, put them inline in config.toml.

Vendor Method Action required
Anthropic OAuth, read from ~/.claude/.credentials.json (or the macOS login Keychain — see below) Run claude once to log in. Token auto-refreshes.
Anthropic (API) Console Admin key (ANTHROPIC_ADMIN_KEY env or [anthropic_api] api_key in config) Set either. Opt-in. This is an organization Admin key (sk-ant-admin01-…), not an inference key or Claude Code OAuth credential.
OpenAI OAuth, read from ~/.codex/auth.json Run codex login once. Token auto-refreshes.
Z.AI API key (ZAI_API_KEY env or [zai] api_key in config) Set either.
OpenRouter API key (OPENROUTER_API_KEY env or [openrouter] api_key in config) Set either.
DeepSeek API key (DEEPSEEK_API_KEY env or [deepseek] api_key in config) Set either. Opt-in — see below.
Kimi API key (KIMI_API_KEY env or [kimi] api_key in config) Set either. Opt-in — see below.
Kilo API key (KILO_API_KEY env or [kilo] api_key in config) Set either. Opt-in. For a team balance, also set [kilo] organization_id; omit it for the personal balance.
Novita API key (NOVITA_API_KEY env or [novita] api_key in config) Set either. Opt-in.
Moonshot API key (MOONSHOT_API_KEY env or [moonshot] api_key in config) Set either. Opt-in. Set [moonshot] region = "cn" for api.moonshot.cn (balance in CNY); the default "global" uses api.moonshot.ai (USD).
Grok (xAI) Management key (XAI_MANAGEMENT_KEY env or [grok] api_key in config) Set either. Opt-in. This is not the inference key — create it under xAI Console → Management keys. See the team note below.

Grok: team-scoped vs organization-scoped keys

The balance lives at /v1/billing/teams/{team}/prepaid/balance, so a team has to be identified. With a team-scoped management key the team is read automatically from the key. With an organization-scoped key it cannot be — that key's scopeId is an organization id, not a team — so set the team explicitly:

[grok]
team_id = "your-team-id"

Without it, an organization-scoped key reports an error saying exactly this rather than silently querying the wrong URL.

Enabling a vendor

enabled = true is what makes a vendor fetch. Anthropic (API), DeepSeek, Kimi, Kilo, Novita, Moonshot, and Grok all default to disabled so that existing installs are unaffected until you opt in. Two ways to do it:

  • Via the TUI Settings overlay (ai-usagebar-tui, then s): saving a non-empty API key sets that vendor's enabled = true for you. Clearing the field again removes the inline key from config.toml.
  • By hand: add enabled = true to the vendor's section alongside the key.

The primary-vendor selector only offers vendors that are currently enabled, so a vendor you haven't opted into cannot be set as primary.

Credential resolution order (for API-key vendors)

For each API-key vendor, ai-usagebar checks in this order:

  1. Env var named by api_key_env in config (defaults: ANTHROPIC_ADMIN_KEY, ZAI_API_KEY, OPENROUTER_API_KEY, DEEPSEEK_API_KEY, KIMI_API_KEY, KILO_API_KEY, NOVITA_API_KEY, MOONSHOT_API_KEY, XAI_MANAGEMENT_KEY). If set + non-empty, used.
  2. Inline api_key in the same config section.
  3. Otherwise, error with a message naming both options.

Security

  • If you put inline api_key values in config, chmod 600 ~/.config/ai-usagebar/config.toml. The default behavior reads only env vars, which is safer when your config might be world-readable.
  • Don't commit your config dir if you check it into dotfiles unless you've redacted api_key lines.
  • OAuth credential files (~/.claude/.credentials.json, ~/.codex/auth.json) are managed by their respective CLIs and already chmod-protected.

macOS: Anthropic credentials in the Keychain

On macOS, recent Claude Code builds don't write ~/.claude/.credentials.json — they keep the same OAuth JSON in the login Keychain under the generic-password service Claude Code-credentials. ai-usagebar detects the missing file and transparently reads (and writes refreshed tokens back to) that Keychain item via the built-in security tool, so no manual step is needed. If the file does exist it still takes precedence, matching Linux.

Configuration

~/.config/ai-usagebar/config.toml (optional — defaults enable Anthropic, OpenAI, Z.AI, and OpenRouter; all other vendors are opt-in). Full example:

[ui]
# Which vendor the widget shows when --vendor is omitted, AND which tab
# is selected when the TUI opens. Defaults to anthropic when not set.
# Only a vendor that is enabled can be primary.
# primary = "anthropic"   # anthropic | anthropic_api | openai | zai
#                         # | openrouter | deepseek | kimi | kilo | novita
#                         # | moonshot | grok

[context]
enabled = false           # opt in, then press c in ai-usagebar-tui
# projects_path = "~/.claude/projects"
# context_window_tokens = 200000  # optional fallback denominator
# [context.model_context_window_tokens]
# "claude-opus-4-6" = 1000000    # exact model id overrides the fallback

[anthropic]
enabled = true
# credentials_path = "/home/you/.claude/.credentials.json"

[anthropic_api]
enabled = true             # disabled by default; requires an organization Admin key
api_key_env = "ANTHROPIC_ADMIN_KEY"
# api_key = "sk-ant-admin01-..."  # not an inference key; chmod 600 if inline
# monthly_limit = 1000     # optional positive, finite USD display limit

[openai]
enabled = true
# codex_auth_path = "/home/you/.codex/auth.json"

[zai]
enabled = true
api_key_env = "ZAI_API_KEY"
# api_key = "..."          # used if ZAI_API_KEY is unset; chmod 600 the file!
# plan_tier = "lite"       # lite | pro | max — display-only

[openrouter]
enabled = true
api_key_env = "OPENROUTER_API_KEY"
# api_key = "sk-or-v1-..."

[deepseek]
enabled = true             # disabled by default; enable once you add an API key
api_key_env = "DEEPSEEK_API_KEY"
# api_key = "sk-..."       # used if DEEPSEEK_API_KEY is unset; chmod 600 the file!

[kimi]
enabled = true             # disabled by default; enable once you add an API key
api_key_env = "KIMI_API_KEY"
# api_key = "sk-..."       # used if KIMI_API_KEY is unset; chmod 600 the file!

# --- Account-balance vendors (all opt-in) ---

[kilo]
enabled = true             # disabled by default; enable once you add an API key
api_key_env = "KILO_API_KEY"
# api_key = "..."          # used if KILO_API_KEY is unset; chmod 600 the file!
# organization_id = "org_..."   # team balance; omit for the personal balance

[novita]
enabled = true             # disabled by default; enable once you add an API key
api_key_env = "NOVITA_API_KEY"
# api_key = "..."          # used if NOVITA_API_KEY is unset; chmod 600 the file!

[moonshot]
enabled = true             # disabled by default; enable once you add an API key
api_key_env = "MOONSHOT_API_KEY"
# api_key = "sk-..."       # used if MOONSHOT_API_KEY is unset; chmod 600 the file!
# region = "global"        # global → api.moonshot.ai (USD) | cn → api.moonshot.cn (CNY)

[grok]
enabled = true             # disabled by default; enable once you add an API key
# The xAI *Management* key, NOT the inference key.
api_key_env = "XAI_MANAGEMENT_KEY"
# api_key = "..."          # used if XAI_MANAGEMENT_KEY is unset; chmod 600 the file!
# Required for organization-scoped keys; auto-resolved for team-scoped ones.
# team_id = "..."

Quick start

# Local testing — auto-detects TTY and renders human-readable output.
ai-usagebar                        # uses [ui] primary (defaults to anthropic)
ai-usagebar --vendor anthropic_api
ai-usagebar --vendor openai
ai-usagebar --vendor zai
ai-usagebar --vendor openrouter
ai-usagebar --vendor deepseek
ai-usagebar --vendor kimi

# Force Waybar JSON (e.g. piping into jq).
ai-usagebar --json

# Live preview while iterating on --format / --tooltip-format.
ai-usagebar --vendor openrouter --watch 5

# Interactive TUI with tabs.
ai-usagebar-tui

Standalone TUI — no Waybar required

The two binaries are independent. If you don't run Waybar (or just want to check usage occasionally rather than have it on your bar permanently), ai-usagebar-tui works as a fully standalone terminal app:

ai-usagebar-tui                    # opens in your current terminal

It runs in any terminal emulator (Kitty, Alacritty, Foot, Ghostty, etc.), works in plain SSH sessions, and doesn't need a compositor or window manager integration. All controls and the Settings overlay work the same way. Use it as:

  • An ad-hoc check ("am I close to my Claude weekly limit before I start a long session?")
  • A foreground monitor on a secondary screen or tmux pane while you code
  • A shell-only tool on remote machines (just install the binary; no Waybar/Hyprland dependencies)

The Waybar widget is optional. The TUI is the best way to see every enabled vendor at once, even if you never set up the widget.

Native desktop integrations (v0.13)

The GNOME Shell extension and macOS menu bar app support selectors for Anthropic, OpenAI, Z.AI, OpenRouter, and DeepSeek. Kimi is widget/TUI-only in v0.13; do not select it in either native desktop integration yet. Desktop protocol and marker parity for Kimi is dedicated future work.

Waybar config

Single module, scroll-to-cycle (recommended)

Use one bar item and scroll through your vendors. The TUI on-click still shows them all:

"modules-right": ["custom/aibar", ...],

"custom/aibar": {
    "exec": "ai-usagebar --format '{vendor_short} {session_pct}% · {session_reset}'",
    "return-type": "json",
    "interval": 300,
    "signal": 13,
    "tooltip": true,
    "on-click": "ai-usagebar-tui",
    "on-scroll-up":   "ai-usagebar --cycle-next",
    "on-scroll-down": "ai-usagebar --cycle-prev"
}

The {vendor_short} placeholder always expands to a 3-letter vendor ID (cld / gpt / zai / opr / dsk / kmi), so the bar text tells you which vendor is active. The other usage placeholders ({session_pct} for Anthropic, {oai_session_pct} for OpenAI, etc.) are vendor-specific. If you want one format string for every cycled vendor, prefer the generic aliases: {session_pct}, {session_reset}, {weekly_pct}, and {weekly_reset} are implemented by all six vendors (Anthropic, OpenAI, Z.AI, OpenRouter, DeepSeek, and Kimi; OpenRouter and DeepSeek use 0 / for the windows they don't expose). Anthropic and OpenAI add *_elapsed, *_pace, and *_bar families; each vendor also exposes its own {oai_*} / {zai_*} / {or_*} / {ds_*} / {kimi_*} families, which expand to empty strings for vendors that don't define them.

signal: 13 lets the scroll-cycle commands refresh the bar instantly (via SIGRTMIN+13) instead of waiting for the next 300s interval.

If your Waybar theme puts a tray expander immediately after custom/aibar, such as Omarchy's group/tray-expander with custom/expand-icon, the usage text can sit very close to the expand icon. Add right padding for the module in your Waybar CSS if you want extra spacing:

#custom-aibar {
    padding-right: 18px;
}

Per-vendor modules

If you'd rather see them all at once:

"modules-right": ["custom/claude", "custom/openai", "custom/openrouter", "custom/zai", "custom/deepseek", "custom/kimi"],

"custom/claude": {
    "exec": "ai-usagebar --vendor anthropic --icon '󰚩'",
    "return-type": "json",
    "interval": 300,
    "tooltip": true,
    "on-click": "ai-usagebar-tui"
},
"custom/openai": {
    "exec": "ai-usagebar --vendor openai --icon '󱢆'",
    "return-type": "json",
    "interval": 300,
    "tooltip": true
},
"custom/openrouter": {
    "exec": "ai-usagebar --vendor openrouter --icon '󱙺' --format '{or_balance} · {or_used_today}'",
    "return-type": "json",
    "interval": 600,
    "tooltip": true
},
"custom/zai": {
    "exec": "ai-usagebar --vendor zai --icon '󰚩'",
    "return-type": "json",
    "interval": 300,
    "tooltip": true
},
"custom/deepseek": {
    "exec": "ai-usagebar --vendor deepseek --icon '󰧑'",
    "return-type": "json",
    "interval": 600,
    "tooltip": true
},
"custom/kimi": {
    "exec": "ai-usagebar --vendor kimi --icon '󰚩'",
    "return-type": "json",
    "interval": 600,
    "tooltip": true
}

Why 300s? The Anthropic and OpenAI Codex endpoints are undocumented and rate-limit aggressively below ~300s. The cache TTL is 60s so multi-monitor instances coexist, but Waybar's polling interval should stay at 300s.

Multiple accounts (advanced)

To watch more than one account of the same vendor — say a personal and a work Claude subscription — run one module per account, giving each its own credentials file and its own cache directory:

"modules-right": ["custom/claude-personal", "custom/claude-work", ...],

"custom/claude-personal": {
    "exec": "ai-usagebar --vendor anthropic --icon '󰚩' --format 'p {session_pct}% · {session_reset}'",
    "return-type": "json",
    "interval": 300,
    "tooltip": true
},
"custom/claude-work": {
    "exec": "ai-usagebar --vendor anthropic --icon '󰚩' --format 'w {session_pct}% · {session_reset}' --creds-path ~/.config/ai-usagebar/accounts/work.credentials.json --cache-dir ~/.cache/ai-usagebar/anthropic-work",
    "return-type": "json",
    "interval": 300,
    "tooltip": true
}
  • --creds-path points the module at a different OAuth credentials file (same JSON shape Claude Code writes). To capture a second account's file, log in with claude under that account and copy ~/.claude/.credentials.json somewhere stable — token refreshes are written back to whatever file the flag names, so each account keeps itself alive independently. chmod 600 the copies.
  • --cache-dir gives the module a private cache so the two accounts don't overwrite each other's 60-second cache window. Any directory works; the per-vendor default is ~/.cache/ai-usagebar/<vendor>.
  • --creds-path currently applies to the Anthropic vendor only. For API-key vendors (Z.AI, OpenRouter, DeepSeek, Kimi) point each module at a different key via a wrapper script that sets the env var, plus its own --cache-dir.
  • The TUI shows the default Claude tab plus one tab per configured [[anthropic.accounts]] entry (see the config example below); Tab / h / l cycle through them like any other tab.
  • On macOS, the login Keychain can hold only one Claude credential per OS user, so additional accounts must be file-based as shown above.

Config-driven accounts (--account)

Instead of repeating --creds-path/--cache-dir on every module, name your extra Anthropic accounts once in config and select them with --account <label>:

[anthropic]
# The default account. `--vendor anthropic` with no `--account` uses this,
# exactly as before. Optional — falls back to ~/.claude/.credentials.json.
# credentials_path = "~/.claude/.credentials.json"

[[anthropic.accounts]]
label = "work"
credentials_path = "~/.config/ai-usagebar/accounts/work.json"

[[anthropic.accounts]]
label = "personal"
credentials_path = "~/.config/ai-usagebar/accounts/personal.json"
"custom/claude-work": {
    "exec": "ai-usagebar --vendor anthropic --account work --format 'w {session_pct}% · {session_reset}'",
    "return-type": "json",
    "interval": 300,
    "tooltip": true
}
  • The default account is the singular [anthropic] credentials_path (or the platform default file). --vendor anthropic without --account uses it, with the same output and the same ~/.cache/ai-usagebar/anthropic/ cache as today.
  • Each --account <label> gets an isolated cache at ~/.cache/ai-usagebar/anthropic/<label>/ automatically — no --cache-dir needed. Only extra accounts get a subdir; the default never moves.
  • --account is Anthropic-only and can't be combined with --creds-path (both name a credentials file). A typo'd label fails loudly, listing the known ones.
  • ai-usagebar-tui reads the same [[anthropic.accounts]] and shows one tab per account (after the default Claude tab), so the config above wires up the widget and the TUI at once.

Hyprland: float the TUI window

By default Hyprland tiles the TUI. To make ai-usagebar-tui open as a centered floating window, the same way Omarchy floats its own settings TUIs (Wi-Fi/impala, audio/wiremix, Bluetooth/bluetui), add this to ~/.config/hypr/hyprland.conf or any sourced .conf, such as looknfeel.conf:

# ai-usagebar TUI — float + center + fixed size. omarchy-launch-tui sets the
# app-id from the binary basename, so the class is org.omarchy.ai-usagebar-tui.
# 875x600 matches the size Omarchy gives its own `floating-window`-tagged TUIs.
windowrule = float on, match:class ^(org\.omarchy\.ai-usagebar-tui)$
windowrule = center on, match:class ^(org\.omarchy\.ai-usagebar-tui)$
windowrule = size 875 600, match:class ^(org\.omarchy\.ai-usagebar-tui)$

Then hyprctl reload (no logout needed).

Omarchy tags a hardcoded list of TUI app-ids with floating-window in ~/.local/share/omarchy/default/hypr/apps/system.conf, which then applies float + center + size 875 600. The rules above set those values directly, so the size is deterministic regardless of which config is sourced first. If you launch the TUI differently (e.g. kitty -e ai-usagebar-tui), replace the class regex with whatever hyprctl clients reports for your terminal.

Hyprland 0.46+ uses the unified windowrule keyword with match:… filters. The older windowrulev2 = …, class:… syntax still works on legacy Hyprland but is deprecated — use the form above on current Omarchy / Hyprland releases.

Vendor support matrix

Vendor Endpoint What you see Native desktop selector (v0.13)
Anthropic api.anthropic.com/api/oauth/usage (undocumented) Session (5h), Weekly (7d), model-scoped weekly (e.g. Fable), Extra usage $ Yes
OpenAI chatgpt.com/backend-api/wham/usage (undocumented; used by official codex CLI) Codex 5h, Codex weekly, Code-review weekly, Credits Yes
Z.AI api.z.ai/api/monitor/usage/quota/limit (undocumented) Session 5h, Weekly 7d, MCP tools monthly Yes
OpenRouter openrouter.ai/api/v1/{credits,key} (documented) Balance, today/week/month spend, free vs paid tier Yes
DeepSeek api.deepseek.com/user/balance (documented) Balance, granted, topped-up credits Yes
Kimi api.kimi.com/coding/v1/usages (undocumented; community-confirmed) Weekly subscription quota + 5h rolling rate-limit window No — widget/TUI only; desktop protocol and marker parity are future work
Kilo api.kilo.ai/api/profile/balance (undocumented; extension-internal) Remaining credit balance ($) No — widget/TUI only
Novita api.novita.ai/openapi/v1/billing/balance/detail (documented) Remaining credit balance ($) No — widget/TUI only
Moonshot api.moonshot.ai|.cn/v1/users/me/balance (documented) Account balance ($ on .ai, ¥ on .cn) No — widget/TUI only
Grok (xAI) management-api.x.ai/v1/billing/teams/{team}/prepaid/balance (Management API; documented) Prepaid credit balance ($) No — widget/TUI only
Anthropic (API) api.anthropic.com/v1/organizations/cost_report (Admin API; documented) Month-to-date spend ($, excludes Priority Tier), optional spend-vs-limit % No — widget/TUI only

Endpoint stability

Four of the six endpoints are undocumented. The Anthropic and OpenAI endpoints are used by their official CLIs (claude and codex), so removing them would break those tools too. That makes them less shaky than scraped web endpoints. Z.AI's monitor endpoint is reverse-engineered from a third-party plugin; treat it as the most fragile one. Kimi's /coding/v1/usages is community-confirmed and used by third-party quota tools; treat it as drift-prone.

When an endpoint drifts, run make smoke. It runs all ignored vendor tests, so the existing Anthropic, OpenAI, Z.AI, and OpenRouter smoke tests still require their respective OAuth credentials or API keys. Kimi alone is optional: its test skips with a diagnostic when KIMI_API_KEY is unset, or run it alone with cargo test --test live kimi_live -- --ignored --nocapture. The live API tests check the exact fields this project depends on and produce a precise failure pointing at what changed. Paste a failure back into Claude Code and the affected types.rs can usually be updated mechanically.

Format placeholders

Shared / Anthropic (claudebar-compatible)

Placeholder Example
{plan} Max 5x
{session_pct}, {session_reset}, {session_bar}, {session_elapsed} 62, 1h 30m, █████████████░░░░░░░, 58
{session_pace}, {session_pace_indicator}, {session_pace_pct}, {session_pace_pts}, {session_pace_delta}, {session_pace_abs_delta} , , 12% ahead, 4pts ahead, 4, 4
{weekly_*} same family for the 7d window
{sonnet_*} same family for the 7d Sonnet window (empty when absent)
{scoped_model}, {scoped_pct}, {scoped_reset}, {scoped_elapsed}, {scoped_bar} Fable, 84, 5d 2h, 27, █████████████████░░░ — first model-scoped weekly window (neutral empty/0/ when absent)
{extra_spent}, {extra_limit}, {extra_pct}, {extra_bar} $2.50, $50.00, 5, █░░░░░░░░░░░░░░░░░░░

OpenAI (Codex OAuth)

{oai_plan}, {oai_session_pct}, {oai_session_reset}, {oai_session_elapsed}, {oai_session_pace}, {oai_session_pace_indicator}, {oai_weekly_*} (same family), {oai_code_review_pct}, {oai_credit_balance}, {oai_local_msgs}, {oai_cloud_msgs}

Z.AI

{zai_plan}, {zai_session_pct}, {zai_session_reset}, {zai_weekly_pct}, {zai_weekly_reset}, {zai_mcp_pct}, {zai_mcp_reset}

OpenRouter

{or_label}, {or_balance}, {or_total}, {or_used}, {or_used_today}, {or_used_week}, {or_used_month}, {or_consumed_pct}, {or_free_tier}, {or_limit}, {or_limit_remaining}, {or_balance_bar}

DeepSeek

{ds_balance}, {ds_granted}, {ds_topped_up}, {ds_available} — credit balance from /user/balance. USD is preferred when both currencies are present; falls back to CNY otherwise.

Kimi

{kimi_plan}, {kimi_weekly_pct}, {kimi_weekly_used}, {kimi_weekly_limit}, {kimi_weekly_remaining}, {kimi_weekly_reset}, {kimi_window_pct}, {kimi_window_used}, {kimi_window_limit}, {kimi_window_remaining}, {kimi_window_reset} — subscription quota + rolling rate-limit window from api.kimi.com/coding/v1/usages. Generic aliases {plan} (plan), {weekly_pct} (weekly usage), and {session_pct} (5h window usage) are also available.

Kilo

{kilo_balance} — remaining credit balance (USD) from api.kilo.ai/api/profile/balance.

Novita

{nv_balance}, {nv_cash}, {nv_credit_limit}, {nv_owed} — account balance and breakdown (USD) from api.novita.ai/openapi/v1/billing/balance/detail.

Moonshot

{km_balance}, {km_voucher}, {km_cash}, {currency} — account balance from api.moonshot.ai|.cn/v1/users/me/balance (USD on .ai, CNY on .cn).

Grok

{grok_balance} — prepaid credit balance (USD) from the xAI Management API (management-api.x.ai).

Anthropic (API)

{aapi_headline}, {aapi_spent}, {aapi_limit}, {aapi_pct} — month-to-date spend for the API/Console account from the Admin API cost_report. The headline is $1.34 / $1000 · 0% when a positive, finite monthly_limit is set in config, $1.34/mo otherwise. Generic aliases {plan}, {session_pct}, and {weekly_pct} are also available (the last two both map to the spend-vs-limit %).

Two things this figure is not. It is spend, not remaining credit — Anthropic exposes no API for the prepaid balance, which is visible only on the Console dashboard. And per the Cost API docs it omits Priority Tier costs, so an organization on Priority Tier is seeing less than its true total spend.

Local development

ai-usagebar --watch 5                              # iterate on --format live
ai-usagebar --vendor openrouter --format '{or_balance} · today {or_used_today}'

make test                                          # unit + integration
source ~/.config/zsh/secrets                       # required for existing vendor smoke tests
make smoke                                         # runs all ignored tests; only Kimi skips without its key
make clippy                                        # cargo clippy -D warnings

TUI controls

ai-usagebar-tui showing the OpenAI tab — Codex 5h and weekly gauges, Credits block with message-count ranges, tabs at top, key hints in the footer

  • Tab / l / — next tab
  • Shift+Tab / h / — previous tab
  • r — refresh active tab
  • R — refresh all tabs
  • s — open Settings overlay (primary vendor + API keys)
  • c — open local Claude context sessions (only when [context] enabled = true); v cycles its layout
  • q / Esc / Ctrl-C — quit

Auto-refresh runs every 60 seconds in the background. Vendors use the same layout. Here's OpenRouter showing the credit balance gauge (red because 98% is consumed), usage-by-period totals, and tier:

ai-usagebar-tui showing the OpenRouter tab — Credit balance gauge at 98% in red ($13.67 left of $900), Usage by period with today/week/month, paid tier

Local context overlay

The optional context overlay answers a different local question from the vendor tabs: how much input context was present in recent Claude Code sessions. Enable it by hand, restart the TUI, and press c:

[context]
enabled = true
layout = "full"                          # full | split | bottom  (`v` cycles)
# projects_path = "~/.claude/projects"  # this is the default
# context_window_tokens = 200000         # optional fallback

# Exact model ids override the fallback when 200K and 1M sessions coexist.
[context.model_context_window_tokens]
"claude-opus-4-6" = 1000000

By default the overlay takes the whole dashboard body — its own screen, not a popup with the vendor panel bleeding around it. v cycles where it sits: fullsplit (beside the vendor panel) → bottom.

Use / or j/k to select a session, Enter for its detail gauge, Esc to return, and r to rescan. The percentage follows Claude Code's status-line definition: input_tokens + cache_creation_input_tokens + cache_read_input_tokens. If no trustworthy window size is configured for a model, the overlay shows the raw token count rather than guessing a percentage. After compaction it shows a waiting state until the next assistant response establishes the new context.

This is a best-effort reader for Claude Code's undocumented local JSONL format, not an API. It reads only bounded tails from the 100 most recently modified top-level sessions, ignores unknown or corrupt lines, skips subagents sidechains, never follows discovered symlinks, and does the filesystem work on the blocking pool so the TUI remains responsive. Nothing under ~/.claude/projects is read while the feature is disabled. Context controls stay in TOML rather than expanding the already-full Settings modal.

Settings overlay

Settings overlay floating over the TUI — Primary vendor radio (Anthropic selected), masked Z.AI API key (•••), masked OpenRouter API key (•••), Save button, key hints at bottom. This older screenshot predates the DeepSeek and Kimi key fields described below.

Press s while the TUI is open. The overlay lets you:

  • Pick the primary vendor that the widget defaults to and that the TUI selects on startup. Use / to cycle.
  • Enter your Z.AI API key, OpenRouter API key, DeepSeek API key, and Kimi API key inline. Keys are masked as you type; press Ctrl-V to reveal or hide them. Env vars (ZAI_API_KEY, OPENROUTER_API_KEY, DEEPSEEK_API_KEY, KIMI_API_KEY) still win at runtime if they're set; the inline key is the fallback. DeepSeek and Kimi remain disabled until their respective config sections set enabled = true.

Saving an API key in the overlay does not enable the vendor — you still need enabled = true in [kimi] or [deepseek] for the widget and TUI to include it.

Key bindings inside the overlay:

  • Tab / ↑↓ — move between fields
  • / — cycle primary-vendor selection (only on the vendor field)
  • Ctrl-V — toggle key visibility on the focused key field
  • Ctrl-S — save and close
  • Esc — discard and close

Save writes to ~/.config/ai-usagebar/config.toml via toml_edit so your existing comments and unrelated fields are preserved. The file is automatically chmod 600ed on save, so inline keys aren't world-readable.

After save, the Settings overlay fires SIGRTMIN+13 so any Waybar module configured with signal: 13 refreshes immediately. You don't need to wait for the next 300-second interval or kick the bar by hand. The TUI's own tabs also re-fetch right away, so a freshly set API key takes effect on the spot.

If your module doesn't use signal: 13, the signal is a no-op and the bar will refresh on its next normal tick (up to interval seconds away). To force-refresh manually: pkill -SIGUSR2 waybar (full reload).

Theming

  • One Dark palette by default.
  • Auto-merges with the active Omarchy theme at ~/.config/omarchy/current/theme/colors.toml.
  • Per-color overrides: --color-low, --color-mid, --color-high, --color-critical (claudebar-compatible).

Changelog

See CHANGELOG.md for the release history. Each release also has its own page at https://github.com/akitaonrails/ai-usagebar/releases with the auto-generated install snippet and checksum.

Acknowledgements

The OpenAI and Anthropic OAuth endpoint references came from claudebar and codexbar, both by mryll. The visual design, including the bordered Pango tooltip, severity colors, and pacing math, is theirs. This project is a Rust port with multi-vendor support.

The Kimi /coding/v1/usages endpoint reference came from community quota tools: CodexBar (steipete), OpenUsage, and OmniRoute.

License

MIT.

About

Rust-based waybar widget to monitor status of Claude, GPT, GLM, OpenRouter plans/credits - inspired by claudebar/codexbar

Resources

License

Stars

196 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors