@leo000001/opencode-quota-sidebar
v1.12.0
Published
OpenCode plugin that shows quota and token usage in session titles
Downloads
1,242
Maintainers
Readme
opencode-quota-sidebar
OpenCode plugin: show token usage and subscription quota in the session sidebar title.

Install
Add the package name to plugin in your opencode.json. OpenCode uses Bun to install it automatically on startup:
{
"plugin": ["@leo000001/opencode-quota-sidebar"]
}Note for OpenCode >=1.2.15: TUI settings (theme/keybinds/tui) moved to tui.json, but plugin loading still stays in opencode.json (plugin: []).
Development (build from source)
npm install
npm run buildAdd the built file to your opencode.json:
{
"plugin": ["file:///ABSOLUTE/PATH/opencode-quota-sidebar/dist/index.js"]
}On Windows, use forward slashes: "file:///D:/Lab/opencode-quota-sidebar/dist/index.js"
Supported quota providers
| Provider | Endpoint | Auth | Status |
| -------------- | -------------------------------------- | --------------- | -------------------------------------- |
| OpenAI Codex | chatgpt.com/backend-api/wham/usage | OAuth (ChatGPT) | Multi-window (short-term + weekly) |
| GitHub Copilot | api.github.com/copilot_internal/user | OAuth | Monthly quota |
| RightCode | www.right.codes/account/summary | API key | Subscription or balance (by prefix) |
| Anthropic | — | — | Unsupported (no public quota endpoint) |
Want to add support for another provider (Google Antigravity, Zhipu AI, Firmware AI, etc.)? See CONTRIBUTING.md.
Features
- Session title becomes multiline in sidebar:
- line 1: original session title
- line 2: Input/Output tokens
- line 3: Cache Read tokens (only if non-zero)
- line 4: Cache Write tokens (only if non-zero)
- line 5:
$X.XX as API cost(equivalent API billing for subscription-auth providers) - quota lines: quota text like
OpenAI 5h 80% Rst 16:20, with multi-window continuation lines indented (e.g.Weekly 70% Rst 03-01) - RightCode daily quota shows
$remaining/$dailyTotal+ expiry (e.g.RC Daily $105/$60 Exp 02-27, without trailing percent) and also shows balance on the next indented line when available
- Session-scoped usage/quota can include descendant subagent sessions (enabled by default via
sidebar.includeChildren=true). Traversal is bounded bychildrenMaxDepth(default 6),childrenMaxSessions(default 128), andchildrenConcurrency(default 5); truncation is logged whenOPENCODE_QUOTA_DEBUG=1. Day/week/month ranges never merge children — only session scope does. - Toast message includes three sections:
Token Usage,Cost as API(per provider), andQuota - Quota snapshots are de-duplicated before rendering to avoid repeated provider lines
- Custom tools:
quota_summary— generate usage report for session/day/week/month (markdown + toast)quota_show— toggle sidebar title display on/off (state persists across sessions)
- Quota connectors:
- OpenAI Codex OAuth (
/backend-api/wham/usage) - GitHub Copilot OAuth (
/copilot_internal/user) - RightCode API key (
/account/summary) - Anthropic: currently marked unsupported (no public quota endpoint)
- OpenAI Codex OAuth (
- OpenAI OAuth quota checks auto-refresh expired access token (using refresh token)
- API key providers still show usage aggregation (quota only applies to subscription providers)
- Incremental usage aggregation — only processes new messages since last cursor
- Sidebar token units are adaptive (
k/mwith one decimal where applicable)
Storage layout
The plugin stores lightweight global state and date-partitioned session chunks.
- Global metadata:
<opencode-data>/quota-sidebar.state.jsontitleEnabledsessionDateMap(sessionID ->YYYY-MM-DD)quotaCache
- Session chunks:
<opencode-data>/quota-sidebar-sessions/YYYY/MM/DD.json- per-session title state (
baseTitle,lastAppliedTitle) createdAtparentID(when the session is a subagent child session)- cached usage summary used by
quota_summary - incremental aggregation cursor
- per-session title state (
Example tree:
~/.local/share/opencode/
quota-sidebar.state.json
quota-sidebar-sessions/
2026/
02/
23.json
24.jsonSessions older than retentionDays (default 730 days / 2 years) are evicted from
memory on startup. Chunk files remain on disk for historical range scans.
Compatibility
- Node.js: >= 18 (for
fetch+AbortController) - OpenCode: plugin SDK
@opencode-ai/plugin^1.2.10 - OpenCode config split: if you are on
>=1.2.15, keep this plugin inopencode.jsonand keep TUI-only keys intui.json.
Optional commands
You can add these command templates in opencode.json so you can run /qday, /qweek, /qmonth, /qtoggle:
{
"command": {
"qday": {
"description": "Show today's usage and quota",
"template": "Call tool quota_summary with period=day and toast=true."
},
"qweek": {
"description": "Show this week's usage and quota",
"template": "Call tool quota_summary with period=week and toast=true."
},
"qmonth": {
"description": "Show this month's usage and quota",
"template": "Call tool quota_summary with period=month and toast=true."
},
"qtoggle": {
"description": "Toggle sidebar usage display on/off",
"template": "Call tool quota_show (no arguments, it toggles)."
}
}
}Configuration files
Recommended global config:
~/.config/opencode/quota-sidebar.config.json
Optional project overrides:
<worktree>/quota-sidebar.config.json<worktree>/.opencode/quota-sidebar.config.json
Optional explicit override:
OPENCODE_QUOTA_CONFIG=/absolute/path/to/config.json
Optional config-home override:
OPENCODE_QUOTA_CONFIG_HOME=/absolute/path/to/config-home
Resolution order (low -> high):
- Global config (
~/.config/opencode/...) - Project root config
.opencodeproject configOPENCODE_QUOTA_CONFIG
Values are layered; later sources override earlier ones.
Defaults
If you do not provide any config file, the plugin uses the built-in defaults below.
Sidebar defaults:
sidebar.enabled:truesidebar.width:36(clamped to20-60)sidebar.multilineTitle:truesidebar.showCost:truesidebar.showQuota:truesidebar.wrapQuotaLines:truesidebar.includeChildren:truesidebar.childrenMaxDepth:6(clamped to1-32)sidebar.childrenMaxSessions:128(clamped to0-2000)sidebar.childrenConcurrency:5(clamped to1-10)
Quota defaults:
quota.refreshMs:300000(clamped to>=30000)quota.includeOpenAI:truequota.includeCopilot:truequota.includeAnthropic:truequota.providers:{}(per-adapter switches, for examplerightcode.enabled)quota.refreshAccessToken:falsequota.requestTimeoutMs:8000(clamped to>=1000)
Other defaults:
toast.durationMs:12000(clamped to>=1000)retentionDays:730
Example config:
{
"sidebar": {
"enabled": true,
"width": 36,
"multilineTitle": true,
"showCost": true,
"showQuota": true,
"wrapQuotaLines": true,
"includeChildren": true,
"childrenMaxDepth": 6,
"childrenMaxSessions": 128,
"childrenConcurrency": 5
},
"quota": {
"refreshMs": 300000,
"includeOpenAI": true,
"includeCopilot": true,
"includeAnthropic": true,
"providers": {
"rightcode": {
"enabled": true
}
},
"refreshAccessToken": false,
"requestTimeoutMs": 8000
},
"toast": {
"durationMs": 12000
},
"retentionDays": 730
}Notes:
sidebar.showCostcontrols API-cost visibility in sidebar title,quota_summarymarkdown report, and toast message.sidebar.widthis measured in terminal cells. CJK/emoji truncation is best-effort to avoid sidebar overflow.sidebar.multilineTitlecontrols multi-line sidebar layout (default:true). Setfalsefor compact single-line title.sidebar.wrapQuotaLinescontrols quota line wrapping and continuation indentation (default:true).sidebar.includeChildrencontrols whether session-scoped usage/quota includes descendant subagent sessions (default:true).sidebar.childrenMaxDepthlimits how many levels of nested subagents are traversed (default:6, clamped 1–32).sidebar.childrenMaxSessionscaps the total number of descendant sessions aggregated (default:128, clamped 0–2000).sidebar.childrenConcurrencycontrols parallel fetches for descendant session messages (default:5, clamped 1–10).outputincludes reasoning tokens (output = tokens.output + tokens.reasoning). Reasoning is not rendered as a separate line.- API cost bills reasoning tokens at the output rate (same as completion tokens).
quota.providersis the extensible per-adapter switch map.- If API Cost is
$0.00, it usually means the model/provider has no pricing mapping in OpenCode at the moment, so equivalent API cost cannot be estimated.
Rendering examples
These examples show the quota block portion of the sidebar title.
sidebar.multilineTitle=true
0 providers (no quota data):
(no quota block)1 provider, 1 window (fits):
Copilot Monthly 78% Rst 04-011 provider, multi-window (for example OpenAI 5h + Weekly):
OpenAI
5h 78% Rst 05:05
Weekly 73% Rst 03-122+ providers (even if each provider is single-window):
OpenAI
5h 78% Rst 05:05
Copilot
Monthly 78% Rst 04-012+ providers mixed (multi-window + single-window):
OpenAI
5h 78% Rst 05:05
Weekly 73% Rst 03-12
Copilot
Monthly 78% Rst 04-01Balance-style quota:
RC Balance $260Multi-detail quota (window + balance):
RC
Daily $88.9/$60 Exp 02-27
Balance $260Provider status (examples):
Anthropic unsupported
Copilot unavailable
OpenAI Remaining ?sidebar.multilineTitle=false
Quota is rendered inline as part of a single-line title:
<base> | Input ... | Output ... | OpenAI 5h 78%+ | Copilot Monthly 78% | ...quota_summary also supports an optional includeChildren flag (only effective for period=session) to override the config per call. For day/week/month periods, children are never merged — each session is counted independently.
Debug logging
Set OPENCODE_QUOTA_DEBUG=1 to enable debug logging to stderr. This logs:
- Chunk I/O operations
- Auth refresh attempts and failures
- Session eviction counts
- Symlink write refusals
Security & privacy notes
- The plugin reads OpenCode credentials from
<opencode-data>/auth.json. - If enabled, quota checks call external endpoints:
- OpenAI Codex:
https://chatgpt.com/backend-api/wham/usage - GitHub Copilot:
https://api.github.com/copilot_internal/user - RightCode:
https://www.right.codes/account/summary
- OpenAI Codex:
- Screen-sharing warning: Session titles and toasts surface usage/quota
information. If you are screen-sharing or recording, consider toggling the
sidebar display off (
/qtoggleorquota_showtool) to avoid leaking subscription details. - State is persisted under
<opencode-data>/quota-sidebar.state.jsonand<opencode-data>/quota-sidebar-sessions/(see Storage layout). - OpenAI OAuth token refresh is disabled by default; set
quota.refreshAccessToken=trueif you want the plugin to refresh access tokens when expired. - State/chunk file writes refuse to write through symlinked targets (best-effort defense-in-depth).
- The
OPENCODE_QUOTA_DATA_HOMEenv var overrides the OpenCode data directory path (for testing); do not set this in production. - The
OPENCODE_QUOTA_CONFIG_HOMEenv var overrides global config directory lookup (<config-home>/opencode). - The
OPENCODE_QUOTA_CONFIGenv var points to an explicit config file and applies as the highest-priority override.
Contributing
Contributions are welcome — especially new quota provider connectors. See CONTRIBUTING.md for a step-by-step guide on adding support for a new provider.
License
MIT. See LICENSE.
