ClaudeMods
☰
EN
● 0 online · Views 0 times
SponsorsSubmit a project
GitHub repositories · by musingfox

omp-quota

[Experimental] Every omp provider's remaining quota in-session — a /quota band above the prompt, /quota refresh, and a toast when a provider worsens from ok (Claude Mod; needs Claude Code 2.1.287+)

musingfox@musingfox

musingfox/cc-plugins/tree/main/omp-quota

Translated

About this mod

omp-quota

Shows every omp provider's remaining quota inside a Claude Code session, as one Claude Mod (a function-hooks module, hooks/register.ts).

  • /quota: toggles a compact table above the prompt, one line per provider.
  • /quota refresh: drops omp's cache and fetches fresh quota, without a model turn.
  • Toast: one in-session toast when a provider's status worsens from ok.

Needs Claude Code 2.1.287 or later, where Claude Mods are on by default. Built and tested against Claude Code 2.1.287.

How omp is run

Each fetch runs omp usage --json with PI_CODING_AGENT_DIR set to $HOME/.omp/agent and a 30 s limit (a cold fetch across all providers took about 10 s on 2026-09-25). The override matters: Claude Code may pass down a PI_CODING_AGENT_DIR of its own (pi-dispatch sets one), and omp reading that home answers with exit 0 and no providers. omp is found on Claude Code's PATH (it usually lives in ~/.bun/bin). With HOME unset, omp is not run, the band reads Unavailable: HOME is unset, and /quota refresh answers omp quota refresh failed: HOME is unset.

Quota is fetched once at session start and then every 5 minutes. A failed fetch leaves the poll running; there is no other retry. A refused /quota registration leaves it running too. When a reload re-fires session start, the previous poll is cancelled first, so the cadence never doubles.

Nothing waits on omp. Session start (which Claude Code awaits before the first prompt) starts the fetch without awaiting it, and the module hooks no tool-call or prompt event, so no tool call or prompt is ever held up by a slow omp.

How quota is read

  • Remaining share of a limit: omp's remainingFraction when it is a number, else 1 − usedFraction, else none; clamped to 0–100%. A provider's share is the lowest of its limits' shares. Shown as a rounded percentage, or — when none is computable.
  • Status of a provider: the worst status among its limits (exhausted > warning > ok); limits without one are ignored, and a provider with none has no status. Reports with the same provider name merge into one provider; a report without one is listed as (unnamed).
  • Worsened provider: one whose status was ok in the previous good fetch and is warning or exhausted now. The first good fetch has no previous; warning → exhausted, a provider without a status on either side, and a newly appearing provider do not count.
  • Failed fetch: omp did not answer (could not start, or still running after 30 s), exited non-zero, printed something that is not a JSON report list, or reported no providers — the last is how omp answers when it reads the wrong home, so it never wipes the display. omp's error output is never shown.
  • Account data: only provider names, limit ids and labels, shares, statuses, and reset times are kept. omp's metadata (email, account id, endpoint) and each limit's scope never reach a toast, the transcript, or the band.

The toast

When a good fetch finds providers that worsened since the previous good fetch (see Worsened provider above), one in-session toast names them all: omp quota: openai-codex now warning, anthropic now exhausted. Failed fetches in between do not reset the comparison. There is no OS notification; a worsening that happens while you are in another window shows in the band, if it is on, when you return.

Commands

  • /quota toggles the band above the prompt on or off and prints nothing in the transcript. Only this command changes the band — a poll or a worsening never does. The choice is kept in the plugin's store (key band) and read at session start, so the band stays as you left it; with nothing stored, or a store that fails, it starts off. A store that fails on the toggle still flips the band for this session.
  • /quota refresh runs omp usage invalidate, then fetches, both against the same omp home, and answers one line: omp quota refreshed or omp quota refresh failed: <reason> (the band then shows the failure in its notice line). When the invalidate fails, the fetch still runs and the answer ends in (cache not invalidated). It does not change the band and needs no model turn.
  • /quota <anything else> answers usage: /quota [refresh] and runs nothing.

The band

The band is the strip directly above the prompt input. While /quota has it on, it shows a dim notice line while fetching (Fetching omp usage), when no fetch has succeeded (Unavailable: <reason>), or when the latest fetch failed (Stale: <reason>; showing data from <age> ago). Then one line per provider that reports limits, from the least share left to the most, for example:

cursor              Monthly   0% 11h 25m exhausted
openai-codex        5 hours 100% 4h 59m  7 days    6% 1d 11h warning
anthropic           5 Hour   86% 1h 44m  7 Day    94% 5d 15h

Each line holds one cell per window (omp's window label, or the limit label when it has none), soonest reset first: <window> <share> <time to reset>, plus the window's status only when it is warning or exhausted. A window's share and reset come from its limit with the least share left (the first one when none has a share), so repeated pools such as antigravity's shared Claude & GPT limits collapse into one cell. Cells are padded so the windows line up across providers. A provider's order uses its lowest share across all limits; providers without a share go last, and one reporting no limits (such as ollama-cloud) is left out. Time to reset reads Xd Yh, Xh Ym, or Ym, now when due, and — when omp gives none. Each share is colored by the percentage shown: red for 0–30%, orange for 31–60%, green for 61–100%; — stays uncolored.

Every line is cut at the band's width with an ellipsis rather than wrapped. The band yields to a survey while one holds it, shares its space with any band another mod draws there (/cal, for one) instead of hiding it, and redraws after every settled fetch, failed ones included, so it always shows the latest data the module holds. Collapse it with ctrl+x ctrl+a (or its [-] mark) without turning it off. It is drawn from Box and Text only, with the props flexDirection, color, dimColor, and wrap.

Tests

claude plugin test omp-quota

The test kit is hermetic: no filesystem, network, or process; every $ call a test makes is answered by a stub beneath the plugin.

tests/fixtures/snapshot.ts is a redacted copy of a live omp usage --json taken on 2026-09-18. To refresh it, capture a new snapshot, remove every metadata object, every scope.projectId and scope.accountId, and resetCredits, then paste it in. The first test in tests/snapshot.test.ts fails while any account key or any string holding @ remains.

Installation

Check the author's README for the marketplace and plugin name first. Commands may change as the repository evolves.

claude plugin marketplace add musingfox/cc-plugins
claude plugin install omp-quota
Original text / README

omp-quota

Shows every omp provider's remaining quota inside a Claude Code session, as one Claude Mod (a function-hooks module, hooks/register.ts).

  • /quota: toggles a compact table above the prompt, one line per provider.
  • /quota refresh: drops omp's cache and fetches fresh quota, without a model turn.
  • Toast: one in-session toast when a provider's status worsens from ok.

Needs Claude Code 2.1.287 or later, where Claude Mods are on by default. Built and tested against Claude Code 2.1.287.

How omp is run

Each fetch runs omp usage --json with PI_CODING_AGENT_DIR set to $HOME/.omp/agent and a 30 s limit (a cold fetch across all providers took about 10 s on 2026-09-25). The override matters: Claude Code may pass down a PI_CODING_AGENT_DIR of its own (pi-dispatch sets one), and omp reading that home answers with exit 0 and no providers. omp is found on Claude Code's PATH (it usually lives in ~/.bun/bin). With HOME unset, omp is not run, the band reads Unavailable: HOME is unset, and /quota refresh answers omp quota refresh failed: HOME is unset.

Quota is fetched once at session start and then every 5 minutes. A failed fetch leaves the poll running; there is no other retry. A refused /quota registration leaves it running too. When a reload re-fires session start, the previous poll is cancelled first, so the cadence never doubles.

Nothing waits on omp. Session start (which Claude Code awaits before the first prompt) starts the fetch without awaiting it, and the module hooks no tool-call or prompt event, so no tool call or prompt is ever held up by a slow omp.

How quota is read

  • Remaining share of a limit: omp's remainingFraction when it is a number, else 1 − usedFraction, else none; clamped to 0–100%. A provider's share is the lowest of its limits' shares. Shown as a rounded percentage, or — when none is computable.
  • Status of a provider: the worst status among its limits (exhausted > warning > ok); limits without one are ignored, and a provider with none has no status. Reports with the same provider name merge into one provider; a report without one is listed as (unnamed).
  • Worsened provider: one whose status was ok in the previous good fetch and is warning or exhausted now. The first good fetch has no previous; warning → exhausted, a provider without a status on either side, and a newly appearing provider do not count.
  • Failed fetch: omp did not answer (could not start, or still running after 30 s), exited non-zero, printed something that is not a JSON report list, or reported no providers — the last is how omp answers when it reads the wrong home, so it never wipes the display. omp's error output is never shown.
  • Account data: only provider names, limit ids and labels, shares, statuses, and reset times are kept. omp's metadata (email, account id, endpoint) and each limit's scope never reach a toast, the transcript, or the band.

The toast

When a good fetch finds providers that worsened since the previous good fetch (see Worsened provider above), one in-session toast names them all: omp quota: openai-codex now warning, anthropic now exhausted. Failed fetches in between do not reset the comparison. There is no OS notification; a worsening that happens while you are in another window shows in the band, if it is on, when you return.

Commands

  • /quota toggles the band above the prompt on or off and prints nothing in the transcript. Only this command changes the band — a poll or a worsening never does. The choice is kept in the plugin's store (key band) and read at session start, so the band stays as you left it; with nothing stored, or a store that fails, it starts off. A store that fails on the toggle still flips the band for this session.
  • /quota refresh runs omp usage invalidate, then fetches, both against the same omp home, and answers one line: omp quota refreshed or omp quota refresh failed: <reason> (the band then shows the failure in its notice line). When the invalidate fails, the fetch still runs and the answer ends in (cache not invalidated). It does not change the band and needs no model turn.
  • /quota <anything else> answers usage: /quota [refresh] and runs nothing.

The band

The band is the strip directly above the prompt input. While /quota has it on, it shows a dim notice line while fetching (Fetching omp usage), when no fetch has succeeded (Unavailable: <reason>), or when the latest fetch failed (Stale: <reason>; showing data from <age> ago). Then one line per provider that reports limits, from the least share left to the most, for example:

cursor              Monthly   0% 11h 25m exhausted
openai-codex        5 hours 100% 4h 59m  7 days    6% 1d 11h warning
anthropic           5 Hour   86% 1h 44m  7 Day    94% 5d 15h

Each line holds one cell per window (omp's window label, or the limit label when it has none), soonest reset first: <window> <share> <time to reset>, plus the window's status only when it is warning or exhausted. A window's share and reset come from its limit with the least share left (the first one when none has a share), so repeated pools such as antigravity's shared Claude & GPT limits collapse into one cell. Cells are padded so the windows line up across providers. A provider's order uses its lowest share across all limits; providers without a share go last, and one reporting no limits (such as ollama-cloud) is left out. Time to reset reads Xd Yh, Xh Ym, or Ym, now when due, and — when omp gives none. Each share is colored by the percentage shown: red for 0–30%, orange for 31–60%, green for 61–100%; — stays uncolored.

Every line is cut at the band's width with an ellipsis rather than wrapped. The band yields to a survey while one holds it, shares its space with any band another mod draws there (/cal, for one) instead of hiding it, and redraws after every settled fetch, failed ones included, so it always shows the latest data the module holds. Collapse it with ctrl+x ctrl+a (or its [-] mark) without turning it off. It is drawn from Box and Text only, with the props flexDirection, color, dimColor, and wrap.

Tests

claude plugin test omp-quota

The test kit is hermetic: no filesystem, network, or process; every $ call a test makes is answered by a stub beneath the plugin.

tests/fixtures/snapshot.ts is a redacted copy of a live omp usage --json taken on 2026-09-18. To refresh it, capture a new snapshot, remove every metadata object, every scope.projectId and scope.accountId, and resetCredits, then paste it in. The first test in tests/snapshot.test.ts fails while any account key or any string holding @ remains.

Similar projects