Live usage limits and balances for your inference providers, drawn on your Ulanzi deck keys — a sibling of ulanzi-system-monitor that reuses the same interface model (a cycler key + tiles that follow the active selection).
Latest release: v1.5.1 ships both the Ulanzi Studio plugin and the standalone inf-agent.
One key cycles the provider; two tiles show its main numbers, with an optional third monthly tile for providers that expose it:
| Provider | Kind | Primary tile | Secondary tile |
|---|---|---|---|
| Claude (Anthropic) | limits | Session (5h) % + reset | Week (7d) % + reset |
| OpenAI (Codex) | limits | Short window % or plan | Long window % + reset |
| Ollama Cloud | limits | Session (5h) % | Week (7d) % |
| OpenCode Go | limits | Rolling 5h % + reset | Week % + reset (monthly on a third tile) |
| OpenRouter | balance | Balance ($) | Spend today / week |
| Nous | balance | Free / tier | Rate limit (rpm/tpm) |
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Provider │ │ ◐ 8% │ │ ◔ 2% │
│ Switch │ │ SESSION │ │ WEEK │ ← Claude selected
│ 🤖 Claude│ │ ↻ 4h 15m │ │ ↻ 5d 23h │
│ 1/6 8% │ └──────────┘ └──────────┘
└──────────┘ press switch → $8.29 / today $0.02 ← OpenRouter selected
host with your keys (hermes NUC) machine running Ulanzi Studio
┌───────────────────────────────┐ ┌──────────────────────────────┐
│ inf-agent.py │ HTTP │ Inference Monitor plugin │
│ reads .claude/.codex/.hermes │ (Tailscale)│ ProviderSampler → /providers │
│ GET /providers → all providers├───────────▶│ Switch key cycles providers │
│ refreshes every 60s │ │ Tiles render the active one │
└───────────────────────────────┘ └──────────────────────────────┘
The agent does all provider-specific work and lives where the credentials
already are; the plugin just polls one endpoint and renders. See
agent/README.md for the JSON contract and per-provider sources.
cd agent
python3 inf-agent.py # listens on 0.0.0.0:9890
# or install as a service — see agent/README.mdVerify: curl http://localhost:9890/providers | python3 -m json.tool
./pack.sh # builds dist/com.ulanzi.infmonitor.ulanziPlugin-<ver>.zipDouble-click the .zip (or import it in Ulanzi Studio). Then on the deck:
- Drop a Provider Switch key. In its settings put the agent address —
http://127.0.0.1:9890if Studio runs on the same box, otherwise the agent host's Tailscale address, e.g.http://100.x.y.z:9890. - Drop two Provider Tile keys next to it; set one to Primary and one to Secondary.
- In the switch settings, tick only the providers that this key should cycle. Selected rows appear under Cycle order; use ↑/↓ to set the exact order. Unselected rows remain under Available providers, and All / reset order restores every provider in the agent's order. Older switch settings continue to include all providers. Press the key to cycle the chosen providers in the saved order; the tiles follow the selection.
If OpenAI was absent from the cycle after installing v1.5.0, it was only omitted from that switch's saved allow-list — the agent still returned it. In v1.5.1 it remains visible under Available providers; tick OpenAI or use All / reset order to restore it.
OpenCode Go exposes three windows. Add a third Provider Tile and set it to Monthly to show its monthly limit; that slot also shows OpenRouter's monthly spend when available.
The Provider Switch owns the shared agent address when one is configured. Provider Tiles follow it, even if an older tile still contains the localhost default. Without a configured switch, a standalone tile uses its own address. The address is persisted for startup without opening the Property Inspector.
The installed Windows Studio 3.3.9 plugin uses the configured Provider Switch as
owner of the shared agent endpoint; a restored tile's localhost default cannot
override it. Fresh-process startup tests and the approved final software checks
passed. A passive capture at 19:11:44–19:12:04 UTC observed five automatic
GET /providers requests from Windows, each answered with HTTP 200. The installed
app hash still matches the tested source. No URL/input interaction was used for
these checks. [Source: final test output, Windows read-back and bounded passive
HTTP capture, 2026-10-10]
Independent read-only review approved the hotfix. Physical-panel appearance was not observed remotely. The live preview retains a separate failed Ollama Cloud live-limits assertion; upstream provider errors remain visible, not replaced with invented readings. v1.5.2 is a local plugin build/source hotfix, not a new published GitHub release asset. See evidence and limitations. [Source: completed review, live preview and release scope, 2026-10-10]
- Claude session/week come from the Anthropic OAuth
usageendpoint using the token Claude Code keeps fresh; the agent only reads it (never refreshes, so it can't disturb your Claude Code login). On token expiry the tile shows an error until Claude Code refreshes. - OpenAI usage comes from the same read-only ChatGPT usage endpoint used by
Codex (
/backend-api/wham/usage). The agent reads/root/.codex/auth.jsonbut never refreshes or writes it. Window labels follow the durations OpenAI actually returns (for example5HandWEEK); accounts with only a weekly window show the plan on the first tile and the weekly gauge on the second. If the endpoint is briefly unavailable, the newest local Codex rate-limit snapshot is shown as stale until live polling recovers. - Ollama Cloud exposes live session and weekly fractions at its authenticated
GET /api/usageendpoint. The endpoint does not include reset timestamps, so its gauges intentionally do not invent a countdown. Plan/renewal metadata still comes fromPOST /api/mewhen available. - OpenCode Go reads its key (prefer
OPENCODE_GO_API_KEY, otherwise OpenCode's localauth.json) and usesGET /zen/go/v1/usagefor rolling 5-hour, weekly, and monthly percentages and reset times. A rejected key or missing subscription is isolated to that provider and does not interrupt the other tiles. - Nous rate limits/tier come from the portal JWT (no network call). Real plan +
purchased balance are read live from the portal account API by delegating to
hermes's own
get_nous_portal_account_info()(run in the hermes venv) — hermes owns the single-use token refresh + persistence + locking, so the agent never calls the Nous refresh endpoint itself (reuse revokes the whole session). Configure viaINF_NOUS_HELPER_PY/INF_NOUS_HELPER_CWD(defaults point at this box's hermes), cachedINF_NOUS_LIVE_TTL(60s). If hermes has no Nous session, it falls back to theINF_NOUS_PLAN/INF_NOUS_BALANCEenv values; restore live withhermes auth add nous. - Dialagram is intentionally not included (no balance API; subscription
inactive). Add providers by extending
agent/inf-agent.py(PROBES). - Secure the agent with
INF_AGENT_TOKENand/or bind it to your Tailscale IP if the host is reachable beyond the tailnet.
agent/inf-agent.py provider probes + HTTP endpoint (stdlib only)
agent/inf-agent.service systemd unit
com.ulanzi.infmonitor.ulanziPlugin/
plugin/app.js main loop: sampler + cycler + paint
plugin/monitor/ProviderSampler.js polls /providers (no-wedge fetch)
plugin/monitor/render.js ring-gauge & value-card tiles + switch tile
plugin/monitor/settings.js PI settings
property-inspector/ tile + switch config UIs
pack.sh build the plugin + agent zips into dist/
Reuses the device API (plugin/common-node), PI framework (libs/) and MDI icon
subset from ulanzi-system-monitor.