I use more than one Claude subscription. Most of the reason is usage: when one account runs low on its limits, I want to keep working on another. Claude Code normally has one login, so moving to another account means signing out and signing back in through the browser each time.

/claude-account is a command in my fork of pi-claude-bridge, the pi extension that runs Claude models through Claude Code's Agent SDK. It keeps several Claude accounts signed in at once and lets each pi session choose which one it uses. The account is a setting on the session, separate from the model, so I still pick Opus in /model and choose the account on its own.

Accounts are config directories

Claude Code keeps its login in a config directory, ~/.claude by default, and reads a different one when CLAUDE_CONFIG_DIR is set. Anthropic documents this as the way to run several accounts side by side. Each account I add gets its own directory under ~/.pi/agent/claude-bridge/accounts/, signed in once with Claude Code's normal login.

The bridge tracks the accounts in a registry file, accounts.json, which is written with mode 0600 and holds names and directory paths but no credentials:

{ "version": 1, "default": "k3v9qd",
  "accounts": [
    { "id": "launch", "name": "default",
      "configDir": null },
    { "id": "k3v9qd", "name": "work",
      "configDir": "/Users/you/.pi/agent/…/k3v9qd" }
  ] }

The login pi was started with is the launch account, with configDir: null, and nothing changes until a second account is added. Credentials stay where Claude Code puts them, which on macOS is the Keychain.

Every account has a random id, and the id is used for the directory name, for the default, and for the record of which account a session uses. macOS ties a Claude Code login's Keychain entry to the path of its config directory, so moving the directory would sign the account out. Renaming an account changes only its name, and the directory stays where it is.

Choosing the account for each Claude Code process

The bridge starts a Claude Code process for each turn, and for a few other things like compaction summaries and the usage meter. Every one of those processes gets its environment from one function:

export function accountEnv(base, account) {
  if (account.configDir === null) return base;
  const env = {
    ...base,
    CLAUDE_CONFIG_DIR: account.configDir,
  };
  for (const key of TOKEN_VARS) delete env[key];
  return env;
}

For an added account it sets CLAUDE_CONFIG_DIR and removes CLAUDE_CODE_OAUTH_TOKEN, ANTHROPIC_API_KEY, and ANTHROPIC_AUTH_TOKEN. A token in the environment takes priority over the login stored in the config directory, so leaving one in place would send every account's requests through the same login.

The launch account gets the environment unchanged instead of an explicit CLAUDE_CONFIG_DIR=~/.claude. On macOS an unset CLAUDE_CONFIG_DIR and an explicit ~/.claude are different Keychain entries, and the explicit path would read as signed out. pi's own process.env is never modified, so tools like pi's bash still see the launch login.

The account belongs to the session

Switching accounts appends a claude-bridge-account entry with the account's id to the pi session. When a session starts, resumes, or forks, the bridge applies the latest of those entries, or the default account if there isn't one. Two panes can run on two different accounts at the same time, and a resumed session comes back on the account it last used.

A switch takes effect on the next turn, and a turn already running finishes on its original account. Claude Code writes its session files under the account's config directory, and the bridge records which directory the current session was written under. When a turn starts on a different account, the directories no longer match, so the bridge builds a new Claude Code session in the new directory from pi's history. The first turn after a switch sends the full history once, because the prompt cache belongs to the account.

The accounts panel after switching the session to the work account

If an account's login has expired, the turn fails with a message naming the account and pointing at /claude-account. It doesn't fall back to another account.

Signing in

Adding an account runs claude auth login --claudeai with CLAUDE_CONFIG_DIR pointed at the new directory. This is the command-line version of Claude Code's /login, and it opens the browser on Claude's sign-in page.

The browser is usually already signed in to claude.ai as a different account than the one being added. Claude's "Switch account" button on that page loses the pending sign-in request, and after signing in with the other account nothing leads back to the waiting claude auth login. So the bridge sends the browser through claude.ai's logout page with the sign-in request attached, which signs the browser out and lands on the login page with the request still in place.

Claude Code opens the browser by running open <url>. For the login, the bridge puts a directory at the front of PATH that contains its own open script, which passes anything that isn't a sign-in URL straight to /usr/bin/open. A sign-in URL on claude.com/cai/oauth/authorize or claude.ai/oauth/authorize keeps its query string and is rewritten to go through logout first:

const path = `/oauth/authorize?${match[1]}`;
return `https://claude.ai/logout?returnTo=${
  encodeURIComponent(path)}`;

It also removes BROWSER from the environment, since Claude Code would otherwise use that and skip open. From there I enter the account's email, click the link in the email, and click Authorize, with nothing to copy or paste. When claude auth login exits, the bridge runs claude auth status --json against the directory to get the email and plan.

The accounts panel waiting for the browser sign-in

The login runs in its own process group, so cancelling kills everything it started. Killing only the parent process would leave claude auth login running and holding its callback port. Adding an account signs the browser out of claude.ai, and this is supported on macOS only.

The panel and commands

A bare /claude-account opens a panel that lists each account with its email and plan, marks the account this session uses and the default for new sessions, and ends with an + Add account row. Enter switches the session to the selected account, d makes it the default, r renames it, and x removes it after a confirmation, which signs the account out and deletes its directory. The launch account can be renamed but not removed, since removing it would sign plain claude out as well.

The accounts panel listing three accounts

The same actions are available as subcommands for scripts and headless sessions:

/claude-account <name>
/claude-account add <name>
/claude-account default <name>
/claude-account list
/claude-account remove <name>

While a bridge model is active, pi's footer shows claude: <name>, and the usage meter reports the active account's limits.

Source

The fork is at schuettc/pi-claude-bridge and installs with pi install npm:@schuettc/pi-claude-bridge. It is based on elidickinson/pi-claude-bridge.