Three Claude Code rate limits on a Tuesday. Not a “that’s inconvenient” problem — a “my refactoring session with 400K tokens of loaded context just vanished” problem.
The first time, I groaned and logged into another account. The second time, I was annoyed. The third time, I was staring at a login screen while my second Max subscription — the one I’d bought specifically for this — sat idle on an account I hadn’t bothered to switch to yet.
I was rotating between Claude accounts like AOL screen names in 2003. I had three Max subscriptions at $100/month each. The bottleneck was not the money. It was the mechanics, so I built a load balancer for Claude Code sessions.
The expensive part was losing the session
Claude Code keeps its credentials in ~/.claude/.credentials.json. One file, one account. Every session on your machine reads that same file. If you want to use a different subscription, you copy new credentials over the old ones, restart your session, and lose everything — the conversation, the context, the flow.
The painful part was not the 30 seconds of switching. It was losing 400,000 tokens of context — roughly 300 pages of code and conversation in the model’s working memory — when I hit the rate-limit window, the rolling cap on exchanges over a time period.
Two terminals with different accounts? Not possible. They both read the same credentials file, so they’d fight over it.
Multi-account management for CLI tools is an underbuilt category. Cloud CLIs — AWS, GCP, and Azure — solved this years ago with named profiles. AI coding assistants have not, probably because most people do not run multiple subscriptions yet. If you use Claude Code enough to hit rate limits, a second subscription pays for itself immediately. It costs $100/month, and each time you get walled and have to restart, you lose more than that in context-rebuild time.
One environment variable separated the accounts
I found that Claude Code respects an environment variable called CLAUDE_CONFIG_DIR — a setting that tells it where to look for its configuration folder. Point it at a different directory, and that session gets its own credentials while sharing everything else through symlinks (filesystem shortcuts that point one path to another). That’s the whole trick. No daemon — a constantly-running background process you have to manage — no global state mutation, no race conditions between terminals.
~/.claude-multi/config/personal/
├── .credentials.json # Isolated — this account's token
├── settings.json → ~/.claude/settings.json # Shared
├── skills → ~/.claude/skills # Shared
└── memory → ~/.claude/memory # Shared
Each terminal launches with one account pinned for its duration. The sessions do not collide, and they do not know about each other. The tooling for two or three accounts does not need to be complicated: one environment variable, symlinks, and a scoring formula.
CLAUDE_CONFIG_DIR is a clean extension point: one variable, full credential isolation, and zero changes to Claude Code itself. If Anthropic adds native multi-account support someday, the architecture would probably look similar — isolated config directories with shared settings linked in.
Picking an account
Isolation solved concurrency. I still needed an answer to “which account should I use right now?” That became the balancer.
Every session records its start time, account name, and process ID (the number the operating system assigns to each running program) into a local SQLite database — a tiny file-based database that needs no server, just a file on disk. The CLI and SQLite tracker run on Bun, which starts significantly faster than Node and reads TypeScript directly, so there is no node_modules install. Background bun run calls record session starts and exits; there is no long-running daemon to manage or crash. When I type cl — the auto-balance alias that replaced my old claude command — the balancer reads that database, scores each account, and picks the best one. A rate-limited account gets deprioritized immediately.
how it actually works give me the detail
Credential isolation via CLAUDE_CONFIG_DIR. Claude Code reads credentials, settings, and skills from a single directory — but which directory is controlled by the CLAUDE_CONFIG_DIR environment variable. The balancer creates one directory per account and symlinks everything that should be shared (settings, skills, memory) back to a canonical source. Only .credentials.json is account-local. Result: any number of terminals run simultaneously, each pinned to its own account, with zero global state mutation.
Session tracking in SQLite via Bun. At session start, a background bun run process writes (account, pid, started_at) to a local SQLite database. At exit, it marks the row closed. This gives the balancer accurate active-session counts without a daemon — just a lightweight Bun script wired to shell hooks.
Scoring — continuous, no threshold cliffs. The balancer scores every account with a smooth formula, not a bucket system:
score = burst_remaining_ratio * 0.7
+ rolling_remaining_ratio * 0.3
- active_sessions * 2Ratios are [0, 1] floats, so the score degrades continuously as usage climbs rather than jumping at an arbitrary threshold. A fully rate-limited account gets an immediate −100 override, which is the only discontinuity — and it’s intentional, because a hard-walled account is genuinely unusable, not just less preferred.
Statusline color survival trick. Claude Code applies dimColor to statusline output, washing out normal ANSI escapes. The fix: bold truecolor — \033[1;38;2;R;G;Bm — which survives the dim pass because bold and 24-bit RGB are applied in separate render phases. Every palette color is also intentionally over-saturated to compensate. Testable: swap any statusline color to a plain \033[32m green and watch it disappear; restore the bold truecolor form and it snaps back.
The formula is not machine learning. It is a weighted heuristic: 70% burst usage ratio (how much short-term quota remains), 30% rolling usage (longer-term usage), minus 2 points per active session on that account. It follows actual usage and routes away from walled accounts without manual switching.
The first two attempts were bad. A Python watchdog polled rate limits every 30 seconds, which was too slow and loaded a Python runtime into every terminal launch. Round-robin switching alternated accounts without knowing whether one was rate-limited and the other was fresh. The scoring formula with active-session weighting was the third try.
What the statusline shows
I also wanted a quick view of the system, so I built a truecolor statusline — 24-bit terminal color with the full RGB range instead of the standard 256-color palette. It shows the model name, context window usage (how full the model’s working memory is), cumulative input and output tokens with per-turn deltas, and rate-limit percentages with time-until-reset.
The statusline reads Claude Code’s transcript directly. Same JSONL log format — JSON Lines, where each line is one event — that the ccusage tool parses. It totals input and output tokens across the entire session, including subagent sidechains (when Claude spawns helper agents to work in parallel), and color-grades every number from green through blue and yellow to red as values climb.
The statusline colors kept washing out. Claude Code applies a forced dimColor to statusline output — a rendering pass that mutes brightness. Normal ANSI color codes — the invisible escape sequences that control text color in terminal output — became nearly invisible. Bold truecolor escapes — \033[1;38;2;R;G;Bm — survive because bold and 24-bit color are applied in separate render phases. The palette is intentionally over-saturated to compensate. A plain green disappears; the bold truecolor form returns.
Installing it
git clone https://github.com/ArcsHealth/claude-power-user.git
cd claude-multi
./install.sh
The installer copies files to ~/.claude-multi/, adds a source line to your shell startup file (.bashrc or .zshrc), and configures the statusline. Then add your accounts:
claude-multi add personal
claude-multi add work
# Log into each account and save credentials
claude login
claude-multi save personal
claude login
claude-multi save work
# Create isolated config dirs
claude-multi setup
The save command refuses to overwrite credentials when the live token belongs to a different account, and duplicate detection prevents the same credentials from being saved under two names.
After that, cl auto-balances. cl-personal or cl-work picks explicitly. The shell aliases generate dynamically from the account list, which lives in one JSON file at ~/.claude-multi/config.json: add a third account called side-project and cl-side-project appears without any extra config. Adding or removing an account requires no database schema migration.
The internal version syncs credentials to remote machines. The open-source release deliberately stays single-machine.
Tools used: Claude Code by Anthropic, Bun by Oven. Source code: claude-multi.