Multi-provider quota + cost + burn-rate statusline plugin for OpenCode's TUI. Reuses the same Python rendering pipeline as
claude-llm-quota-bar— one bar, two editors.
|
Plugin e curadoria por @lpdigital.me — Philipe compartilha plugins, automações e IA toda semana no Instagram. Manda um follow se a barra te ajudou. |
[MiniMax-M3·minimax] • 📁 ~/meu-projeto • 📟 v1.17.8
⬆12.5K ⬇3.2K ⚡cache 25% • 🧠 12% usado (88% livre) • ⏱ 1.2M / 50M tokens (2%)
🇧🇷 R$0,37 🇺🇸 $0.06 • ⌛ 12m • ⚡ 1.3K t/m
Three lines, updated after every model response — identical in Claude Code and OpenCode.
- Model & provider — active model name with provider badge (MiniMax, OpenRouter, DeepSeek, Mistral, OpenAI, Codex, Anthropic)
- Token counters — ⬆ input / ⬇ output with cache read/write breakdown
- Context window — percentage used with color-coded warnings (🧠)
- Provider quota — remaining tokens on your Token Plan (⏱), with warn/alert thresholds
- Real-time cost — estimated spend in BRL and USD, with burn-rate emoji (🧊 calm / ⚡ busy / 🔥 heavy)
- Session duration — elapsed time since session start (⌛)
- Two output modes — sticky TUI toast (never disappears) or log panel (
:open-logs) - Zero runtime deps — the vendored Python script uses stdlib only; the plugin imports only Node built-ins
| Provider | Quota endpoint | Env var |
|---|---|---|
| MiniMax | Token Plan API | MINIMAX_API_KEY |
| OpenRouter | Credits endpoint | OPENROUTER_API_KEY |
| DeepSeek | Balance API | DEEPSEEK_API_KEY |
| Mistral | Usage API | MISTRAL_API_KEY |
| OpenAI | Credit grants (admin key) | OPENAI_API_KEY |
| Codex | Session-based tracking | (built-in) |
Missing a key? That segment is silently omitted — no errors, no stack traces.
OpenCode's built-in statusline is a one-liner with the model name. If you juggle multiple LLM providers (MiniMax, OpenRouter, DeepSeek, Mistral, OpenAI, Codex, etc.) you usually want to know at a glance:
- How much of your Token Plan has been burned in the last 5h
- How many credits remain on OpenRouter
- Your burn rate (tokens/min) and projected cost
- The context window usage for the current model
- Whether you're approaching a rate limit or hitting cache discounts
Rather than reimplement that logic against OpenCode's event payloads, this
plugin forwards the OpenCode session into the same Python statusline script
that powers claude-llm-quota-bar under Claude Code. The bar looks
identical in both editors.
| Variant | File | Output | Best for |
|---|---|---|---|
| Log panel (v1.0.0) | plugins/llm-statusline.ts |
bar in OpenCode's log panel (:open-logs) |
Quiet users who don't want popups |
| Toast popup (v1.2.0) | plugins/llm-statusline.toast.ts |
Sticky TUI toast (never disappears) + :open-logs backup |
Users who want the bar always visible |
Both variants share the same Python script and the same quota adapters.
┌──────────────────┐ session.idle ┌──────────────────────┐
│ OpenCode TUI │ ───────────────► │ llm-statusline*.ts │
│ (any LLM model) │ │ (plugin) │
└──────────────────┘ └──────────┬───────────┘
│
│ append JSONL
▼
~/.claude/projects/<hash>/
<sessionId>.jsonl
│
│ CLAUDE_PROJECT_DIR
│ CLAUDE_SESSION_ID
▼
┌──────────────────────┐
│ python/session_tokens.py
│ (vendored self-contained)
└──────────┬───────────┘
│ stdout (3 lines)
▼
client.app.log() OR client.tui.showToast()
(log panel) (toast popup)
- OpenCode fires
session.idleafter each model response. - The plugin queries
client.session.messages()for token totals from the AssistantMessage payload. - It writes a Claude-Code-compatible JSONL entry so the Python script can read it like a real Claude Code session.
- It spawns
python/session_tokens.pywith the project cwd, session id, and a synthesised stdin payload. - The script's rendered 3-line bar is delivered through
client.app.log()(log panel variant) orclient.tui.showToast()(toast variant).
Copy the prompt below and paste it into any AI chat (ChatGPT, Claude, Gemini, etc.). The assistant will install this statusline plugin end-to-end on your machine — no programming knowledge required on your side.
Click to reveal the install prompt — copy everything inside the box
You are helping me install "opencode-llm-statusline", a plugin for
[OpenCode][oc] (the AI coding TUI) that adds a statusline showing
the active model, token usage, cost in USD, context window %, and
burn rate. It comes in two variants: a toast popup (v1.2.0, default)
or a log-panel renderer (v1.0.0). Both are written in TypeScript and
install as a single `.ts` file symlinked into the OpenCode plugins
directory.
Your job: install it on my machine end-to-end and verify it works.
Do not ask me coding questions — make sensible decisions and tell me
what you did. If you hit a step that needs my input (e.g. which
variant I prefer), ask exactly one focused question and continue.
=========================================================
STEP 1 — Detect my environment
=========================================================
Run these commands and remember the output:
uname -a # OS family (Darwin / Linux / Windows-bash)
command -v opencode # is OpenCode already installed? which version?
opencode --version # need >= 0.5
command -v node # need Node.js >= 18
node --version
command -v python3 # need Python 3.10+ (for the helper script)
python3 --version
echo "PLUG_DIR=${OPENCODE_PLUGINS_DIR:-$HOME/.config/opencode/plugins}"
If `opencode` is missing, tell me to install it from
https://opencode.ai/docs and stop. If `node` is missing, install it
from https://nodejs.org (LTS recommended) and stop. If `python3` is
missing, install it from https://python.org and stop.
=========================================================
STEP 2 — Choose the variant
=========================================================
Ask me ONE question: "Which variant do you want?"
- **Toast popup (v1.2.0, recommended)** — a non-intrusive toast at
the top of the TUI that fades in/out. Good for short summaries
(model, tokens, cost, ctx %).
- **Log panel (v1.0.0)** — appends each turn's usage to a dedicated
log buffer inside the TUI. Good for long sessions where you want
the historical context.
Default to toast unless I say otherwise. Remember my choice for
STEP 3.
=========================================================
STEP 3 — Clone and symlink
=========================================================
Run:
git clone https://github.com/philipecomputacao/opencode-llm-statusline.git
cd opencode-llm-statusline
mkdir -p ~/.config/opencode/plugins
# If I chose toast:
ln -sf "$(pwd)/plugins/llm-statusline.toast.ts" \
~/.config/opencode/plugins/llm-statusline.ts
# If I chose log panel:
ln -sf "$(pwd)/plugins/llm-statusline.ts" \
~/.config/opencode/plugins/llm-statusline.ts
Verify the symlink:
ls -l ~/.config/opencode/plugins/llm-statusline.ts
# expect: ... -> /<absolute path>/llm-statusline.ts or .toast.ts
If the symlink points to a non-existent file, you cloned to a
different path than the symlink — `cd` into the clone dir and re-run
the `ln -sf` command with `$(pwd)` substituted for the current
absolute path.
=========================================================
STEP 4 — Register the plugin in OpenCode
=========================================================
Open the file ~/.config/opencode/config.json (or the equivalent
config file the opencode CLI uses — check `opencode --help` or
`opencode config docs`). Add the plugin entry:
{
"plugins": {
"llm-statusline": {
"path": "~/.config/opencode/plugins/llm-statusline.ts"
}
}
}
If config.json already exists with other settings, MERGE this block
into the existing "plugins" object — don't overwrite anything else.
Verify the JSON is valid with:
python3 -m json.tool < ~/.config/opencode/config.json > /dev/null \
&& echo "config.json is valid JSON"
If that command errors, paste me the error and the config.json
contents (without API keys) so I can see the syntax mistake.
=========================================================
STEP 5 — Verify it works
=========================================================
Restart OpenCode (close and reopen the TUI). Type any short prompt.
You should see either:
- A toast popup at the top of the TUI with the model name, token
counts, and a cost line (if you chose the toast variant).
- A new "LLM" log panel that updates on each turn (if you chose
the log panel variant).
If nothing appears, the most common cause is that the plugin path
in config.json doesn't match the symlink target. Run:
ls -l ~/.config/opencode/plugins/llm-statusline.ts
realpath ~/.config/opencode/plugins/llm-statusline.ts
Both should point to the same file inside the cloned repo. Fix
the config.json "path" if they don't match.
=========================================================
STEP 6 — Optional: enable cost tracking
=========================================================
The statusline shows cost in USD for any model with a known price.
No configuration needed — the bundled pricing data covers OpenAI,
Anthropic, Google, Mistral, and DeepSeek. If you route through a
custom gateway, you can extend the pricing list by editing
`lib/pricing.json` inside the cloned repo and restarting OpenCode.
=========================================================
DONE — Tell me what you did
=========================================================
Summarise in 3-5 bullet points:
- which variant I picked
- the absolute path to the symlink target
- the contents of my config.json plugins block
- whether STEP 5 verification passed
- any caveats or things I should know
If anything failed, give me the exact error message and the command
that produced it. Don't try to fix it silently — surface it.
- OpenCode
>= 0.5(tested on1.17.8) - Node.js
>= 18(fornode:child_processandnode:url) - Python 3.10+ on
PATH(the script uses match/case,int | None) - A POSIX-ish shell (Linux, macOS, WSL). Not tested on Windows native.
git clone https://github.com/philipecomputacao/opencode-llm-statusline.git
cd opencode-llm-statuslineFor the toast popup variant (v1.2.0, recommended):
mkdir -p ~/.config/opencode/plugins
ln -sf "$(pwd)/plugins/llm-statusline.toast.ts" \
~/.config/opencode/plugins/llm-statusline.tsFor the log panel variant (v1.0.0):
ln -sf "$(pwd)/plugins/llm-statusline.ts" \
~/.config/opencode/plugins/llm-statusline.tsEdit ~/.config/opencode/opencode.jsonc:
The ./ is resolved relative to ~/.config/opencode/ and points at the
symlink you created above.
The Python script reads keys from the shell environment when it runs. Without keys, the corresponding quota segment is silently omitted — no errors, no stack traces.
# ~/.zshrc or ~/.bashrc — REPLACE the placeholder values with your real keys.
export MINIMAX_API_KEY=<your-MiniMax-token-plan-key>
export OPENROUTER_API_KEY=<your-openrouter-key>
export DEEPSEEK_API_KEY=<your-deepseek-key>
export MISTRAL_API_KEY=<your-mistral-key>
# Admin-only — for OpenAI credit-grants dashboard:
export OPENAI_API_KEY=<your-openai-admin-key>See the full list of supported providers and quota endpoints in the
claude-llm-quota-bar README.
Plugins are loaded at boot. Send any prompt and the toast should fire (variant 1.2.0) or the bar should appear in the log panel (variant 1.0.0).
This plugin ships with sensible defaults. Tweak via env vars:
| Env var | Default | Effect |
|---|---|---|
LLM_STATUSLINE_PYTHON |
python3 |
Python interpreter to spawn |
LLM_STATUSLINE_TOAST_MS |
0 (sticky) |
Toast duration in ms. 0 = never auto-dismiss |
OPENCODE_PROJECT_DIR |
(shell cwd) | Override the folder shown in the bar |
All other behaviour (which segments to render, colour thresholds, FX cache
TTL, etc.) lives in the vendored
python/statusline.env.json — copy it to
~/.config/opencode-llm-statusline/statusline.env.json (or set the
STATUSLINE_ENV env var) to override.
- Confirm OpenCode loaded the plugin:
You should see
tail -100 ~/.local/share/opencode/log/opencode.log | grep -i "llm-statusline"
Plugin loadedfor each OpenCode boot. - Confirm the symlink resolves:
The target must exist.
ls -la ~/.config/opencode/plugins/llm-statusline.ts - Run the Python script by hand:
It should print three lines. If it errors, the Python script itself is broken (file a bug).
echo '{"model":{"id":"minimax/MiniMax-M3"},"workspace":{"current_dir":"/tmp"},"version":"1.17.8","context_window":{"used_percentage":0},"cost":{"total_duration_ms":0}}' \ | CLAUDE_PROJECT_DIR=/tmp CLAUDE_SESSION_ID=test \ python3 "$(pwd)/python/session_tokens.py"
OpenCode 1.17.8 plugin SDK does not expose tool-call parts (see CHANGELOG.md for details), so the plugin can't see where the agent is reading files from. Two workarounds:
- Launch OpenCode from inside the project:
cd /path/to/project opencode - Or set
OPENCODE_PROJECT_DIR=/path/to/projectin the shell before launching OpenCode.
The ⏱ segment only renders when the active model matches a provider with a
wired-up quota adapter and the matching API key is in the environment.
See claude-llm-quota-bar's provider table for the full list.
Set LLM_STATUSLINE_PYTHON to the full path, e.g.:
export LLM_STATUSLINE_PYTHON=/opt/homebrew/bin/python3.12git clone https://github.com/philipecomputacao/opencode-llm-statusline.git
cd opencode-llm-statusline
# Symlink for live testing
ln -sf "$(pwd)/plugins/llm-statusline.toast.ts" \
~/.config/opencode/plugins/llm-statusline.ts
# Run the CI smoke test locally (Python + TypeScript syntax)
.github/workflows/smoke-test.ymlSee CONTRIBUTING.md for commit conventions, code style, and the PR checklist.
The python/ directory is a periodic copy of
claude-llm-quota-bar's session_tokens.py and friends. To sync:
# From this repo
git clone https://github.com/philipecomputacao/claude-llm-quota-bar.git /tmp/cb
diff -ruN /tmp/cb/session_tokens.py python/session_tokens.py
diff -ruN /tmp/cb/lib python/lib
diff -ruN /tmp/cb/pricing.json python/pricing.json
diff -ruN /tmp/cb/statusline.env.json python/statusline.env.json
# Apply the diffs manually. Keep this repo's commit history clean by
# committing the sync as chore(python): sync from upstream <sha>.claude-llm-quota-bar— the upstream Claude Code statusline. This plugin is a thin adapter that runs the same script under OpenCode.free-claude-code-plus— the fcc-claude fork that motivated the multi-provider design.
Plugin e curadoria por @lpdigital.me.

{ "plugin": ["./plugins/llm-statusline.ts"] }