ModelDeck · Guides · CLI proxy

Pool your Claude & Codex subscriptions behind a CLI proxy

By Tim Harris· Published August 7, 2026· Updated August 7, 2026· 10 min read

Some people don't want to pick an account at all — they want every subscription they own working as one pool. Instead of pointing Claude Code and Codex at their providers directly, you point them at a small proxy on your own machine. Every account is signed into that proxy, and it spreads requests across them, so a single long session draws from the whole pool instead of draining one plan. This guide sets that up end to end, then puts ModelDeck on top so you can see what the pool is actually doing.

The proxy used here is CLIProxyAPI — an open-source (MIT) proxy that exposes OpenAI-, Claude-, and Codex-compatible endpoints and handles the OAuth logins for you. It's a separate project, not part of ModelDeck; its docs live at help.router-for.me. What ModelDeck adds is the part a proxy can't show you: how much is actually left in each account it's routing to.

localhost:8317 — proxy credential pool
claude-personal@example.com.json
MaxWRR weight 10
5-hour limitin 53 min97%
7-day limitin 17 hrs37%
7-day · premium modelin 17 hrs62%
claude-work@example.com.json
MaxWRR weight 5
5-hour limitin 1 hr100%
7-day limitin 4 days54%
7-day · premium modelin 4 days13%
claude-side@example.com.json
ProWRR weight 0
5-hour limitin 2 hrs21%
7-day limitin 1 day3%
7-day · premium modelin 1 day0%

The end state, up front: three subscriptions in one pool, each with its live quota windows and a routing weight. The healthy account carries weight 10, the one pacing ahead of its reset gets 5, and the nearly-drained one sits at 0 — out of rotation until its window comes back. Recreated UI with example accounts.

1Install and run the proxy

On macOS, Homebrew is the shortest path. The proxy listens on port 8317.

brew install cliproxyapi
brew services start cliproxyapi

Linux one-liner installs, Docker, and Windows builds are covered in the upstream quick start.

Bind it to localhost. The shipped config leaves host empty, which listens on every interface. In your config.yaml, set host: 127.0.0.1 so your pooled accounts are reachable only from your own machine.

2Sign each subscription into the pool

Run the login flag once per account — a browser opens, you sign in with that account, and the proxy writes a credential file for it into its auth directory. Repeat for every Claude and Codex subscription you own.

cli-proxy-api --claude-login   # OAuth callback on port 54545
cli-proxy-api --codex-login    # OAuth callback on port 1455

Add --no-browser to print the login URL instead of opening a window — useful over SSH.

3Point your CLIs at it

Claude Code takes two environment variables. The token is a placeholder — the real credentials live in the proxy, not in your shell.

export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
export ANTHROPIC_AUTH_TOKEN=sk-dummy
Codex — ~/.codex/config.toml
model_provider = "cliproxyapi"

[model_providers.cliproxyapi]
base_url = "http://127.0.0.1:8317/v1"
experimental_bearer_token = "sk-dummy"
wire_api = "responses"

4Turn on weighted routing

Round-robin treats every account equally, which is exactly wrong when one is nearly empty. Switch the strategy to weighted, and each account's share becomes a number you control.

config.yaml
routing:
  strategy: weighted-round-robin
  session-affinity: true
  session-affinity-ttl: 1h

Then add a top-level integer weight to each account's credential JSON in the auth directory. Higher means a bigger share of traffic; zero or negative takes that account out of rotation entirely without deleting it — that's the weight 0 badge in the shot above.

Session affinity keeps one conversation pinned to the account that started it, so a long session doesn't hop mid-thread. Failover still moves it if that account goes unavailable.

What the pool looks like over time

Each account's weekly window is its own clock, opening when you first use the account and resetting seven days later. Once several subscriptions are pooled, those clocks interleave — and that's the whole point: while one account waits out its reset, the others carry the traffic.

quota windows — two weeks
SunMonTueWedThuFriSatSunMonTueWedThuFriSat
claude-personal@example.com
7-day limit 37%
37% · resets Satnext window
claude-work@example.com
7-day limit 54%
54% · resets Wed
codex-personal@example.com
weekly 61%
61% · resets Thunext window
claude-side@example.com
7-day limit 3%
3% · resets Frinext window
current windowelapsedupcoming

Staggered resets are a feature. Because each window opened at a different moment, the pool never resets all at once — there's almost always an account that just got fresh capacity. A weighting policy can lean on whichever account is closest to reset with quota to spare. Recreated UI with example accounts.

5Put ModelDeck on top

Once the proxy is routing, the question stops being "which account am I on" and becomes "which accounts still have room". ModelDeck answers that from the menu bar — and on machines with a proxy installed, each deck card also shows the routing weight that account currently carries, as a quiet badge beside the plan tier. Usage and routing share, side by side:

ModelDeck — deck
☀ Claude
Personalweight 10Max (20x)
5-hour windowresets 8:49 AM97%
Weeklyresets Sat37%
Workweight 5Max
Weeklyresets Wed54%
Weekly · premium modelresets Wed13%
Side projectweight 0Pro
Weeklyresets Fri3%
◎ Codex
Personalweight 8Pro
Weeklyresets Thu61%
Clientweight 3Team
Weeklyresets Mon28%

The tie-together. The same accounts the proxy is routing, with their live usage and their current routing weight in one glance — you can see both what's left and where the balancer is sending traffic right now. Recreated UI with example accounts.

And this is where pooling stops being bookkeeping and starts answering the only question that matters at 9am: "can I launch the big run today?" Click the provider header and ModelDeck renders a single verdict for the entire pool — every account's remaining capacity, tier-weighted and simulated forward through the next seven days of staggered resets, compressed into one green / yellow / red answer:

ModelDeck — Claude availability

Claude availability

Only 745 pts are usable right now, across 2 of 3 accounts. The next reset lands in 17 hr. Your weekly pace itself is fine — this is about what you can start today.

Green: safe to launch heavy multi-agent work. Yellow: normal work is fine — hold the heavy runs until the next reset. Red: slow down and focus on one project. The bar shows how close you are to the neighboring band.

Pool now: 1,010 of 2,600 pts Measured pace: 310 pts/day Usable now: 745 pts across 2 of 3 accounts Current burn: ~640 pts/day (2.1× your weekly pace) At today's rate: pool bottoms out in ~14 hr; next reset lands in 17 hr Lowest point over 7 days: 180 pts Burst headroom today: ~105 pts Next big reset: Personal, resets in 17 hr (+2,000 pts)

Points are tier-weighted capacity: one Pro plan-week is 100 points, a Max 20x week is 2,000.

The whole pool, one verdict. Not "account three is at 9%" — but "you have ~105 points of burst headroom today, the pool bottoms out in 14 hours, and 2,000 points come back tomorrow morning." It knows a drained account isn't dead, just early — every account snaps back to full at its known reset in the simulation. This works with any multi-account deck; with the proxy underneath, it describes capacity your CLI will actually draw on automatically. Recreated UI with example accounts.

ModelDeck reads only the non-secret weight and identity fields from the proxy's credential files. It never writes to them, never routes a request, and never changes your pool. Claude accounts are matched by email, Codex by account identifier; a machine without the proxy simply shows nothing.

Auth directory: ModelDeck looks in ~/.config/cliproxyapi/auth. CLIProxyAPI's own default is ~/.cli-proxy-api — if you keep yours there, point the daemon at it with MODELDECK_CLIPROXY_AUTH_DIR, or set auth-dir in the proxy config to match.

6Close the loop: weights that follow real usage

Hand-set weights go stale within hours. The setup this guide was written from closes the loop instead: ModelDeck's local daemon exposes every account's live remaining percentage, window reset times, and account identifiers at http://127.0.0.1:3867/api/state, and a small scheduled job re-derives the weights from it.

ModelDeck daemonlive usage per account 127.0.0.1:3867/api/state Scheduled jobevery 5 minutes
Scheduled jobderives weight from pace weight: 10 / 5 / 3 / 0 CLIProxyAPIweighted round-robin
CLIProxyAPIserves Claude Code & Codex usage changes ModelDeck daemonsees it, loop repeats

The loop. Usage drives weights, weights drive routing, routing drives usage. No component guesses: the weights always reflect what the accounts actually have left.

The policy that has held up in practice, if you build your own:

# weight from pace, not just from remaining %
pace = (remaining / 100) / (hours_until_reset / 168)

pace >= 2.0  -> 10      # way ahead: drain this one first
pace >= 1.5  ->  8
pace >= 1.0  ->  5      # on pace for the cycle
pace >= 0.7  ->  3
otherwise    ->  1
remaining < 5%  -> 0    # bench it until the window resets

Why pace and not just percentage: quota left over at reset is quota wasted. An account at 40% with a day to go should be drained harder than an account at 40% with a week left. Weighting on pace pushes work toward whatever would otherwise expire unused.

Watch the model-scoped windows separately. Anthropic meters its premium model in its own weekly bucket, so an account that's out of premium capacity still has its full general weekly allowance for every other model. Benching it outright strands half its quota. Better: leave it in the pool and give that one account an excluded-models list, so it keeps serving the models it can still serve.

Two rules worth stealing. Never edit credential files while the proxy is running — stop it, write, start it again, or a shutdown flush can overwrite your edits. And if the usage numbers are stale or the daemon is down, change nothing: weighting from guessed numbers is worse than leaving yesterday's weights in place.

Frequently asked questions

Does this violate provider terms? You're using your own subscriptions, signed in through each provider's own OAuth flow, at the rate limits each account already has. The proxy doesn't bypass, spoof, or game any limit — it only chooses which of your accounts serves each request.

Does ModelDeck require the proxy? No. ModelDeck works standalone as a multi-account usage monitor. The proxy integration is additive: if the credential files are present, weight badges appear; if not, nothing changes.

Can ModelDeck change the weights? No, by design. ModelDeck reads and displays; your proxy and your rebalance job make the routing decisions. That split is part of ModelDeck's safety contract.

See the whole pool at a glance.

ModelDeck puts every account's remaining capacity — and its routing weight — in your menu bar. Free, local-only.

Download ModelDeck for macOS