Skip to content

Repository files navigation

Switch Claude Account

Latest release Last commit License: MIT PowerShell 7.4+ GitHub Sponsors Ko-fi

A zero-dependency PowerShell utility for Claude Code on Windows, Linux, and macOS that combines secure multi-account management with a live usage dashboard and automated limit-based rotation.

sca monitor: pool-aggregate Session bar at 22% (green) and Week bar at 62% (yellow), then a five-row slot table with the active 'work' row in green, two inactive 'ok' rows, one yellow 'near limit' row, one red 'limited 7d' row, a right-aligned '▶ switching slot at 95%' header indicator, and a '[Monitor] Rotated from \

Features

Account & identity

  • Identity-aware slots: each slot's OAuth email is captured at save time, baked into the filename, and locked in a sidecar; what you see in list is guaranteed to be who the tokens actually belong to
  • Named slots with rotation: unlimited accounts under any name (filename-unsafe characters auto-sanitized); sca switch with no name cycles through them alphabetically

Live usage monitoring

  • Live plan-usage dashboard: sca usage -Watch polls Anthropic's /api/oauth/usage and renders a flicker-free, auto-refreshing view of Session (5h) and Week (7d) limits across every slot; the terminal-tab title is updated each poll so a backgrounded watch is glanceable from the taskbar / Alt-Tab
  • Transparent token refresh: expired access tokens are refreshed before usage queries and mirrored back into the active credentials file

Automation

  • Auto-reconcile: silently captures Claude Code's hourly token refreshes into the tracked slot; auto-saves cross-account swaps under a timestamped name so you never lose state
  • Smart rotation (OpenCode only): sca monitor auto-rotates to the next eligible slot when the active one hits a usage threshold (default 95%); refuses to run while Claude Code is open
  • Cold-slot warmup: sca warmup (and sca monitor -KeepWarm) opens each dormant slot's 5h window by running the real Claude Code CLI, so Anthropic reports usage data for every account (billable)

Reliability & footprint

  • Atomic-safe writes: slot-file updates use an atomic rename (MoveFileEx on Windows, rename(2) on Unix) with retry so they survive a running Claude Code on .credentials.json; save / switch still refuse to run while it's open to protect ~/.claude.json
  • Zero dependencies: pure PowerShell 7.4+, no external packages, no companion assets

Installation

Requisite

Requires PowerShell 7.4+ on Windows, Linux, or macOS. Run everything from pwsh.

Platform Install PowerShell
Windows winget install Microsoft.PowerShell
Linux Microsoft's package instructions
macOS Microsoft's package instructions

The test suite runs on all three on every push.

Download

Download latest switch_claude_account.ps1 and place it anywhere on disk.

Tip

Check the releases page for older versions.

Manual (run once)

.\switch_claude_account.ps1 install

This adds sca (short) and switch-claude-account (long) aliases to your PowerShell profile. Close and reopen your terminal to activate them.

Without alias

.\switch_claude_account.ps1 <action> [name]

Usage

Save an account

Log into an account in Claude Code, close Claude Code, then save:

sca save work
sca save personal
sca save test-project

save refuses to run while Claude Code is open and refuses to save a slot whose identity it cannot resolve from ~/.claude.json (primary) or /api/oauth/profile (fallback). There are no unlabeled-no-identity slots. To rename a slot: sca switch old-name; sca save new-name; sca remove old-name.

List saved slots

sca list

The active slot is marked with * (sourced from ~/.claude/.sca-state.json). Slots whose identity sidecar is missing or invalid are hidden from the list, from rotation, and from switch; re-running sca save <name> while that slot is active recaptures the sidecar.

Switch to a slot

sca switch work

switch refuses to run while Claude Code is open. It atomically writes the slot's bytes into .credentials.json AND restores the slot's captured oauthAccount block into ~/.claude.json so Claude Code's /status shows the matching email.

Rotate to the next slot

sca switch

Without a name, switch activates the next slot in alphabetical order and wraps from the last back to the first. The current position comes from state.active_slot.

Remove a slot

sca remove test-project

remove refuses to delete the slot tracked as currently active.

Identity capture: who is each slot actually logged in as?

Slot names are user-assigned labels; nothing stops you from naming a slot work and later overwriting it with credentials for a completely different account. At sca save time the tool pulls the OAuth email from ~/.claude.json's oauthAccount block (Claude Code's own cache) and embeds it in the slot filename:

~/.claude/.credentials.work(ada.lovelace@arpa.net).json

A paired sidecar .credentials.work(ada.lovelace@arpa.net).account.json holds the full whitelisted identity (accountUuid, emailAddress, organizationUuid, displayName, organizationName) so sca switch can restore the matching oauthAccount block to ~/.claude.json. Because the email is captured at save time and carried in both the filename and sidecar, it cannot drift from the OAuth tokens; the only way to update a slot's email label is to re-run sca save.

When the slot name already equals the OAuth email, the filename is deduplicated to .credentials.alice@example.com.json and the Account column shows .

Check plan usage

sca usage                         # one-shot table for every slot
sca usage work                    # verbose single-slot block (Session / Week, absolute reset times)
sca usage -Json                   # machine-readable per-slot output
sca usage -NoColor                # strip ANSI color (also: $env:NO_COLOR='1')

The output shows the 5-hour session limit (Session column, "Current session" in Claude Code's /usage) and the 7-day weekly all-models limit (Week column, "Current week (all models)") as percentages of each account's Claude.ai subscription:

sca usage one-shot: green pool-aggregate Session bar at 10% and Week bar at 24%, then a two-row table showing active 'work' (green) and inactive 'personal' (gray)

Decoding the output:

  • Pool-aggregate bars: sum utilization over N × 100% across every slot with numbers to show, whether read live or served from the cache after a failed read, so the bars never contradict the rows beneath them. Bar color: green <50%, yellow ≥50%, red ≥90%.
  • Active marker (*): sourced from ~/.claude/.sca-state.json; appears at the start of the row and inherits the row's color.
  • Account column: the OAuth email captured at save time. Shows when the email equals the slot name (deduped filename), the actual email otherwise.
  • Session / Week cells: <pct>% <delta>. The delta is (2h 11m) under 24h with minute precision, (102h) at 24h+ with integer hours, or when there is no data. A bucket whose window has already rolled also shows : the percentage it carried describes a window the account has left, so it is dropped rather than shown as stale.
  • Status column: one of ok, near limit (≥90%), limited 5h / limited 7d (≥100%), error (error <code> on an HTTP failure that carried one), expired, unauthorized, rate-limited, or no-oauth. Status drives the entire row's color.
  • Failure reasons: labels stay short so they cannot widen the table. Why a slot failed prints below it as [Usage] <slot>: <reason>. The block is capped at eight lines so it cannot push the table off screen in a live watch; the lines naming every affected slot and the per-status remedies (expired, unauthorized, no-oauth) are kept first, and up to three per-slot messages take whatever is left. No failed slot is left unexplained.

Drill into a single slot for absolute reset times in your local timezone:

sca usage work

sca usage work: yellow [Usage] header, dim Account line, green Status: ok, then Session and Week rows with absolute reset times in Europe/Berlin

list, switch, usage, warmup, and monitor (per poll) run a quiet reconcile pass before doing their work: if .credentials.json has changed since the last sync (Claude Code refreshed a token, or you logged into a different account inside Claude Code), the new bytes are captured into the tracked slot, or auto-saved under auto-<UTC-timestamp>(<email>).json if the email differs.

Warning

Unofficial API. sca usage calls api.anthropic.com/api/oauth/usage, the same endpoint Claude Code's /usage uses internally. Undocumented by Anthropic and may break on Claude Code upgrades; when that happens, see the extraction recipe at the top of switch_claude_account.ps1 to re-pin the constants. The endpoint is not a public API and may be changed or withdrawn at Anthropic's discretion; use accordingly.

Note

Token refresh. If a slot's access token has expired (default TTL ~1h), sca usage transparently refreshes it against platform.claude.com/v1/oauth/token and mirrors the new tokens back into both the slot file and .credentials.json via atomic rename so the active session keeps working.

Watch plan usage live

Execute sca usage -Watch to enable the live dashboard:

sca usage -Watch                  # live, self-refreshing view; Ctrl-C to quit
sca usage work -Watch             # follow a single slot
sca usage -Watch -Interval 300    # slower poll cadence (60s floor)
sca usage -Watch -NoColor         # strip ANSI color

The terminal-tab title is updated on every poll so a backgrounded watch is glanceable from the taskbar / Alt-Tab:

22% | 62% | Switch Claude Account

sca usage -Watch: pool-aggregate Session bar at 22% (green) and Week bar at 62% (yellow), then a five-row slot table with the active 'work' row in green, two inactive 'ok' rows, one yellow 'near limit' row, one red 'limited 7d' row, and a [Watch] Last poll footer

Note

The title's numbers come from the active slot (or the slot named in sca usage <name> -Watch); a non-ok row falls back to the bare brand suffix. A [~] prefix appears when a bucket is ≥90%, [!] when ≥100%. Pre-watch title is restored on Ctrl-C.

Warm up cold slots

Anthropic only reports /api/oauth/usage data for slots that have an open server-side 5h session window, which only a real message can open. Warmup automates the manual "switch to a slot, send one message" routine across every saved slot: for each slot it switches in and runs the real Claude Code CLI (claude -p "Hi" in safe-mode on Haiku, ~$0.004/slot), then restores the slot you started on. Because it runs the actual client, it opens the window exactly like you typing a message would.

sca warmup                            # warm every slot once, print the table, exit
sca warmup slot-2                     # warm just one slot
sca monitor -KeepWarm                 # auto-rotate AND keep every slot warm for the whole watch

sca monitor -KeepWarm does more than the one-shot pass: at each poll it re-opens any slot whose 5h window has since closed, so a long session keeps every slot warm instead of letting them all expire ~5h after startup. (A 5h window can only be reopened after it closes, so a just-expired slot is re-warmed within one poll, not before.) A per-slot cooldown keeps a slot whose warm keeps failing from being retried every poll.

Both sca warmup and sca monitor -KeepWarm refuse to operate while Claude Code is running (the per-slot swap writes ~/.claude.json) and require the claude CLI to be installed and logged in. A slot whose token refresh is temporarily rate-limited is reported and skipped, not retried. -KeepWarm is the typical companion to monitor: rotation needs every peer slot reporting real data to make good decisions, which keeping them warm guarantees.

Auto-rotate on usage limit (OpenCode only)

sca monitor is a live watch that auto-rotates to the next eligible slot when the active slot's max(Session, Week) utilization hits the threshold. Rotation is what monitor is for, so it is always on (there is no -Auto flag); for a read-only live view use sca usage -Watch instead.

sca monitor                  # rotate when active slot hits 95% (default)
sca monitor -Threshold 90    # rotate earlier on either bucket
sca monitor -KeepWarm        # also keep every slot warm (billable)

Peer slots are walked in alphabetical wrap order (same direction as sca switch without a name); peers that are themselves at or above the threshold are skipped, as are peers with non-ok HTTP status. When no peer is eligible, the footer surfaces the soonest reset across all slots as a cooldown ETA: [Monitor] No free slot available! Cooling down for 1h 12m.. The mode is indicated on every frame by a right-aligned ▶ switching slot at N% header indicator plus a latched [Monitor] … footer line.

sca monitor: same five-row slot table as the watch view, with a right-aligned '▶ switching slot at 95%' header indicator and a '[Monitor] Rotated from \

Important

OpenCode-scoped feature. Requires opencode-claude-auth >= 1.5.4, which re-reads ~/.claude/.credentials.json on cache miss so a swap propagates to a running OpenCode process without restart. Claude Code itself is NOT supported: its in-memory ~/.claude.json cache would race the swap, so sca monitor refuses to start (and to rotate mid-watch) while claude is running. Close Claude Code before running sca monitor; OpenCode can keep running.

Install / uninstall alias

sca install      # Add aliases to your PowerShell profile
sca uninstall    # Remove aliases from your PowerShell profile
sca help         # Show usage info

Workflow

Saving accounts

  1. Open Claude Code and log in with your first account
  2. Close Claude Code
  3. Run sca save work
  4. Open Claude Code, log out, log in with a different account
  5. Close Claude Code
  6. Run sca save personal

If Claude Code is running when you invoke save or switch, the action exits immediately with a clear message; no partial writes occur. One install shape escapes that check, see Why close Claude Code first?.

Switching between accounts

  1. Close Claude Code
  2. Run sca switch work
  3. Open Claude Code: it now uses the work credentials and /status shows the matching email

Why close Claude Code first?

sca save and sca switch read and write ~/.claude.json's oauthAccount block. Claude Code keeps that block in an in-memory cache that may flush back and clobber the update. Closing the app eliminates the race. (Slot-file updates done by sca usage's token refresh use MoveFileEx with retry, so they survive an open Claude Code on .credentials.json itself; but the ~/.claude.json cache race means you still need to close it for the two write actions.)

Important

The guard does not catch every install shape. Claude Code installed from npm (@anthropic-ai/claude-code) runs as a node process rather than one named claude, so sca has to recognise it from the process command line instead. That works on Linux. It does not work on Windows, where reading command lines costs ~53 s and a guard on every write cannot spend that, nor on macOS, where PowerShell does not expose process command lines at all. On those two platforms, close Claude Code yourself rather than relying on the refusal. Claude Code from the native installer is detected on all three.

Platform Notes

File locations and CLAUDE_CONFIG_DIR

Credentials, slot files, and the state file live in ~/.claude/ (%USERPROFILE%\.claude\ on Windows), except that Claude Code's own config is ~/.claude.json, a sibling of that directory rather than a file inside it.

Setting CLAUDE_CONFIG_DIR moves the whole tree, including .claude.json, and sca follows it. A leading ~ is not expanded, matching what Claude Code itself does; a relative value resolves against the directory you run the command in, and is resolved once at startup so every read and write in that run lands in the same place. If the relocation leaves saved slots behind in the default directory, sca prints one line naming the directory in use and counting what is being skipped; with nothing stranded it stays silent, because the variable is a permanent setting and a line on every invocation would only teach you to ignore it.

The home directory itself comes from %USERPROFILE% / $HOME when set, and otherwise from the account database, the same fallback Claude Code uses. sca works in a container or systemd unit started without those variables.

File permissions (Linux and macOS)

Every file sca writes is created 0600 before being moved into place, matching what Claude Code does. This includes .credentials.json, slot files, identity sidecars, the state file, and ~/.claude.json.

Credential files left readable by anything else are tightened to 0600 on the first run of any action, and sca reports how many it changed. That pass covers the files sca creates under the credentials directory; ~/.claude.json is Claude Code's and is left alone, as are symlinks.

A credentials directory sca creates for you is 0700, since slot filenames carry account email addresses. One that already exists keeps the mode it has, and on any machine where Claude Code ran before sca did, that is the usual case. sca will not re-permission another tool's directory, so if the filenames matter to you, run it yourself once:

chmod 700 ~/.claude

Name sanitization

Spaces, filename-unsafe characters (\ / : * ? " < > | and control chars), PowerShell wildcard brackets ([ ]), and parentheses (( )) are automatically replaced with _. Trailing dots are stripped. Reserved Windows device names (CON, PRN, AUX, NUL, COM1-COM9, LPT1-LPT9) are rejected.

These rules are Windows-strict on every platform by design, so a slot name yields the same filename everywhere and a ~/.claude directory copied from Linux or macOS to Windows stays usable.

  • my personalmy_personal
  • foo/barfoo_bar
  • foo[bar]foo_bar_
  • foo(bar)foo_bar_
  • foo.foo
  • CON → error (reserved device name)

Profile encoding

sca install and sca uninstall preserve your PowerShell profile's existing encoding (UTF-8 with or without BOM, UTF-16 LE/BE). ANSI-encoded profiles are treated as UTF-8 no-BOM (indistinguishable without a BOM).

State file

The active-slot tracker lives at ~/.claude/.sca-state.json; plain JSON, safe to inspect. Schema: { schema, active_slot, last_sync_hash }.

Execution policy (Windows)

If you get a security warning on first run, press Y or run once as:

Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

Testing

pwsh -NoProfile -File tests/Invoke-Tests.ps1

Pester 5 is auto-installed to CurrentUser scope on first use. PSScriptAnalyzer runs in advisory mode if installed. Each test sandboxes $env:USERPROFILE, $env:HOME, $env:CLAUDE_CONFIG_DIR and $PROFILE.CurrentUserAllHosts to Pester's $TestDrive so your real .claude directory and PowerShell profile are never touched. Exit code follows Pester: 0 on pass, non-zero on any failure.

License & Disclaimer

MIT. Copyright (c) 2026 Finn Kumkar.

Unofficial tool. Not affiliated with, endorsed by, or sponsored by Anthropic. "Claude" and "Claude Code" are trademarks of Anthropic PBC, used here descriptively. The script interacts with Anthropic's ~/.claude.json config and the undocumented /api/oauth/usage endpoint as a third-party tool; usage is subject to Anthropic's Consumer Terms of Service and Usage Policy in addition to this repo's MIT terms. Use only with Anthropic accounts you personally own; this tool does not enable sharing one account among multiple people.

Support

If sca saves you a hassle, consider supporting future work:

Support on Ko-fi

About

A zero-dependency cross-platform PowerShell script to switch between multiple Anthropic Claude accounts.

Topics

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages