Skip to main content

Quotamux

Route your coder to the subscription with the most quota left.

多模型多订阅额度调度器 —— 让任意 coder 自动落到余量最多的那个订阅上。

License: MIT


The problem

You pay for several AI coding subscriptions. Then this happens:

kimi-A     weekly  7% left   ← burned out on Tuesday
kimi-B     weekly 46% left
minimax-1  weekly 73% left
minimax-2  weekly 99% left   ← never touched

One subscription is exhausted while another sits idle, because nothing tells your tooling which pool still has room. You find out when a job dies with a 429.

Worse, the usual reflex is to estimate usage from your own logs. Local logs are a proxy: they miss calls that bypass them, their accounting differs from the provider's, and your own grouping code can be wrong. Every conclusion built on a proxy inherits its bias. (Ask us how we know — a full day of modelling, all of it wrong.)

What it does

Asks each provider how much is actually left, then hands your coder the environment for the pool with the most quota remaining — not merely one that is non-empty. "Non-empty is good enough" is exactly how one subscription burns out while another idles.

$ quotamux
池                       周剩      窗剩  重置
🔴kimi-A                  7%     99%  2026-08-04 00:39
🟢kimi-B                 46%    100%  2026-08-04 05:25
🟢minimax-1              73%     98%  2026-08-03 01:00
🟢minimax-2              99%    100%  2026-08-03 01:00 ←选它
🟡claude-max             22%     86%  2026-07-31 23:59
# Works with ANY coder — quotamux only emits environment variables
eval "$(quotamux --export)" && claude -p "fix the failing test"
eval "$(quotamux --export)" && aider --message "..."
eval "$(quotamux --export)" && your-own-agent

Install

pip install quotamux        # or: pipx install quotamux

Configure

Providers ship built in. Declare your subscriptions in ~/.quotamux/config.yaml (YAML or JSON). You only ever write environment-variable names — never secrets:

providers:
  kimi:
    subscriptions:
      # Multiple keys under one subscription share ONE quota pool.
      # (Verified: same-account keys return byte-identical usage.)
      # So rotating to another key of the same account when throttled is a no-op.
      - name: "kimi-team"
        keys: [KIMI_CODE_API_KEY, KIMI_CODE_API_KEY_1, KIMI_CODE_API_KEY_2]
      - name: "kimi-personal"
        keys: [KIMI_CODE_API_KEY_5]

Point elsewhere with QUOTAMUX_CONFIG=/path/to/config.yaml.

Supported providers

Provider Weekly Rate window Usage endpoint
Kimi Code {base}/usages
MiniMax /v1/token_plan/remains
Anthropic (Claude Max/Pro) /api/oauth/usage
OpenAI ⚠️ config only, untested /v1/organization/costs
DeepSeek pay-as-you-go, no pool

Two of these endpoints are not in any public documentation. We found them by reading the vendors' own clients — Kimi's from its CLI source, Anthropic's from strings on the Claude Code binary. If a dashboard can show a number, something serves that number; follow the signpost back to the machine.

Add a provider — config only, no code

Adding a vendor means adding a block to your config. Two parse modes cover every provider we have met:

providers:
  acme:
    display: ACME AI
    usage:
      url: "https://api.acme.example/v1/quota"
      auth: bearer                    # or: x-api-key
      headers: {api-version: "2026-01-01"}
      parse:
        mode: ratio                   # vendor returns absolute remaining/limit
        week:   {remaining: "quota.remaining", limit: "quota.limit", reset: "quota.reset_at"}
        window: {list: "windows", remaining: "detail.remaining", limit: "detail.limit"}
    lane:
      base_url: "https://api.acme.example/anthropic"
      model: "acme-1"
      auth_env: ANTHROPIC_AUTH_TOKEN
    subscriptions:
      - name: "acme-seat-1"
        keys: [ACME_KEY_1]
mode when the vendor returns fields
ratio absolute remaining / limit week.{remaining,limit,reset}, window.{list,remaining,limit}
percent remaining percent select.{path,where}, week.{pct,reset_ms}, window.{pct}
percent_used used percent (utilization) week.{used_pct,reset}, window.{used_pct}

Declare the models a provider serves so --model can find it:

    models:
      - {id: "acme-1", aliases: [acme, a1]}
      # usage_row: only when the vendor reports quota per model — names the row to read
      - {id: "acme-turbo", aliases: [turbo], usage_row: turbo}

A test in this repo proves the claim: a fully fictional provider that appears nowhere in the source runs end to end from config alone.

"Most quota left" — three levels

All three levels pick the emptiest-loaded pool, never just "one that still has something". What changes between levels is which pools are eligible, and that depends on what the task needs:

quotamux --pick                 # any model will do → most weekly quota left, full stop
quotamux --model opus --pick    # needs this model  → only pools that serve it
quotamux --model k3,m3 --pick   # either is fine    → pools serving k3 OR m3,
                                #                      then the emptiest across vendors

The third form is the one you want most days: "this job runs fine on Kimi or MiniMax". It keeps the job runnable (right model) and stops one subscription burning out while another idles (most quota left). Order expresses preference — with --model k3,m3, a pool serving both gets k3.

Where a vendor reports quota per model (MiniMax returns one row per model), the per-model figure wins. A subscription can look 90 % free overall while the model you need is down to 5 %.

Selection rule

  1. If --model is given, drop pools that do not serve it. Weekly quota is worthless on a pool that will not run your model.
  2. A pool is eligible when its tightest rate window has ≥ --min-window percent left (default 15). Weekly quota is useless if you are about to get throttled.
  3. Among eligible pools, pick the one with the most quota remaining — per-model if the vendor reports it, otherwise subscription-level. This is the rule that stops one subscription burning out while another idles.
  4. Pay-as-you-go pools are excluded unless you pass --allow-metered — spending money should be an explicit decision.
  5. Nothing eligible → exit code 1. Queue and wait for the window. Buying another subscription rarely fixes what is a scheduling problem.

Safety

  • Secrets are never printed by quotamux, --pick or --json. Only --export emits keys — that is its entire job — and it writes them to stdout so you can eval them. Do not pipe --export into logs or CI output.
  • Config holds environment-variable names, never key material.
  • Native subscriptions (Claude Max OAuth) emit no environment at all. Injecting a base URL or bearer token there downgrades OAuth and kills the subscription channel — a mistake we made in production so you do not have to.

Notes

  • Queries run concurrently and are cached for 60 s (--fresh to bypass), so launching a batch of workers does not hammer the usage endpoints.
  • quotamux --json is stable machine output; build your own policy on top of it.

License

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

quotamux-0.1.0.tar.gz (24.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

quotamux-0.1.0-py3-none-any.whl (19.9 kB view details)

Uploaded Python 3

File details

Details for the file quotamux-0.1.0.tar.gz.

File metadata

  • Download URL: quotamux-0.1.0.tar.gz
  • Upload date:
  • Size: 24.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for quotamux-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2ae99294e9520495ad8dadb6eebef0379c8fe5e123de452048532b381f027da3
MD5 4fe0b8c032e0e720ba4a89cce8d92b3c
BLAKE2b-256 f0e88b2a31455d71a7cdac142bc126ecbb4ea407bc8b909cfc7ceb17c492634f

See more details on using hashes here.

Provenance

The following attestation bundles were made for quotamux-0.1.0.tar.gz:

Publisher: release.yml on mojumacro/quotamux

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file quotamux-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: quotamux-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for quotamux-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 28bc226a5fc0a7f37841374ed898eb1be1e2d5dfcd6954595b90d3cd03aeb241
MD5 76188e47ecd4e101aec476052ca7b3c7
BLAKE2b-256 c12cc8f955cadba3d50bff72cd29f59545bda2df1ddf4c6f8154ce5e9a7ba174

See more details on using hashes here.

Provenance

The following attestation bundles were made for quotamux-0.1.0-py3-none-any.whl:

Publisher: release.yml on mojumacro/quotamux

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page