Manage multiple Claude Code accounts with usage tracking, load balancing, and a system tray app
This project is derived from can1357/c2switcher, the original multi-account Claude Code manager created by @can1357. The core concept, load-balancing algorithm, and CLI design all originate there. All credit for the original idea and implementation belongs to them.
The lineage is:
can1357/c2switcher (original — KDE Plasma widget + CLI)
↓
incompletebiped/c2switcher-mint (Linux port — Cinnamon panel applet)
↓
incompletebiped/c2switcher-windows (this repo — Windows system tray app)
This Windows edition is a substantial adaptation rather than a direct code fork — the system tray UI was rewritten from scratch in PySide6, and Windows-specific changes were made throughout — but the foundational ideas, API approach, and load-balancing logic are entirely derived from the original work. The original is released under the MIT License.
- Multi-account management — Add, remove, reorder, and nickname accounts
- Auto-detect new logins — Tray app monitors
~\.claude\.credentials.jsonand auto-imports new accounts - Usage tracking — Monitor 5-hour, 7-day, and Sonnet usage limits with color-coded indicators
- Smart load balancing — Automatically picks the optimal account based on usage, drain rates, and active sessions
- Session-safe switching — Detects when Claude Code is actively processing and blocks switching mid-request
- Auto-switch on rate limit — When your current account hits 95%+ usage, automatically swaps to the optimal account between prompts or after the session ends
- Active account indicator — Shows which account Claude Code is currently using
- Session tracking — See which accounts are actively being used and where
- Light/dark themes — Toggle between themes from the tray popup
- Windows system tray app — Monitor all accounts from the system tray with one-click switching
- Usage caching — Respects rate limits with 5-minute cache
- Wrapper script —
c2claudePowerShell command for seamless account switching - Start with Windows — Optional registry entry to launch the tray app at login
- Single executable — Builds to a standalone
c2switcher.exevia PyInstaller
This tool uses undocumented OAuth API endpoints to fetch usage data and authenticate accounts. While Anthropic allows users to create multiple accounts (confirmed by multiple people who asked Anthropic Staff), this implementation relies on reverse-engineered API endpoints that may change without notice.
If Anthropic would prefer this tool not exist, please reach out and I'll gladly take it down.
- Windows 10/11
- Python 3.10+
- Claude Code CLI installed and configured
git clone https://github.com/incompletebiped/c2switcher-windows.git
cd c2switcher-windows
pip install -e .pip install -e .[build]
pyinstaller build.spec
# produces dist/c2switcher.exePlace c2switcher.exe somewhere on your PATH, or keep it alongside c2claude.ps1.
Copy c2claude.ps1 to a directory on your PATH, or create a PowerShell alias:
Set-Alias c2claude "C:\path\to\c2claude.ps1"# Recommended: OAuth login (opens browser)
c2switcher login
# Add more accounts
c2switcher login
# Or import existing credentials from ~/.claude/.credentials.json
c2switcher addc2switcher nickname 0 main
c2switcher nickname 1 work# Check that accounts are registered
c2switcher ls
# Fetch usage
c2switcher usage
# Launch Claude with the optimal account
c2claudeRun c2switcher with no arguments (or double-click c2switcher.exe) to launch the system tray app.
Tray icon: Color-coded by overall usage status:
- Green (< 70%) — Plenty of headroom
- Yellow (70–90%) — Getting close
- Red (> 90%) — Nearly exhausted
Popup (click the tray icon):
- Header with refresh and optimal-switch buttons
- Usage bars showing per-account utilization
- Account cards — one per account, showing:
- Active indicator for the currently active account
- Index, nickname, and email
- Usage indicators: 5-hour, 7-day, and Sonnet
- Time-until-reset countdown
- Light/dark theme toggle
The tray app detects whether Claude Code is actively processing by checking for established TCP connections from Claude's PIDs via psutil:
| State | Optimal button | Manual card click |
|---|---|---|
| Claude idle at prompt | Unlocked | Works |
| Claude streaming a response | Locked | Works (use at your own risk) |
| No Claude process running | Unlocked | Works |
When the current account's usage reaches 95%+ (on either the 5-hour or 7-day window), the tray app automatically switches to the optimal account:
- Between prompts — If Claude is open but idle, credentials are swapped seamlessly
- After session ends — If Claude Code is closed, credentials are pre-positioned for the next session
- During processing — Auto-switch waits until the current request finishes
- 5-minute cooldown between auto-switches to prevent rapid back-and-forth
- Only triggers when there are 2+ accounts registered
The tray app monitors ~\.claude\.credentials.json for changes. When a new login is detected (refresh token changes), the new account is automatically imported. Regular token refreshes are ignored.
The tray app can register itself in the Windows startup registry (HKCU\Software\Microsoft\Windows\CurrentVersion\Run) to launch automatically at login.
Show the active account, nickname, and live usage in the Claude Code status bar.
What it looks like:
[1] BxB Media 5h:20% 7d:3%
The label [index] nickname is purple. Each percentage is color-coded green/yellow/red matching the tray thresholds (< 70% / 70–90% / > 90%).
Why this approach: c2switcher.exe takes ~3–4 seconds to start (PyInstaller + SQLite + DPAPI) — far too slow for a status line. Instead, the tray app writes %APPDATA%\c2switcher\current_account.txt on every refresh (every 60s and on each switch), and the status line reads that file directly via PowerShell (~800ms).
Prerequisite: The tray app must be running. It writes the cache file; the status line just reads it. The file is created on the tray's first refresh after launch.
Setup:
If you're using this repo with Claude Code, run the included slash command — it auto-detects your username and writes the correct config:
/setup-statusline
Or add manually to %USERPROFILE%\.claude\settings.json:
{
"statusLine": {
"type": "command",
"command": "cat /c/Users/YOUR_USERNAME/AppData/Roaming/c2switcher/current_account.txt"
}
}Replace YOUR_USERNAME with your Windows username. Restart Claude Code for the setting to take effect.
Troubleshooting:
| Symptom | Fix |
|---|---|
| Nothing shows | Confirm the tray app is running and %APPDATA%\c2switcher\current_account.txt exists |
Plain text [1] nickname with no usage or color |
Tray app is running an old build — rebuild with .\build.ps1 and restart |
Escape codes show as literal text ([38;5;141m...) |
Claude Code version doesn't support ANSI in the statusline — upgrade Claude Code |
Rebuilding after source changes:
Always use build.ps1 — it installs to the correct location and creates the Start Menu shortcut:
.\build.ps1Do not run pyinstaller build.spec directly (that outputs to dist/ and won't update the installed exe). After rebuilding, restart the tray app for changes to take effect.
If you're working on this repo inside Claude Code, the following slash commands are available:
| Command | Description |
|---|---|
/setup-statusline |
Auto-configure the Claude Code statusline for c2switcher |
/rebuild |
Run build.ps1, report result, and remind you to restart the tray |
/diagnose |
Full health check — tray process, cache file, accounts, token validity |
/add-account |
Guided OAuth login flow with nickname prompt and verification |
/debug-auth |
Deep token inspection — expiry times, stale flags, cross-reference active credentials |
/check-sessions |
Active and recent sessions, stale PID detection, per-account counts |
These are defined in .claude/commands/ and require no setup — just open the repo in Claude Code and invoke them.
Option 1: OAuth Login (Recommended)
c2switcher loginOption 2: Import Existing Credentials
c2switcher add # Add current account
c2switcher add --nickname work # With a nickname
c2switcher add --creds-file ~/path/to/credentials.json # From a specific filec2switcher lsc2switcher nickname 0 "My Work Account" # By index
c2switcher nickname work "Work Pro" # By current nickname
c2switcher nickname [email protected] "Main" # By emailc2switcher remove 0 # By index (prompts for confirmation)
c2switcher remove work # By nickname
c2switcher remove [email protected] # By email
c2switcher remove 0 --yes # Skip confirmationIf the removed account is currently active in ~\.claude\.credentials.json, the credentials file is also cleared.
c2switcher usage # Rich table output
c2switcher usage --force # Bypass 5-minute cache
c2switcher usage --json # JSON output for scriptingColor indicators:
- Green (< 70%) — Plenty of headroom
- Yellow (70–90%) — Getting close
- Red (> 90%) — Nearly exhausted
c2switcher switch 0 # By index
c2switcher switch work # By nickname
c2switcher switch [email protected] # By emailc2switcher optimal # Auto-switch to best account
c2switcher optimal --dry-run # Show best without switching
c2switcher optimal --token-only --quiet # Get token for scriptsc2switcher cycle # Rotate to next accountc2switcher current
c2switcher current --format=prompt # For shell prompts: [0] main
c2switcher current --json# Session insights (top projects, daily cadence, heatmaps)
c2switcher report-sessions --output ~/c2switcher_session_report.png --days 30
# Usage risk forecast (burn rates, reset timeline)
c2switcher report-usage --output ~/c2switcher_usage_report.png --window-hours 24PowerShell script that combines account selection with running Claude Code:
c2claude # Use optimal account (default)
c2claude -0 # Use account 0
c2claude -1 # Use account 1
c2claude -a work # Use account by name/email/index
c2claude --cycle # Cycle to next account
c2claude -p "explain this" # Pass arguments to claudeThe wrapper handles session registration, load balancing, account stickiness, and cleanup on exit.
| Command | Aliases | Description |
|---|---|---|
login |
OAuth login and add account | |
add |
Import existing account credentials | |
remove |
Remove an account from c2switcher | |
nickname |
Set or update an account nickname | |
reorder-accounts |
Reorder accounts by specifying new order | |
ls |
list, list-accounts |
List all accounts |
usage |
Show usage across accounts | |
current |
Show currently active account | |
force-refresh |
Force token refresh for account(s) | |
report-sessions |
Generate session analytics report | |
report-usage |
Generate usage risk forecast report | |
optimal |
pick |
Find and switch to optimal account |
switch |
use |
Switch to specific account |
cycle |
Rotate to next account | |
list-sessions |
List active sessions | |
session-history |
history |
Show past sessions with usage deltas |
apikey |
Manage API keys |
| Command | Description |
|---|---|
start-session |
Register a new Claude session |
end-session |
Mark a session as ended |
All data is stored in %APPDATA%\c2switcher\store.db (SQLite):
- Account credentials and metadata
- Usage history with timestamps
- Session tracking (PID, working directory, duration)
Tokens are automatically refreshed when within 10 minutes of expiry. Force a manual refresh:
c2switcher force-refresh # All accounts
c2switcher force-refresh work # Specific accountAPI calls are cached for 5 minutes to avoid rate limiting. Use --force to bypass.
The optimal account selection uses a multi-factor scoring system:
- Drain rate (core metric) —
headroom / hours_until_resetwhere headroom = 99% − current utilization. Higher drain rate = more capacity available per hour = better candidate. - Five-hour throttling — Penalizes accounts with high short-term usage to prevent burst rate limits. Score is halved at 90%+ five-hour utilization.
- Burst protection — Skips accounts where current usage + expected burst (based on historical deltas) >= 94%.
- Pace alignment — Adjusts score based on whether usage is ahead of or behind the expected pace for the reset window.
- Session awareness — Among similar candidates, prefers accounts with fewer active and recent sessions.
- Round-robin — Accounts within 0.05 %/hr of each other are treated as equivalent and rotated fairly.
Accounts at 99%+ utilization are excluded entirely.
Each c2claude invocation registers a session, selects an account, runs Claude, and cleans up on exit. Dead sessions are auto-cleaned via multi-factor liveness checks using psutil.
| Path | Purpose |
|---|---|
%APPDATA%\c2switcher\store.db |
SQLite database (accounts, usage, sessions) |
%APPDATA%\c2switcher\load_balancer_state.json |
Round-robin state for fair rotation |
%APPDATA%\c2switcher\.lock |
File lock for concurrent operation safety |
%APPDATA%\c2switcher\theme.json |
Theme preference (light/dark) |
%APPDATA%\c2switcher\headers.json |
HTTP header configuration |
%APPDATA%\c2switcher\current_account.txt |
Cache file for status line (written by tray app) |
~\.claude\.credentials.json |
Active Claude Code credentials |
| Variable | Description |
|---|---|
DEBUG_SESSIONS=1 |
Enable verbose session tracking logs |
C2SWITCHER_DEBUG_BALANCER=1 |
Show detailed load balancer scoring |
| Mint (Linux) | Windows | |
|---|---|---|
| Desktop integration | Cinnamon panel applet (JavaScript) | System tray app (PySide6 + pystray) |
| Process detection | ss (socket statistics) |
psutil |
| Data directory | ~/.c2switcher/ |
%APPDATA%\c2switcher\ |
| Wrapper script | c2claude (Bash) |
c2claude.ps1 (PowerShell) |
| Startup | Desktop autostart | Windows registry (HKCU\...\Run) |
| Distribution | pipx install |
pip install or standalone .exe via PyInstaller |
| Installer | setup.sh |
Manual |
Ensure the install location is on your PATH. If installed via pip:
# Check where it was installed
pip show c2switcher
# Or for the exe build, add dist/ to your PATHc2switcher loginLog in with the affected account — the existing account record is updated automatically by UUID match.
Verify Claude works: claude -p hi --model haiku
Dead sessions auto-cleanup, but you can check manually:
c2switcher list-sessionsMake sure c2switcher is on your PATH and that accounts have been added:
c2switcher ls
c2switcher usagegit clone https://github.com/incompletebiped/c2switcher-windows.git
cd c2switcher-windows
pip install -e .
c2switcher --helpThe CLI entry point is c2switcher, and the Python package lives under c2switcher/. The system tray app source is in c2switcher/presentation/tray/.
Based on c2switcher-mint, itself a fork of can1357/c2switcher.
Tip: Add c2claude.ps1 to your PowerShell profile as an alias for maximum laziness.