English | 中文
Quota pooling + cost-aware routing for AI coding agents.
Your coding-agent subscriptions are already paid for. qpool pools the scattered quota from every agent CLI/IDE you own into one ledger, then routes each task to the cheapest entry that can actually do it — already-paid subscription quota (marginal cost ≈ 0) first, soon-expiring credit packs next, pay-as-you-go only when nothing else fits.
The way to save tokens is not to use fewer of them. It is to move work that would have hit a metered API onto quota you have already paid for.
subscription (paid, ~$0) → credit packs (expiring soon) → pay-as-you-go ($$)
consume first before it expires last resort
| Pain | Today |
|---|---|
| Subscription quota goes unused | Cursor/Kiro/Codex monthly fees are paid, but the quota sits idle in silos |
| Quota info is fragmented | N dashboards, N logins, N reset cycles to track |
| Metered APIs cost real money | The default path burns cash with no cost awareness |
| Credit packs expire | Free/purchased packs die quietly — nobody drains them first |
| Price ≠ capability | The cheapest entry that can do the task is the one that should |
qpool is a control plane. It deliberately does not re-implement the passthrough gateway — that job belongs to CLIProxyAPI, which qpool drives through its Management API.
┌─ collectors (11 real APIs + manual channel + plugin dir)
│ codex · claude-code · cursor · gemini · copilot · kimi
│ cline · grok(xAI mgmt) · doubao(ark) · windsurf · devin
│ │ qpool quota sync --apply
│ ▼
│ ┌───────────────────────────────────────────────┐
│ │ quota ledger (SQLite) │
│ │ entries: kind/total/remaining/TTL/cost/tier │
│ │ events: append-only usage log │
│ └───────────────────────────────────────────────┘
│ │ route_sort_key (marginal-cost ordering)
│ ▼
│ conductor: reconcile → disable/enable + priority + fill-first
│ │ Management API (localhost:8317/v0/management)
└─────────┤
▼
CLIProxyAPI — protocol bridge + multi-account pool (not reinvented here)
│ ANTHROPIC_BASE_URL / OPENAI_BASE_URL
▼
Claude Code · Codex CLI · any compatible harness
│ per-request tokens flow back via usage-queue
▼
task-level accounting → monthly savings report
- Quota ledger — one unified table for every agent × account: kind (subscription / credit pack / payg), remaining, TTL, unit cost, capability tier. Lazy reset-cycle rollover, append-only usage events (event sourcing).
- 11 real collectors — poll the vendors' own quota APIs using local CLI credentials (OAuth files, OS keychains, app state DBs). No re-login.
- Cost-aware routing — capability hard-filter first, then marginal-cost order: fuller subscriptions → soonest-expiring packs → cheapest metered API.
- Route simulation — the three bills before you commit a task: routed cost vs pay-as-you-go cost vs saved-by-pooling, with a failover chain and per-entry skip reasons.
- CLIProxyAPI control plane — reconcile loop pushes decisions to the
gateway: disable exhausted credentials, re-enable recovered ones, write
priority fields, set
fill-firstso the pool drains cheapest-first. - Task-level accounting — drains the gateway's per-request usage queue into the ledger; monthly report shows real money spent, payg-equivalent value of pooled usage, and saved by pooling.
- Daemon —
sync → reconcile → pull-usageon an interval, with a single-instance lock. Also--oncefor cron/launchd. - Plugin collectors — proprietary/internal agents live in
~/.qpool/collectors/, outside this repo (see below).
Requires Python ≥ 3.9, zero third-party dependencies.
git clone <your-fork-url> qpool && cd qpool
python3.11 -m venv ~/.local/share/qpool/venv
~/.local/share/qpool/venv/bin/pip install -e .
mkdir -p ~/.local/bin
ln -sf ~/.local/share/qpool/venv/bin/qpool ~/.local/bin/qpool # on your PATH
qpool quota list1. Register quota manually
qpool quota add --agent codex --account work --kind subscription \
--total 500 --unit requests --reset monthly --capability 4
qpool quota add --agent claude-code --account main --kind credit_pack \
--total 1000000 --unit tokens --expires 2026-10-01 --capability 5
qpool quota add --agent kimi-cli --account main --kind payg \
--cost-per-unit 0.000002 --unit tokens2. Or sync real readings from the vendors' own APIs (auto-detects local
CLI credentials; dry-run until --apply):
qpool quota sync # show what every collector can read
qpool quota sync --apply # write readings into the ledger3. Simulate before you commit — the three bills:
$ qpool quota simulate --amount 500000 --unit tokens --tier 3
route plan for 500,000 tokens, capability >= T3:
PRIMARY #2 claude-code/main credit_pack T5 1,000,000 left est $0
FALLBACK #3 kimi-cli/main payg T3 metered est $1
the three bills:
routed cost : $0
payg-only : $1
saved by pool : $14. Hook up CLIProxyAPI (the passthrough data plane)
export QPOOL_CPA_KEY=<remote-management.secret-key from your CLIProxyAPI yaml>
qpool quota cpa status # credential pool × ledger, with decisions
qpool quota cpa reconcile --apply # push disable/enable + priority + fill-first
qpool quota cpa pull-usage # book per-request tokens into the ledgerStandard OpenAI-compatible providers (e.g. Doubao/Ark) skip OAuth bridging entirely — register them as upstreams straight into the gateway:
export ARK_API_KEY=...
qpool quota cpa register-provider --name doubao --preset ark \
--model doubao-seed-2-1-pro-260628:doubao-pro
# Agent Plan / Coding Plan subscribers: add --plan (switches to /api/plan/v3)
# -> qpool quota cpa providers to verify5. Run the loop
qpool quota daemon # every 60s: sync → reconcile → pull-usage
qpool quota daemon --once # single round, cron/launchd friendly6. See what pooling saved you
qpool quota report
# real money spent (payg) : $0.24
# pooled usage, payg-equivalent : $1
# saved by pooling : $1| Agent | Credentials source | Quota API | Notes |
|---|---|---|---|
| Codex | ~/.codex/auth.json |
chatgpt.com/backend-api/wham/usage |
5h + 7d windows, credits |
| Claude Code | macOS Keychain → ~/.claude/.credentials.json |
api.anthropic.com/api/oauth/usage |
OAuth beta header |
| Cursor | state.vscdb ItemTable (read-only) |
api2.cursor.sh Connect-RPC |
email/membership too |
| Gemini CLI | ~/.gemini/oauth_creds.json |
cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota |
pro/flash families |
| Copilot | COPILOT_TOKEN / IDE hosts.json |
api.github.com/copilot_internal/user |
free-plan normalize |
| Kimi CLI | ~/.kimi-code/credentials/ |
api.kimi.com/coding/v1/usages |
string numerics tolerated |
| Cline | CLINE_API_KEY |
api.cline.bot/api/v1/users/{id}/balance |
official REST |
| Grok / xAI | XAI_MANAGEMENT_KEY + XAI_TEAM_ID |
management-api.x.ai/.../invoice/preview |
replaces gRPC-web reverse engineering |
| Doubao / Ark | VOLC_ACCESS_KEY_ID + VOLC_SECRET_ACCESS_KEY |
GetInferenceUsage (signature V4) |
monthly consumption |
| Windsurf | WINDSURF_SERVICE_KEY |
server.codeium.com/api/v1/GetTeamCreditBalance |
Enterprise |
| Devin | DEVIN_API_KEY |
api.devin.ai/v3/.../consumption/daily |
Enterprise, ACU |
| everything else | ~/.qpool/static_quotas.json |
— | manual channel (kiro, antigravity, qoder, opencode, …) |
| internal agents | ~/.qpool/collectors/*.py |
your API | plugin dir, never committed |
qpool quota add register a quota entry (subscription/credit_pack/payg)
qpool quota list ledger view (default: marginal-cost route order)
qpool quota consume record usage manually (strict: no overdraft)
qpool quota remove delete an entry and its events
qpool quota events append-only usage history
qpool quota simulate dry-run routing: the three bills + failover chain
qpool quota report monthly usage + savings report
qpool quota sync poll vendor APIs via local credentials (--apply to write)
qpool quota cpa CLIProxyAPI control plane: status/reconcile/pull-usage
qpool quota daemon control loop: sync -> reconcile -> pull-usage
qpool quota run dispatch a task to the cheapest capable agent, with failover
| Variable | Purpose |
|---|---|
QPOOL_DB |
ledger path (default ~/.qpool/qpool.db) |
QPOOL_CPA_URL |
CLIProxyAPI base (default http://localhost:8317) |
QPOOL_CPA_KEY |
CLIProxyAPI management key (remote-management.secret-key) |
QPOOL_STATIC_QUOTAS |
manual-channel JSON path |
QPOOL_COLLECTORS_DIR |
plugin collector dir (default ~/.qpool/collectors) |
~/.qpool/executors.json |
per-user agent→CLI mappings for quota run (out of repo): {"cli": {"<agent>": ["<cli>", "-p"]}} |
~/.qpool/credentials.json |
API keys as env fallback ({"ARK_API_KEY": "..."}) |
CODEX_HOME, KIMI_CODE_HOME, COPILOT_TOKEN, GEMINI_TOKEN, CLINE_API_KEY, XAI_MANAGEMENT_KEY, XAI_TEAM_ID, VOLC_ACCESS_KEY_ID, VOLC_SECRET_ACCESS_KEY, ARK_API_KEY_ID, WINDSURF_SERVICE_KEY, DEVIN_API_KEY |
collector credentials |
Internal or proprietary agents do not belong in this repo. Drop a Python file
in ~/.qpool/collectors/ exposing three symbols and it joins the registry:
# ~/.qpool/collectors/acme-agent.py
from qp.collectors.base import QuotaReading
AGENT = "acme-agent"
def detect_credentials():
return {"access_token": "...", "source": "internal"}
def fetch_readings(creds):
return [QuotaReading(agent="acme-agent", window_key="daily",
label="acme-agent (internal)", used_percent=33.0)]Then qpool quota sync --agent acme-agent --apply flows through the same
pipeline as every built-in collector.
- Capability hard filter —
capability_tierof the entry must be ≥ what the task needs (--tier), and the quota unit must match (tokenstasks cannot spendrequestsquota). - Marginal-cost order — subscriptions first (already paid; the fuller
one wins), credit packs next (soonest expiry wins — drain before it dies),
pay-as-you-go last (cheapest unit price wins). Expired/depleted entries
always sink to the bottom. Two strategies:
--strategy cost(default) picks the cheapest entry that meets the tier floor;--strategy capabilitypicks the strongest entry and lets cost break ties. - Gateway orchestration — that order becomes
priorityfields +fill-firston CLIProxyAPI, so the pool literally drains cheapest-first; exhausted credentials get disabled, recovered ones re-enabled withreset-quota. - Execution —
qpool quota run "<task>"walks the same failover chain and actually dispatches: headless agent CLIs (mapped per-user in~/.qpool/executors.json) or openai-compatible gateway upstreams, with per-candidate timeout, a--max-costpayg guard, and failover on quota/auth failure. The repo ships no agent-to-CLI mappings — which harnesses you run is your configuration, not project knowledge.
Polling your own quota (what qpool's collectors do) is read-only. Consuming subscription quota through a passthrough gateway is a different matter — Google explicitly prohibits using an AI Pro subscription via API; other vendors are unenforced but gray. That risk lives in the passthrough layer (CLIProxyAPI and friends), not in this control plane. Know your vendors' terms; qpool only makes the accounting and routing visible to you.
qpool is an original implementation — no third-party code is copied into this repository. Ideas and publicly observable functional facts (API endpoints, credential locations) were informed by:
- onWatch (GPL-3.0) — quota polling and reset-cycle detection ideas. Used strictly as an external reference; not included, copied, or linked, and not required to build or run qpool.
- claude-code-router — credential-pool status and cooldown model ideas.
- oh-my-codex — dispatch state machine and event-sourcing ideas.
- CLIProxyAPI (MIT) — the passthrough data plane qpool drives, as an external process via its Management API. Not bundled; install and run it separately.
See NOTICE for the full third-party acknowledgment text.