musingfox/cc-plugins/tree/main/omp-quota
omp-quota
[Experimental] 각 omp provider의 남은 할당량을 세션 안에서 보여 줍니다. 프롬프트 위의 /quota 밴드, /quota refresh, provider가 ok에서 나빠질 때의 toast를 제공합니다(Claude Mod; Claude Code 2.1.287+ 필요).
이 mod 소개
omp-quota
각 omp provider의 남은 할당량을 Claude Code 세션 안에 표시하는 Claude Mod입니다(function-hooks 모듈, hooks/register.ts).
/quota: 프롬프트 위에 provider마다 한 줄씩 나오는 간결한 표를 켜고 끕니다./quota refresh: omp 캐시를 버리고 최신 할당량을 가져옵니다. 모델 턴은 발생하지 않습니다.- Toast: provider 상태가
ok에서 나빠지면 세션 안에서 toast를 한 번 표시합니다.
Claude Mods가 기본으로 켜지는 Claude Code 2.1.287 이상이 필요합니다. Claude Code 2.1.287을 기준으로 만들고 테스트했습니다.
omp 실행 방식
가져올 때마다 PI_CODING_AGENT_DIR을 $HOME/.omp/agent로 설정한 뒤 omp usage --json을 실행하고 30 s 제한을 둡니다(2026-09-25에 모든 provider를 대상으로 한 콜드 가져오기는 약 10 s였습니다). 이 재정의가 중요합니다. Claude Code가 자체 PI_CODING_AGENT_DIR을 넘길 수 있고(pi-dispatch가 하나를 설정함), omp가 그 home을 읽으면 종료 코드 0과 provider 없음으로 응답하기 때문입니다. omp는 Claude Code의 PATH에서 찾습니다(대개 ~/.bun/bin에 있습니다). HOME이 설정되지 않으면 omp를 실행하지 않고 밴드에는 Unavailable: HOME is unset, /quota refresh에는 omp quota refresh failed: HOME is unset을 표시합니다.
할당량은 세션 시작 시 한 번 가져온 뒤 5분마다 가져옵니다. 가져오기에 실패해도 폴링은 계속되고 다른 재시도는 없습니다. /quota 등록이 거부되어도 계속 실행합니다. reload로 세션 시작이 다시 실행되면 먼저 이전 폴링을 취소하므로 주기가 중복되지 않습니다.
omp를 기다리는 작업은 없습니다. 세션 시작(Claude Code는 첫 프롬프트 전에 이를 await함)은 기다리지 않고 가져오기를 시작합니다. 모듈은 tool-call이나 prompt 이벤트에도 hook하지 않으므로 느린 omp 때문에 도구 호출이나 프롬프트가 멈추지 않습니다.
할당량 읽기
- 남은 비율: omp의
remainingFraction이 숫자면 사용하고, 아니면1 − usedFraction, 그것도 아니면 없음으로 처리합니다. 0–100%으로 제한합니다. provider의 비율은 해당 limit 비율 중 가장 낮은 값입니다. 반올림한 백분율로 표시하며 계산할 수 없으면—입니다. - 상태: provider의 상태는 limit 중 가장 나쁜 상태(
exhausted>warning>ok)입니다. 상태가 없는 limit은 무시하고, 아무 상태도 없는 provider에는 상태가 없습니다. 같은 provider 이름의 보고서는 하나로 합치며, 이름이 없는 보고서는(unnamed)으로 표시합니다. - 나빠진 provider: 이전 정상 가져오기에서 상태가
ok였고 이번에는warning또는exhausted가 된 provider입니다. 첫 정상 가져오기에는 이전 상태가 없습니다.warning→exhausted, 어느 한쪽에 상태가 없는 provider, 새로 나타난 provider는 포함하지 않습니다. - 가져오기 실패: omp가 응답하지 않았거나(시작하지 못했거나 30 s 뒤에도 실행 중), 0이 아닌 상태로 끝났거나, JSON 보고서 목록이 아닌 내용을 출력했거나, provider를 보고하지 않은 경우입니다. 마지막 경우는 omp가 잘못된 home을 읽을 때의 응답이므로 표시를 지우지 않습니다. omp의 오류 출력은 표시하지 않습니다.
- 계정 데이터: provider 이름, limit id와 label, 비율, 상태, 재설정 시간만 보관합니다. omp의
metadata(email, account id, endpoint)와 각 limit의scope는 toast, 기록, 밴드에 절대 도달하지 않습니다.
Toast
정상 가져오기에서 이전 정상 가져오기 이후 나빠진 provider(위의 나빠진 provider 참조)를 찾으면 세션 안의 toast 하나에 모두 표시합니다: omp quota: openai-codex now warning, anthropic now exhausted. 그 사이의 가져오기 실패는 비교를 초기화하지 않습니다. OS 알림은 없습니다. 다른 창에 있을 때 나빠져도 돌아왔을 때 밴드가 켜져 있으면 밴드에서 확인할 수 있습니다.
명령
/quota는 프롬프트 위 밴드를 켜거나 끄며 기록에는 아무것도 출력하지 않습니다. 밴드를 바꾸는 것은 이 명령뿐이고 폴링이나 악화는 바꾸지 않습니다. 선택은 플러그인 저장소의bandkey에 보관하고 세션 시작 시 읽으므로 떠날 때의 상태가 유지됩니다. 저장된 값이 없거나 저장소가 실패하면 꺼진 상태로 시작합니다. 전환할 때 저장에 실패해도 해당 세션에서는 밴드를 전환합니다./quota refresh는omp usage invalidate를 실행한 뒤 가져오며 둘 다 같은 omp home을 사용합니다. 한 줄로omp quota refreshed또는omp quota refresh failed: <reason>을 답합니다(밴드의 알림 줄에 실패가 표시됨). invalidate가 실패해도 가져오기는 계속하고 응답 끝에(cache not invalidated)를 붙입니다. 밴드를 바꾸지 않고 모델 턴도 필요 없습니다./quota <anything else>는usage: /quota [refresh]라고 답하고 아무것도 실행하지 않습니다.
밴드
밴드는 프롬프트 입력 바로 위의 띠입니다. /quota가 켜져 있으면 가져오는 동안 흐린 알림 줄(Fetching omp usage), 성공한 가져오기가 한 번도 없을 때(Unavailable: <reason>), 최신 가져오기가 실패했을 때(Stale: <reason>; showing data from <age> ago)를 표시합니다. 그 다음 limit을 보고한 provider를 남은 비율이 낮은 순서부터 한 줄씩 표시합니다. 예:
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
각 줄에는 각 window마다 셀 하나를 둡니다(omp의 window label을 쓰고, 없으면 limit label을 사용). 가장 빠른 재설정 순서로 <window> <share> <time to reset>을 표시하며 window 상태는 warning 또는 exhausted일 때만 덧붙입니다. window의 비율과 재설정 시간은 남은 비율이 가장 낮은 limit(비율이 없으면 첫 번째)에서 가져오므로 antigravity의 공유 Claude·GPT limit처럼 반복되는 풀은 한 셀로 합칩니다. provider 사이에서 window가 맞도록 셀에 여백을 채웁니다. provider 순서는 모든 limit 중 가장 낮은 비율을 사용하며, 비율이 없는 provider는 마지막으로 보내고, limit을 보고하지 않는 provider(예: ollama-cloud)는 제외합니다. 재설정까지의 시간은 Xd Yh, Xh Ym, Ym 중 하나로 읽고, 기한이면 now, omp가 주지 않으면 —입니다. 비율은 표시된 백분율에 따라 0–30% 빨강, 31–60% 주황, 61–100% 초록으로 색칠하며 —는 색칠하지 않습니다.
각 줄은 줄바꿈하지 않고 밴드 너비에서 생략 부호로 자릅니다. survey가 밴드를 차지하면 양보하고, 다른 mod가 같은 곳에 밴드를 그리면(예: /cal) 숨기지 않고 공간을 공유합니다. 성공 여부와 관계없이 가져오기가 확정될 때마다 다시 그려 모듈이 가진 최신 데이터를 표시합니다. ctrl+x ctrl+a(또는 [-] 표시)로 접을 수 있지만 끄지는 않습니다. Box와 Text만 사용해 그리며 props는 flexDirection, color, dimColor, wrap입니다.
Tests
claude plugin test omp-quota
테스트 키트는 hermetic합니다. 파일 시스템, 네트워크, 프로세스를 사용하지 않으며 테스트가 실행하는 모든 $ 호출은 플러그인 아래 stub이 답합니다.
tests/fixtures/snapshot.ts는 2026-09-18에 가져온 실시간 omp usage --json의 비식별화 사본입니다. 갱신하려면 새 snapshot을 캡처하고 모든 metadata 객체, 모든 scope.projectId와 scope.accountId, resetCredits를 제거한 뒤 붙여 넣습니다. 계정 key나 @가 들어간 문자열이 하나라도 남아 있으면 tests/snapshot.test.ts의 첫 테스트가 실패합니다.
설치
먼저 작성자의 README에서 marketplace와 플러그인 이름을 확인하세요. 저장소 구조에 따라 명령어가 달라질 수 있습니다.
claude plugin marketplace add musingfox/cc-plugins claude plugin install omp-quota
원문 / 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
remainingFractionwhen it is a number, else1 − 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
okin the previous good fetch and iswarningorexhaustednow. 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'sscopenever 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
/quotatoggles 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 (keyband) 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 refreshrunsomp usage invalidate, then fetches, both against the same omp home, and answers one line:omp quota refreshedoromp 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>answersusage: /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.
