OpenCode Quota can share its cached quota data with scripts, status bars, CI, and monitoring tools. These options do not make extra provider requests.
| What you need | Use |
|---|---|
| Run a command and get JSON | opencode-quota show --json |
| Read the same JSON often | Export file |
| Send numbers to a monitoring system | OpenTelemetry metrics |
Use this for scripts and CI:
opencode-quota show --jsonUseful variations:
# Only Copilot
opencode-quota show --json --provider copilot
# Exit with an error when comparable quota is below 5%
opencode-quota show --json --threshold 5Threshold exit codes:
| Code | Meaning |
|---|---|
0 |
Quota is available and above the threshold |
1 |
At least one comparable cached percentage is below the threshold |
2 |
Results were incomplete or no comparable percentage was found |
npx @slkiser/opencode-quota show --json --threshold 5Some Copilot results contain values instead of percentages. Select a percentage row instead of assuming the first row is one:
opencode-quota show --json --provider copilot \
| jq -r '(.providers.copilot.entries? // []) | map(select(.renderType == "percent" and .percentRemaining != null)) | first | .percentRemaining // empty'Use this for a status bar or another tool that checks quota often.
Add this to opencode-quota/quota-toast.json:
The file is normally written here:
~/.cache/opencode/quota-export.json
If you set XDG_CACHE_HOME, the file is written to $XDG_CACHE_HOME/opencode/quota-export.json instead.
The TUI refreshes the file about once a minute. A write error is logged, but it does not break the TUI.
Add this to your tmux config:
set -g status-interval 30
set -g status-right '#(jq -r "[.providers|to_entries[]|select(.value.status==\"ok\")|first(.value.entries[]?|select(.renderType==\"percent\" and .percentRemaining!=null))|(.percentRemaining|floor|tostring)+\"%\"]|join(\" | \")" ~/.cache/opencode/quota-export.json 2>/dev/null)'Add this to starship.toml:
[custom.quota]
command = "opencode-quota show --json 2>/dev/null | jq -r '[.providers|to_entries[]|select(.value.status==\"ok\")|first(.value.entries[]?|select(.renderType==\"percent\" and .percentRemaining!=null))|(.percentRemaining|floor|tostring)+\"%\"]|join(\" \")'"
when = "true"
interval = 60Use this only when your OpenCode host already has an OpenTelemetry metrics provider and exporter. OpenCode Quota does not create or configure them.
Add this to opencode-quota/quota-toast.json:
{
"telemetry": {
"enabled": true,
},
}OpenCode Quota then publishes two gauges:
| Metric | Meaning |
|---|---|
opencode.quota.consumed |
Used quota from 0 to 1 |
opencode.quota.cache.age |
Age of cached data in seconds |
If the host has no global metrics provider, nothing is sent and OpenCode Quota continues normally.
Metric fields and privacy
opencode.quota.consumed uses percentage rows only. Its value is (100 - percentRemaining) / 100, limited to the range 0 to 1. Value rows such as balances are not converted into this metric.
| Metric | Labels |
|---|---|
opencode.quota.consumed |
quota.provider, quota.result_type, quota.window |
opencode.quota.cache.age |
quota.provider |
Label values stay limited:
quota.provideris a maintained provider ID,custom, orother.quota.result_typeisquota,rate_limit,usage,spend,budget,balance, orstatus.quota.windowisrpm,five_hour,hour,day,week,month,year,mcp,code_review, orunknown.
When several rows map to the same safe labels, OpenCode Quota reports the highest consumed ratio or oldest cache age. Display names, account IDs, configured source IDs, credentials, URLs, paths, errors, and raw responses are never labels.
Minimal host setup example
Register the provider before OpenCode loads OpenCode Quota. Replace the console exporter with your real exporter.
import { metrics } from "@opentelemetry/api";
import {
ConsoleMetricExporter,
MeterProvider,
PeriodicExportingMetricReader,
} from "@opentelemetry/sdk-metrics";
const reader = new PeriodicExportingMetricReader({
exporter: new ConsoleMetricExporter(),
exportIntervalMillis: 60_000,
});
const provider = new MeterProvider({ readers: [reader] });
metrics.setGlobalMeterProvider(provider);
export async function shutdownMetrics() {
await provider.shutdown();
}The command and export file both use JSON schema version 2.
Every provider has status. Other fields depend on that status:
ok:fetchedAtandentriespartial:fetchedAt,entries, anderrorserror:fetchedAtand a safeerrormessageunavailable: no other fields are required
Provider statuses:
| Status | Meaning |
|---|---|
ok |
Data is available |
partial |
Some data worked and some failed |
error |
The provider failed |
unavailable |
No matching cached data exists |
A percentage entry uses renderType: "percent" and percentRemaining. A value entry uses renderType: "value" and value.
Optional entry fields include window, resetAt, observedAt, and sourceId. A provider can also include rawDetails: sanitized provider-owned key/value facts that stay out of normal quota displays.
Configured quotaProviders entries include sourceId. The quota-providers result includes a sources list so tools can match each result to its configured source. Treat status: "partial" as incomplete.
rawDetails is curated and safe to export. Secrets, credentials, URLs, checked paths, and raw provider responses remain excluded from public JSON. Use /quota_status when you need live diagnostics.
Configured source details
Rows from a configured quotaProviders definition appear under providers["quota-providers"] and keep their stable sourceId:
{
"sourceId": "openrouter-primary",
"renderType": "percent",
"percentRemaining": 40
}The provider also includes a summary for every configured source:
"sources": [
{
"id": "openrouter-primary",
"providerId": "openrouter",
"status": "ok",
"entryCount": 1
}
]Each summary is exactly id, effective providerId, coarse status, and entryCount. A source can be ok after producing valid rows while failed mapping candidates can still make the aggregate provider partial.
Small JSON example
{
"version": 2,
"exportedAt": 1748736000,
"fromCache": true,
"cacheAgeSeconds": 42,
"providers": {
"copilot": {
"status": "ok",
"fetchedAt": 1748735958,
"entries": [
{
"name": "Premium Requests",
"resultType": "quota",
"acquisitionMethod": "remote_api",
"ownership": "maintained",
"authority": "provider_reported",
"renderType": "percent",
"percentRemaining": 62.3
}
]
}
}
}- All options use data collected during normal OpenCode Quota activity.
- The command and export file read cached data instead of contacting providers.
- The OpenTelemetry integration reads in-memory results and never starts its own refresh loop.
- OpenTelemetry metric labels are limited to safe provider, result type, and quota-window values.
- Display names, account IDs, source IDs, credentials, paths, URLs, errors, and raw responses are never metric labels.
{ "export": { "enabled": true, }, }