-
Notifications
You must be signed in to change notification settings - Fork 5
Accounts
Two Claude subscriptions - a work Max and a personal Pro, say - normally mean
/logout, a browser round-trip and a minute lost every time you move between
them. Claude Code has no account switcher of its own
(#35856). This one
saves each login under a name and switches in place:
claude-account save PRO # the login you are on now
claude auth login # sign in to the other account, once
claude-account save PERSO
claude-account use PRO # from now on: no browser, no logoutEvery client shows the same thing: the GNOME dropdown and the macOS menu list
the saved accounts with each one's usage and switch on a click, the status line
tags the session with its account ([PRO]), and the MCP tool grows
list_accounts / save_account / switch_account so you can say "switch me
to PERSO" in the conversation.
./install.sh accounts puts claude-account on your PATH (~/.local/bin).
The desktop panels and the MCP server need nothing extra: the same module is
installed alongside them by ./install.sh statusline / mcp, and the GNOME
extension and the macOS app carry their own port of it.
Off by default in the panels. Nothing account-related is drawn until you
turn on Enable named accounts in the GNOME preferences or the macOS Settings
(Accounts section); the status line shows its [PRO] tag only with
--segments=…,account. The CLI and the MCP tools work regardless.
A Claude Code login is exactly two things:
| What | Where (Linux) | Where (macOS) |
|---|---|---|
| The OAuth tokens | ~/.claude/.credentials.json |
login Keychain item Claude Code-credentials
|
Who the account is (oauthAccount: email, organization, tier) |
~/.claude.json |
~/.claude.json |
use NAME swaps those two and nothing else - settings, hooks, plugins, MCP
servers, project history all stay. Both paths follow CLAUDE_CONFIG_DIR when
it is set. In order:
- The login you are leaving is written back into its own saved profile. Claude
Code rotates its tokens as it runs, so the copy taken at
savetime would otherwise die with its old refresh token. A login that was never saved is parked under a name derived from its email rather than lost. - The target's access token is refreshed first if it is stale (see below). A refresh that fails leaves your current login untouched.
- The target's tokens and
oauthAccountblock are installed.
Claude Code sessions already running keep the old login until they restart;
use tells you how many there are. New sessions, the panels and the MCP tool
see the new account immediately.
One file per account, mode 0600, in a 0700 directory:
- Linux:
${XDG_STATE_HOME:-~/.local/state}/claude-usage-panel/accounts/NAME.json - macOS:
~/Library/Application Support/claude-usage-panel/accounts/NAME.json
Names are one path segment: letters, digits, . _ -, up to 32 characters,
no leading dot or dash. remove NAME forgets one; --uninstall accounts keeps
them (delete the folder yourself).
An access token lives about eight hours. Claude Code refreshes the login it is
on; nobody refreshes the ones it is not on. So when a saved account is needed -
to read its usage for the dropdown, or to switch to it - and its access token
is within five minutes of expiry, the panel exchanges that account's refresh
token for a new pair against Claude Code's own OAuth client
(platform.claude.com/v1/oauth/token, grant_type=refresh_token) and stores
the result in its own profile file only. The live login is never refreshed
by the panel: that stays Claude Code's job, exactly as before.
A refresh token lasts about thirty days. A saved account left untouched longer
than that reads login expired everywhere; sign in to it once with
claude auth login and save it again.
Off by default. When it is on (the toggle sits in the dropdown / menu, next to
the accounts, and in the preferences), each poll checks whether the active
account has crossed the threshold (90%, adjustable 50-100) on any limit. If
another saved account has usage at least 15 points under the threshold, the
panel switches to the one with the most headroom, notifies you (Switched PRO → PERSO: PRO was at 92% - 2 running sessions keep the old login until restarted) and re-polls as the new account. Never twice within five minutes,
never to an account it has no usage for, never when the current login is not a
saved one. The same rule, from the same shared fixture, drives the status
line's hint: [PRO ⇢ PERSO] in yellow means this session is at the threshold
and PERSO has room - it does not switch by itself; the status line has no
credentials.
claude-account list [--usage] [--json] saved accounts, the active one marked
claude-account current [--json] the active account's name (exit 1 if unsaved)
claude-account save NAME [--force] save the current login as NAME
claude-account use NAME [--json] make NAME the current login
claude-account remove NAME forget a saved account
claude-account refresh [NAME] refresh the stored token(s) now
save refuses a name that already belongs to a different account, and refuses
to save an account that is already saved under another name; --force
overrides both. list --usage reads every account's limits (refreshing where
needed) and writes the snapshot the status line reads.
claude-code/accounts.js is the implementation behind the CLI, the MCP server
and the status line. The GNOME extension (lib/pure.js + lib/accounts.js)
and the macOS app (ClaudeUsageCore/Accounts.swift + AccountStore.swift)
mirror it; tests/fixtures/accounts.json pins the decisions they must agree on
(what a valid profile is, which saved account the live login is, when a token
is valid / stale / expired, and the auto-switch rule). The usage snapshot the
panels write for the status line is one small JSON file next to the profiles.