Manage multiple Claude Code accounts with usage tracking, load balancing, and a KDE Plasma widget
C2Switcher is a practical CLI tool for juggling multiple Claude Code accounts. It tracks usage, automatically selects the best account based on availability, and includes a neat Plasma widget for at-a-glance monitoring.
- Multi-account management - Store and switch between multiple Claude Code 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 and active sessions
- Session tracking - See which accounts are actively being used and where
- KDE Plasma widget - Monitor all accounts from your panel
- Usage caching - Respects rate limits with 5-minute cache
- Wrapper script -
c2claudecommand for seamless account switching
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, including me), 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. I'm very compliant like that :)
curl -fsSL https://raw.githubusercontent.com/can1357/c2switcher/master/setup.sh | bashOr download and run interactively:
git clone https://github.com/can1357/c2switcher.git
cd c2switcher
./setup.shThe interactive installer will ask what you want to install:
- CLI tools only
- CLI tools + KDE Plasmoid
- Plasmoid only (if CLI already installed)
# Install the package locally (editable)
pip install -e .
# Or use setup.sh with options (installs via pip under the hood)
./setup.sh --cli # CLI tools only
./setup.sh --plasmoid # Plasmoid only (requires CLI)
./setup.sh --all # Install everythingOption 1: OAuth Login (Recommended)
Authenticate directly with Anthropic and automatically add the account:
c2switcher loginThis uses dual-flow authentication (automatic localhost callback + manual fallback) matching Claude Code's native behavior. Options:
# Login with a nickname
c2switcher login --nickname work
# Manual-only mode (disable localhost server)
c2switcher login --manual-only
# Don't auto-open browser
c2switcher login --no-browser
# Save credentials but don't add to c2switcher
c2switcher login --no-addOption 2: Import Existing Credentials
Add your current account (from ~/.claude/.credentials.json):
c2switcher addAdd with a memorable nickname:
c2switcher add --nickname workAdd from a specific credentials file:
c2switcher add --creds-file ~/path/to/credentials.json --nickname personal$ c2switcher lsOutput:
Claude Code Accounts
╭───────┬──────────┬────────────────────┬───────────┬──────┬───────────────────╮
│ Index │ Nickname │ Email │ Name │ Type │ Tier │
├───────┼──────────┼────────────────────┼───────────┼──────┼───────────────────┤
│ 0 │ main │ ****@gmail.com │ **** │ Max │ default_claude... │
│ 1 │ work │ ****@gmail.com │ **** │ Max │ default_claude... │
│ 2 │ personal │ ****@gmail.com │ **** │ Max │ default_claude... │
╰───────┴──────────┴────────────────────┴───────────┴──────┴───────────────────╯
$ c2switcher usageOutput:
Usage Across Accounts
╭───────┬──────────┬────────────────────┬─────┬─────┬─────────┬──────────╮
│ Index │ Nickname │ Email │ 5h │ 7d │ 7d Sonnet │ Sessions │
├───────┼──────────┼────────────────────┼─────┼─────┼─────────┼──────────┤
│ 0 │ main │ ****@gmail.com │ 0% │ 45% │ 87% │ 0 │
│ 1 │ work │ ****@gmail.com │ 5% │ 77% │ 100% │ 0 │
│ 2 │ personal │ ****@gmail.com │ 11% │ 3% │ 6% │ 1 │
╰───────┴──────────┴────────────────────┴─────┴─────┴─────────┴──────────╯
Active Sessions (1):
* ****@gmail.com (/home/user/projects/myproject, 4m ago)
Color indicators:
- 🟢 Green (< 70%) - Plenty of headroom
- 🟡 Yellow (70-90%) - Getting close
- 🔴 Red (> 90%) - Nearly exhausted
Force refresh (ignore 5min cache):
c2switcher usage --forceJSON output for scripting:
c2switcher usage --jsonTwo rich analytics dashboards are built in. Each command prints a detailed terminal summary and saves a PNG visualization (default paths shown).
# Session insights (top projects, daily cadence, heatmaps, recommendations)
c2switcher report-sessions \
--db ~/.c2switcher/store.db \
--output ~/c2switcher_session_report.png \
--days 30 \
--min-duration 60
# Usage risk forecast (limit timing, burn rates, reset timeline)
c2switcher report-usage \
--db ~/.c2switcher/store.db \
--output ~/c2switcher_usage_report.png \
--window-hours 24Add --show if you want the figure displayed after it is written.
Switch by index:
c2switcher switch 0Switch by nickname:
c2switcher switch workSwitch by email:
c2switcher switch [email protected]c2switcher optimalThis automatically switches to the best account based on:
- Drain rate urgency - Headroom ÷ hours until reset (prioritizes accounts about to reset)
- Fresh account bonus - Boosts accounts with <25% usage (up to +3.0 %/hour)
- Five-hour throttling - Multiplicative penalty for high 5-hour usage (90%: ×0.5, 85%: ×0.7, 80%: ×0.85)
- Tier priority - Sonnet capacity (tier 1) preferred over overall (tier 2)
- Burst protection - Skips accounts where usage + expected burst ≥ 94%
- Load balancing - Round-robin for similar drain rates, considers active/recent sessions
Show optimal account without switching:
c2switcher optimal --dry-runGet token only (for scripts):
c2switcher optimal --token-only --quietSee which account is currently active:
c2switcher currentFor use in shell prompts:
c2switcher current --format=prompt
# Output: [0] main
# Example PS1 integration:
PS1='$(c2switcher current --format=prompt) $ 'JSON output:
c2switcher current --jsonRotate to the next account in your list:
c2switcher cycleUseful for quick manual rotation without looking up indices.
The wrapper combines account selection with running Claude Code:
# Use optimal account (default)
c2claude
# Use account 0
c2claude -1
# Use account 1
c2claude -2
# Use account by name/email/index
c2claude -a work
# Cycle to next account
c2claude --cycle
# Pass arguments to claude
c2claude -p "explain this code"
c2claude --model opus -p "complex task"The wrapper handles:
- Session registration and tracking
- Load balancing (even for short commands)
- Account stickiness (reuses the same account for a session)
- Cleanup on exit
Want to hack on the tool?
git clone https://github.com/can1357/c2switcher.git
cd c2switcher
pip install -e .
python -m c2switcher --helpThe CLI entry point is c2switcher, and everything now lives under the c2switcher/ package for easier maintenance.
- Compact panel view: Shows average Sonnet usage with color-coded badge
- Detailed popup: Combined usage bar + individual account cards
- Quick switching: One-click optimal account selection
- Auto-refresh: Polls every 60 seconds
- No services needed: Directly executes
c2switchercommands
./setup.sh --plasmoidOr manually:
kpackagetool6 --type=Plasma/Applet --install plasmoid- Right-click panel -> "Add Widgets..."
- Search for "Claude Code Usage"
- Drag to panel
| Command | Aliases | Description |
|---|---|---|
login |
OAuth login and add account | |
add |
Import existing account credentials | |
ls |
list, list-accounts |
List all accounts |
usage |
Show usage across accounts | |
current |
Show currently active account | |
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 | |
sessions |
List active sessions | |
history |
session-history |
Show past sessions with usage deltas |
force-refresh |
Force token refresh for account(s) |
These are typically called by c2claude, not manually:
| Command | Description |
|---|---|
start-session |
Register a new Claude session |
end-session |
Mark a session as ended |
All commands support:
--json- Output as JSON (where applicable)--help- Show command help
All data is stored in ~/.c2switcher/store.db (SQLite):
- Account credentials and metadata
- Usage history with timestamps
- Session tracking (PID, working directory, duration)
When a token expires (or within 10 minutes of expiry), c2switcher automatically refreshes it using Anthropic's OAuth token endpoint. This is a direct API call that doesn't consume usage.
Force refresh tokens manually:
# Refresh all accounts
c2switcher force-refresh
# Refresh specific account
c2switcher force-refresh workIf refresh fails (e.g., revoked or invalid credentials), you'll see:
Error: Direct token refresh failed. Please re-authenticate.
In this case, log in to Claude Code with that account and re-add it to c2switcher.
API calls are cached for 5 minutes to avoid rate limiting. Use --force to bypass the cache.
The optimal account selection uses a sophisticated drain-rate scoring system:
-
Baseline drain rate:
(99% - current_usage) / hours_until_reset- Measures %/hour capacity before limit
- Higher = more urgent to use (about to reset soon)
-
Sonnet pace gate: Pace adjustment only when sonnet ≥90%
- Keeps hot sonnet accounts draining faster near reset
- Prevents lukewarm sonnet accounts from crowding out cooler ones
-
Low-util bonus: Overall usage <60% earns up to +5.0 %/hour (clamped at 20%)
- Only active while sonnet <85%
- Rewards underused accounts without over-weighting near-zero usage
-
Sonnet penalty: Sonnet ≥95% subtracts 2.0 %/hour to steer load elsewhere
-
Priority score:
baseline_drain + pace_adj + low_bonus − sonnet_penalty -
Five-hour throttling: Multiplicative penalty for high short-term usage
- 90%+ in last 5h: ×0.5 (half priority)
- 85-90%: ×0.7
- 80-85%: ×0.85
- Prevents overuse concentration
-
Adjusted drain:
priority_score × five_hour_factor -
Final ranking (in order):
- Adjusted drain (primary metric)
- Utilization (lower is better)
- Hours to reset (closer = better)
- Five-hour util (lower = better)
- Active sessions (fewer = better)
- Recent sessions (fewer = better)
-
Filtering:
- Burst protection: Skip if
usage + expected_burst ≥ 94% - Cool-down: Prefer accounts with 5-hour usage <90%
- Window priority: overall window is used while it has headroom, sonnet only once overall is exhausted
- Burst protection: Skip if
-
Round-robin: Accounts with similar drain (±0.05 %/hour) rotate fairly
This maximizes total usage across all accounts while preventing limit violations.
Each c2claude invocation:
- Registers a session (PID, working directory)
- Requests optimal account (with session ID for stickiness)
- Switches to the selected account
- Runs Claude
- Marks session as ended on exit
Dead sessions are automatically cleaned up using multi-factor liveness checks.
| Variable | Description |
|---|---|
DEBUG_SESSIONS=1 |
Enable verbose session tracking logs |
C2SWITCHER_DEBUG_BALANCER=1 |
Show detailed load balancer scoring |
| Path | Purpose |
|---|---|
~/.c2switcher/store.db |
SQLite database (accounts, usage, sessions) |
~/.c2switcher/load_balancer_state.json |
Round-robin state for fair account rotation |
~/.c2switcher/.last_cleanup |
Session cleanup throttle marker |
~/.claude/.credentials.json |
Active Claude Code credentials |
/usr/local/bin/c2switcher |
CLI tool |
/usr/local/bin/c2claude |
Wrapper script |
./setup.sh --uninstallOr manually:
# Automatic uninstall
./setup.sh --uninstall
# Or manually:
# Remove CLI tools
sudo rm /usr/local/bin/c2switcher /usr/local/bin/c2claude
# Remove plasmoid
kpackagetool6 --type=Plasma/Applet --remove org.claudecode.usage.plasma
# Remove all c2switcher data (optional)
rm -rf ~/.c2switcher/# Add your accounts via OAuth login
c2switcher login --nickname main
c2switcher login --nickname work
c2switcher login --nickname personal
# Or import existing credentials
c2switcher add --nickname main
c2switcher add --nickname work
c2switcher add --nickname personal
# Check usage
c2switcher usage
# Use optimal account automatically
c2claude
# Or manually pick one
c2claude -a work
# Check session history
c2switcher history# Get JSON output for parsing
optimal=$(c2switcher optimal --dry-run --json)
email=$(echo "$optimal" | jq -r '.email')
echo "Best account: $email"
# Get current account
current=$(c2switcher current --json)
echo "Active: $(echo "$current" | jq -r '.email')"
# Check if any account has Sonnet available
c2switcher usage --json | jq '.[] | select(.usage.seven_day_sonnet.utilization < 90)'
# Get token for scripting
token=$(c2switcher optimal --token-only --quiet)
# Now use $token with Anthropic API# Try each account until one works
for i in {0..2}; do
c2switcher switch $i
claude -p "test" && break
done- Python 3.7+
- Claude Code CLI installed and configured
- KDE Plasma 6.0+ (for plasmoid only)
click>= 8.1.0rich>= 13.0.0requests>= 2.31.0psutil>= 5.9.0
Installed automatically via requirements.txt.
Ensure /usr/local/bin is in your PATH:
export PATH="/usr/local/bin:$PATH"Add to ~/.bashrc or ~/.zshrc to make permanent.
If you see "Failed to refresh token. The credentials may be revoked or invalid":
- Log in to Claude Code with that account to generate fresh credentials
- Re-add the account to c2switcher:
c2switcher add --nickname <name>
Make sure the claude command works:
claude -p hi --model haikuVerify c2switcher works from terminal:
c2switcher usage --jsonCheck plasmoid logs:
journalctl -f | grep plasmashellRestart plasmashell to reload the widget:
systemctl --user restart plasma-plasmashellOr remove and re-add the widget to your panel.
Dead sessions should auto-cleanup, but you can manually verify:
c2switcher sessionsEnable debug mode:
DEBUG_SESSIONS=1 c2claudeImprovements are welcome:
- Fork it
- Create a feature branch
- Submit a PR
Built for personal use, released in case others find it useful. Not affiliated with Anthropic.
Tip: Bind c2claude to a shell alias or keyboard shortcut for maximum laziness.
