← Discover MCPs and Agents
a
MCPAI & MLGitHub

ai-agent-status-bar

Universal tmux quota/usage status bar for AI coding CLIs, compatible with Codex, Claude Code, OpenCode, Cline and more.

Links

README

From the repo.

ai-agent-status-bar

A single tmux status bar that shows the quota of whichever AI coding CLI you happen to be running — OpenCode Go or its Z.AI GLM Coding Plan (toggleable with F12), Cline/ClinePass, Command Code, Codex, or Claude Code — next to a clock.

Cline        ClinePass 5h 100% (3h02m) · W 50% (19/08) · M 43% (30/08) | 16/08/2026 13:44
OpenCode     Go 5h 99% (4h58m) · W 100% (16/08) · M 100% (16/09) | 16/08/2026 18:51
             Lite (Z.AI) 5h 95% (4h31m) · W 99% (16/08)          | (after F12)
Command Code Goat 5h 99% (4h58m) · W 100% (24/08) · M 86% (17/09) | 17/08/2026 18:51
Codex        Plus W 11% (20/08) | 16/08/2026 13:44
Claude Code  Team 5h 100% (29m) · W 95% (22/08) | 16/08/2026 13:44

This is the unified successor to three sibling projects (opencode-go-tmux-status-bar, cline-cli-clinepass-tmux-status-bar, command-code-tmux-status-bar). They shared ~80% of their code — caching, colour thresholds, countdown rendering, the tmux launcher flow, the installer — and differed only in where the numbers come from. That difference is now the only thing a new harness needs to contribute; everything else lives in a shared core.

Percentages are quota remaining, coloured by how much is left (green > 50%, amber > 20%, red below). The bracketed figure is when that window resets: a live countdown for the fast-moving 5-hour window, a date for the slower weekly and monthly ones. A trailing ~ means the refresh failed and the last known values are being shown.

The bar appears only when you launch a harness through it, and disappears with it. Nothing starts a multiplexer behind your back, and no AI CLI is ever modified — the providers read credentials the CLIs already write and call the corresponding billing/usage APIs directly.

Architecture

ai-agent-status-bar/
├── README.md
├── LICENSE
├── install.sh                  # one installer for all providers
├── lib/
│   ├── core.sh                 # cache TTL, fallback, colours, countdown,
│   │                           #   rendering, plan toggle, tmux session setup
│   └── providers/
│       ├── opencodego.sh       # first-party Go usage API (curl)
│       ├── opencodezai.sh      # Z.AI GLM Coding Plan monitor API (curl)
│       ├── clinepass.sh        # ClinePass usage-limits API (curl)
│       ├── commandcode.sh      # billing API (curl) + plan-cap table
│       ├── codex.sh            # chatgpt.com wham/usage (curl) — Codex
│       └── claudecode.sh       # api.anthropic.com oauth/usage (curl) — Claude
├── bin/
│   ├── ai-bar-quota            # dispatcher: auto-detect or AI_BAR_PROVIDER
│   ├── ai-bar-toggle           # F12 helper: swap a bar between sibling plans
│   ├── ai-bar-tmux             # generic launcher (--tool opencode|cline|command-code|<bin>)
│   └── wrappers/               # compatibility shims for the old command names
│       ├── _template.sh        #   one shim, symlinked under each legacy name
│       ├── opencodego-quota, opencodego-tmux
│       ├── opencodezai-quota, opencodezai-tmux
│       ├── clinepass-quota, clinepass-tmux
│       ├── commandcode-quota, commandcode-tmux
│       ├── codex-quota, codex-tmux
│       └── claudecode-quota, claudecode-tmux
├── tmux/
│   └── bar.conf                # the bar as a global config (optional)
└── shell/
    └── bashrc-snippet.sh       # harness aliases (opencode/cline/command-code)

Core / provider split. lib/core.sh is harness-agnostic: it owns the cache (TTL, stale fallback, field-count guard), the colour thresholds, the countdown and date rendering, the tmux session-setup, and the launcher flow. Each file under lib/providers/ implements a small adapter contract — only the fetching and normalisation of that harness's numbers — and nothing else. Adding a new AI coding CLI is, in the common case, a single new file under lib/providers/. See Adding a new provider below.

How the bar is applied

status-right is a session option in tmux, not a server-wide one: ai-bar-tmux creates its session and then sets that session's status line, palette included, so the bar shows only while you are in a session launched through it. Whatever ~/.tmux.conf defines globally — your own dotfiles, or another quota bar — is never touched and keeps governing every other session. Run opencode and you see the Go bar; run cline and you see the ClinePass bar; run command-code and you see the Goat/Pro/Max bar; run codex and you see the Plus bar; run claude and you see the Team bar — even concurrently on the same tmux server. Install order does not matter, and nothing is ever written to ~/.tmux.conf.

tmux/bar.conf is kept for anyone who wants a bar globally; wiring it up by hand is ln -s tmux/bar.conf ~/.tmux.conf. On a machine with no tmux config at all there is nothing to do: the session options carry the whole bar.

Requirements

  • Linux (tested on Ubuntu 26.04 under WSL2, x86_64)
  • At least one of:
    • OpenCode with the OpenCode Go provider connected (/connect in the TUI), and optionally the Z.AI GLM Coding Plan too (zai-coding-plan) to alternate between them with F12
    • Cline CLI signed in to ClinePass, or a Cline API key
    • Command Code (npm i -g command-code, then command-code login)
    • Codex (npm i -g @openai/codex or brew install codex, then codex login)
    • Claude Code (npm i -g @anthropic-ai/claude-code, then claude login)
  • jq, curl, tmux
  • A terminal about 110 columns wide, or the bar gets clipped from the left
  • No root: everything lands under ~/.local

Install

git clone <this repo> ai-agent-status-bar
cd ai-agent-status-bar
./install.sh

Then open a new shell and run a harness as usual (opencode, cline, command-code, codex, or claude). The installer is safe to re-run, backs up anything it would overwrite, and never touches ~/.tmux.conf.

By default every provider found under lib/providers/ is installed. To install only specific ones:

./install.sh --provider opencodego --provider clinepass
FlagEffect
--provider Xinstall only provider X (repeatable)
--allinstall all providers (default)
--helpshow usage
--no-codexbarno-op (kept for backwards compat)

What the installer does

  1. Prerequisites — checks jq, curl, tmux.
  2. Core scripts — symlinks bin/ai-bar-quota, bin/ai-bar-toggle, bin/ai-bar-tmux into ~/.local/bin (shared by all providers).
  3. Legacy wrappers — for each selected provider, symlinks the old command names (opencodego-quota, clinepass-quota, commandcode-quota, codex-quota, claudecode-quota, …) so existing tmux configs and muscle memory keep working.
  4. tmux — nothing: the bar is applied per-session by ai-bar-tmux.
  5. Shell aliases — adds one block to ~/.bashrc that sources shell/bashrc-snippet.sh, defining opencode/cline/command-code/codex/claude aliases (each only when its launcher is installed).

Symlinks rather than copies: the clone stays the single source of truth, git pull updates every machine at once, and git status surfaces local drift instead of hiding it.

Usage

Run a harness with the bar

opencode        # alias -> ai-bar-tmux --tool opencode
cline           # alias -> ai-bar-tmux --tool cline
command-code    # alias -> ai-bar-tmux --tool command-code
codex           # alias -> ai-bar-tmux --tool codex
claude          # alias -> ai-bar-tmux --tool claude

Or explicitly, pinning a provider so the right bar shows regardless of auto-detection:

ai-bar-tmux --tool opencode --provider opencodego

Inside an existing tmux or when tmux is absent, the harness runs directly (no nesting, no second status bar).

Render the block standalone

The helper script prints plain text by default and tmux colour markup with --tmux, so it is equally usable from a shell:

$ ai-bar-quota
Go 5h 99% (4h58m) · W 100% (16/08) · M 100% (16/09)

$ AI_BAR_PROVIDER=opencodezai ai-bar-quota
Lite 5h 95% (4h31m) · W 99% (16/08)   # Z.AI GLM Coding Plan

$ ai-bar-quota --tmux
#[fg=colour245]Go #[fg=colour114]5h 99% (4h58m) · W 100% (16/08) · M 100% (16/09)#[fg=colour238] | #[default]

Alternate between plans (F12)

When both OpenCode plan keys exist (opencode-go and zai-coding-plan in ~/.local/share/opencode/auth.json), the Go-pinned bar becomes multi-plan: press F12 inside the session to swap the slot between Go … and Lite/Pro … (the Z.AI plan's level). The choice lives in a small per-session state file under ~/.cache/ai-bar/sessions/, so it survives relaunches, and every plan keeps its own quota cache either way. Only plans whose credentials are actually present take part in the cycle — with one key there is nothing to swap and the bar stays static.

Change the key with AI_BAR_TOGGLE_KEY; disable by unsetting the declaring provider's PROVIDER_TOGGLE_LIST. Two caveats worth knowing:

  • The F12 binding lives in tmux's root (global) key table, so with several live multi-plan sessions the most recently launched one owns the shared key; pressing it anywhere else just no-ops.
  • Bare F12 stops reaching the terminal application while such a session is attached. Pick a different key via AI_BAR_TOGGLE_KEY if yours uses it.

Pin / override the provider

Auto-detection tries, in order: $AI_BAR_PROVIDER, the first provider whose gate_check passes, then the first whose HARNESS_BIN is on PATH. To force a specific provider:

AI_BAR_PROVIDER=opencodego ai-bar-quota

Legacy command names

The old per-tool commands still work, pinning the matching provider:

opencodego-quota          # -> ai-bar-quota with AI_BAR_PROVIDER=opencodego
clinepass-quota --tmux    # -> ai-bar-quota --tmux with AI_BAR_PROVIDER=clinepass

Configuration

Per-provider TTL env vars control how often the network is hit; the bar redraws on tmux's status-interval (1s in the optional global config, 5s for multi-plan sessions so F12 feels instant, otherwise tmux's default) and only one real API request goes out per TTL window.

VariableDefaultProviderEffect
OPENCODEGO_QUOTA_TTL30opencodegoSeconds between Go usage API calls
OPENCODEGO_API_BASEhttps://opencode.aiopencodegoOverride the first-party API base URL
OPENCODEZAI_QUOTA_TTL30opencodezaiSeconds between Z.AI quota API calls
OPENCODEZAI_API_BASEhttps://api.z.aiopencodezaiOverride the Z.AI monitor API base URL
OPENCODEZAI_QUOTA_ALWAYSopencodezaiShow the Z.AI block even without a plan key on disk
CLINEPASS_QUOTA_TTL30clinepassSeconds between usage calls
CLINEPASS_QUOTA_ALWAYS0clinepass1 shows the quota even when ClinePass is not the active provider
CLINE_API_KEYclinepassPreferred Cline API key; otherwise a valid local OAuth token is tried
CLINEPASS_API_KEYclinepassCompatibility alias for CLINE_API_KEY
CLINEPASS_API_BASEhttps://api.cline.botclinepassOverride the usage-limits API base URL
COMMANDCODE_QUOTA_TTL30commandcodeSeconds between billing API calls
COMMAND_CODE_API_KEYcommandcodeOverride the API key (otherwise read from ~/.commandcode/auth.json)
COMMANDCODE_API_BASEhttps://api.commandcode.aicommandcodeOverride the billing API base URL
CODEX_QUOTA_TTL30codexSeconds between wham/usage calls
CODEX_API_BASEhttps://chatgpt.comcodexOverride the wham/usage API base URL
CLAUDECODE_QUOTA_TTL30claudecodeSeconds between oauth/usage calls
CLAUDE_API_BASEhttps://api.anthropic.comclaudecodeOverride the oauth/usage API base URL
AI_BAR_PROVIDERallPin the provider, skipping auto-detection
AI_BAR_TMUX_RIGHT_LEN110allstatus-right-length for launched sessions
AI_BAR_TOGGLE_KEYF12multi-plan barsKey that swaps the bar between sibling plans
AI_BAR_STATUS_INTERVAL5multi-plan barsSession status-interval while a toggleable bar is applied

To change a refresh rate permanently, edit the default in the provider file under lib/providers/.

How it works

ai-bar-quota runs this flow for the detected provider:

  1. Serve fresh cache — if the cached values are younger than the TTL and the field count matches CACHE_FIELDS, render them and exit. No network.
  2. Gate check — the provider may hide the block entirely (no key configured, a different provider active, …). Silent for status bars, explanatory when a human runs the script by hand.
  3. Fetch — call fetch_quota, which returns one line of normalised values: label fp fr wp wr mp mr. Percentages are remaining (0-100, or -1 to omit a window); resets are epochs (0 = unknown). The cache is written and the values rendered.
  4. Degrade — on any failure, render the stale cache (with a trailing ~) if available, else n/d. A stale number beats a blank bar.

The block carries its own trailing separator, so it disappears cleanly instead of leaving an orphan | behind when there is nothing to show.

Per-provider data sources

ProviderQuota sourceGate
opencodegoGET https://opencode.ai/zen/go/v1/usage with the Go key from ~/.local/share/opencode/auth.jsonOpenCode Go key present
opencodezaiGET https://api.z.ai/api/monitor/usage/quota/limit with the zai-coding-plan key from the same auth.json; 5-hour + weekly credit windows, label from the subscribed level (Lite, Pro, …, bare ZAI when unknown). Quirk: this endpoint wants the raw key (Authorization: <key>, no Bearer)OpenCode Z.AI coding-plan key present (or OPENCODEZAI_QUOTA_ALWAYS=1)
clinepassGET https://api.cline.bot/api/v1/users/me/plan/usage-limits; CLINE_API_KEY first, then unexpired OAuth tokens from ~/.cline/data/settings/providers.jsonlastUsedProvider == cline-pass or cline (or CLINEPASS_QUOTA_ALWAYS=1)
commandcodecurl to /alpha/billing/credits + /alpha/billing/subscriptions (best-effort /alpha/whoami for orgId) with the key from ~/.commandcode/auth.json or COMMAND_CODE_API_KEYAPI key present
codexcurl to /backend-api/wham/usage with the ChatGPT access_token from ~/.codex/auth.json~/.codex/auth.json with tokens.access_token
claudecodecurl to /api/oauth/usage with the OAuth accessToken from ~/.claude/.credentials.json (field claudeAiOauth.accessToken)~/.claude/.credentials.json with claudeAiOauth.accessToken

For commandcode, the 5-hour and weekly windows come straight from the credits payload's windowLimits; the monthly window is derived — plan cap (looked up from the same per-plan table the TUI's /usage overlay uses) minus remaining monthly credits. Purchased and free credits are excluded: they do not reset at period end and would mask exhaustion. The block label is the plan's short name (Go, Goat, Pro, Max, Ultra, Provider, TeamsPro), resolved from planId and cached with the figures so it survives failed refreshes.

Adding a new provider

A new AI coding CLI needs one file: lib/providers/<name>.sh. It is sourced by core.sh and implements the adapter contract. Nothing else in the project needs to change — install.sh auto-discovers providers via glob, the dispatchers auto-detect via gate_check / HARNESS_BIN, and the launcher accepts any binary via --tool <bin>.

Minimal provider

# lib/providers/myagent.sh
if [ -n "${_AI_BAR_PROVIDER_MYAGENT:-}" ]; then
  unset -f gate_check plan_label 2>/dev/null
  unset _AI_BAR_PROVIDER_MYAGENT
fi
_AI_BAR_PROVIDER_MYAGENT=1

PROVIDER_ID="myagent"
PROVIDER_LABEL="MyAgent"          # default block label
CACHE_FIELDS=7                    # label + 6 (3 windows × pct,reset)
QUOTA_TTL_ENV="MYAGENT_QUOTA_TTL"
HARNESS_BIN="myagent"             # for auto-detection + --tool alias
# (no external binary beyond jq/curl; providers are fully autonomous)

# fetch_quota: stdout = "label fp fr wp wr mp mr"
#   fp/wp/mp: percent REMAINING (0-100), or -1 to omit that window
#   fr/wr/mr: reset epoch seconds (0 = unknown)
#   return non-zero on hard failure; the core handles stale-cache / n/d.
fetch_quota() {
  local json
  json=$(myagent-usage --json 2>/dev/null) || return 1
  printf '%s' "$json" | jq -er '
    def clamp: round | if . < 0 then 0 elif . > 100 then 100 else . end;
    def epoch:
      if type == "number" then .
      elif type == "string" and . != ""
      then (sub("\\.[0-9]+"; "") | try fromdate catch 0)
      else 0 end;
    [ "MyAgent",
      (100 - .fiveHour.usedPercent  | clamp), (.fiveHour.resetsAt | epoch),
      (100 - .weekly.usedPercent    | clamp), (.weekly.resetsAt   | epoch),
      (100 - .monthly.usedPercent   | clamp), (.monthly.resetsAt  | epoch) ]
    | map(tostring) | join(" ")
  '
}

Optional hooks

FunctionDefaultWhen to override
gate_checkalways passhide the block when the provider is not active (no key, wrong provider, …). Print an explanation only when ai_bar_mode = plain.
plan_labelpass throughwhen the block label is dynamic (e.g. commandcode resolves it from planId).

Variables

VariableRequiredMeaning
PROVIDER_IDyes (defaults to filename)cache directory name
PROVIDER_LABELyesdefault block label / fallback
CACHE_FIELDSyes (default 6)field count the cache must have to be valid
QUOTA_TTL_ENVyes (default AI_BAR_QUOTA_TTL)env var overriding the 30s TTL
HARNESS_BINrecommendedharness binary name, for auto-detection and --tool
PROVIDER_TOGGLE_LISTnospace-separated sibling ids AI_BAR_TOGGLE_KEY (F12) may cycle through while this provider owns the bar; declare it in every participating provider so a pinned sibling stays toggleable too

Install / wrapper

./install.sh picks up the new provider automatically. To add a legacy wrapper name, drop a symlink in bin/wrappers/ following the existing convention (<name>-quota, <name>-tmux_template.sh) and add a case to the case "$p" in block in install.sh if the legacy names differ from the provider id.

Things that are not obvious

These cost real debugging time, inherited from the three original projects.

Fully autonomous for all six providers — every adapter uses curl + jq; CodexBar is not installed or invoked. --no-codexbar remains accepted as a deprecated no-op so existing installation scripts do not break.

OpenCode Go's usage endpoint is first-party but new. /zen/go/v1/usage returns the server-side rolling, weekly, and monthly windows and accepts the same key stored after /connect. It is deployed but not yet listed with the documented model endpoints, so failures degrade to the stale cache; the adapter does not fabricate a local estimate.

CodexBar has a commandcode provider but it does not work on Linux. Its usage source is web-only and the CLI answers "only supported on macOS". The commandcode provider here calls the billing API with curl instead, exactly like the TUI mod.

resetAt (commandcode) arrives in three shapes. Epoch milliseconds, epoch seconds, or an ISO string depending on the endpoint — and the ISO strings carry fractional seconds and non-Z offsets, which jq's fromdate rejects as-is. The parser normalises all of them; anything before ~1973 in milliseconds is implausible for a reset date, so that is how seconds and milliseconds are told apart.

The plan-cap table is duplicated from the mod, longest-prefix-first. The product's own order matches individual-go before individual-goat after a plan upgrade; the copy here keeps the corrected order. If Command Code adds plans, update the table in lib/providers/commandcode.sh.

expiresAt in Cline's providers.json is in milliseconds. Comparing it against date +%s makes valid tokens look long expired.

A Cline API key is the reliable ClinePass credential. Create one under Settings → API Keys and export it as CLINE_API_KEY. As a zero-config fallback the adapter tries unexpired workos: account tokens from providers.json, but deliberately does not refresh or rewrite them. Cline uses a five-minute refresh margin, and the adapter excludes tokens inside that margin rather than racing their expiry.

OpenCode has no readable "active provider" flag on disk. Nothing as cheap as a JSON field says whether Go is the provider in use right now, so the opencodego block shows whenever a Go key is configured, in any tmux session. The F12 toggle exists precisely because of this: instead of guessing which plan is hot, the two plans share one slot and you pick with a keystroke.

The Z.AI coding-plan quota endpoint is official but undocumented. /api/monitor/usage/quota/limit is what Z.AI's own @z_ai/coding-helper plugin queries; it wants the raw key, not Bearer, and reports percent used with epoch-millisecond resets. Schema drift degrades to the stale cache like any other provider.

tmux runs #() through a non-interactive sh whose PATH has no ~/.local/bin. The scripts prepend it themselves rather than trusting the caller. $HOME is expanded inside #(), which is what keeps tmux/bar.conf free of absolute paths.

tmux only runs status jobs for an attached client. A detached session never draws its status bar, so #() never fires — worth knowing before concluding that a config is broken. tmux display-message -p '#{T:status-right}' does not run jobs either, so it is useless for testing this.

tmux loads ~/.tmux.conf once per server. Only relevant if you wired tmux/bar.conf up globally by hand: a server that was already running keeps serving the old bar until it exits (tmux kill-server when nothing valuable is open). Session options like the ones ai-bar-tmux applies are immune to this, which is one more reason the bar is applied per session.

Uninstall

./uninstall.sh            # remove symlinks + bashrc block
./uninstall.sh --purge    # also remove cache, legacy CodexBar, and warn about sources

Safe to re-run, backs up ~/.bashrc before editing. The script only removes symlinks that point back into this repo, so a hand-placed file with the same name is left alone. --purge does not rm -rf the repo itself (the script is running from inside it); it prints the path and the command to run.

Manual uninstall (equivalent):

rm ~/.local/bin/{ai-bar-quota,ai-bar-toggle,ai-bar-tmux}
rm ~/.local/bin/{opencodego,opencodezai,clinepass,commandcode,codex,claudecode}-{quota,tmux}

# Legacy CodexBar installed by ai-agent-status-bar <= 0.2 (if unused elsewhere)
rm -rf ~/.local/lib/codexbar ~/.local/bin/codexbar

# Cache
rm -rf ~/.cache/ai-bar

Then delete the block marked ai-agent-status-bar from ~/.bashrc. Backups made by install.sh / uninstall.sh are named *.bak-<timestamp> next to each original.

Migration from the per-tool repos

The unified project is a drop-in replacement. The old per-tool command names keep working through wrappers, and the old tmux configs that reference them need no edits. To migrate:

  1. ./install.sh (installs all providers and the legacy wrappers).
  2. Remove the old per-tool checkout and its symlinks (the installer's backup() will have preserved any pre-existing files it overwrote).
  3. The old clinepass-quota-bar / opencodego-quota-bar / commandcode-quota-bar blocks in ~/.bashrc are superseded by the single ai-agent-status-bar block; remove the old ones to avoid double-aliasing.

License

MIT — see LICENSE.

Tests

./tests/run.sh

The suite uses an isolated temporary HOME and a deterministic curl mock; it performs no network requests and never reads real credentials.

Credits

All six providers are fetched directly with curl + jq; CodexBar is not a runtime dependency. The ClinePass endpoint/schema and the historical OpenCode local-estimation behaviour were cross-checked against CodexBar. The Z.AI GLM Coding Plan adapter mirrors the query performed by Z.AI's own @z_ai/coding-helper plugin (api.z.ai/api/monitor/usage/quota/limit, raw-key auth), keyed by the zai-coding-plan entry OpenCode writes at /connect. Command Code quota semantics (derived monthly window, plan-cap table, defensive parsing) mirror the command-code-quota-status-bar TUI mod. Codex quota comes from chatgpt.com/backend-api/wham/usage with the ChatGPT login token that Codex stores at ~/.codex/auth.json (same pattern as Command Code: read at call time, Bearer header only). Claude Code quota comes from api.anthropic.com/api/oauth/usage with the OAuth token at ~/.claude/.credentials.json (claudeAiOauth.accessToken, 5h + weekly windows, plan-aware label). This unified project supersedes the three sibling repos opencode-go-tmux-status-bar, cline-cli-clinepass-tmux-status-bar, and command-code-tmux-status-bar.

Collected info

  • 0 stars
  • Language: Shell
  • Source updated: 8/27/2026

Config for your environment

Replace {MCP_ENDPOINT_URL} with this MCP’s endpoint URL (from its repo or docs above). No API key — you connect directly.

Tool

OS

Config file: ~/.cursor/mcp.json

{
  "mcpServers": {
    "mcp-server": {
      "url": "{MCP_ENDPOINT_URL}"
    }
  }
}

Paste into mcpServers in the config file. Restart Cursor after saving.

If this MCP is also published on mcpchannel.ai, you can subscribe from Browse and use the gateway config there instead.