ccswitch juggles Claude Code accounts from one config

ccswitch is a small bash-and-Python tool, posted to Show HN on September 4, that lets one Claude Code install keep several signed-in accounts. Switching between them rewrites two pieces of account state and nothing else, so MCP servers, plugins, skills and session history all stay in one shared ~/.claude.
The project’s README on GitHub is upfront about the cost: only one account can be active at a time, and a switch applies everywhere. If you need two accounts running at once in different terminals, the author tells you to use CLAUDE_CONFIG_DIR instead. The tool needs bash, python3 and Claude Code. Linux is supported, macOS is marked experimental, and the code is MIT-licensed.
What’s wrong with CLAUDE_CONFIG_DIR?
Claude Code keeps one signed-in account at a time. The usual workaround is to point CLAUDE_CONFIG_DIR at a different folder for each account. Claude Code then reads and writes its config there instead of the default ~/.claude. No second binary gets installed. The same process just looks in another directory, so each account ends up with its own login state, hooks, skills, MCP servers, settings and CLAUDE.md files.
That separation is exactly what the README objects to. Under the directory approach, it says, MCP servers, plugins and marketplaces, skills, agents, slash commands, session history, settings.json and CLAUDE.md “all get duplicated per account, and each copy drifts.” Guides to the directory setup describe the same problem from the other side. Copying a whole ~/.claude into every profile can drag stale MCP servers, old hooks and unrelated memory along with it. One guide’s fix is to symlink the projects folder so both accounts can --resume each other’s conversations while their credentials stay apart.
Files inside a repository are unaffected either way. .mcp.json, .claude/settings.json and CLAUDE.md load from the repo no matter which account is active.
Two files, two keys
Claude Code keeps account state in two places. ~/.claude/.credentials.json holds the OAuth access and refresh tokens. ~/.claude.json is a mixed file: it carries your sign-in identity alongside MCP servers, per-project trust decisions and other config. For each account, ccswitch stores a copy of the credentials file plus an identity.json holding just the oauthAccount and userID keys from ~/.claude.json, under ~/.config/ccswitch/accounts/<name>/.
A switch writes those two back into place and leaves every other key in ~/.claude.json alone, which is why mcpServers, projects and the rest stay shared. There is one more step that is easy to miss. Claude Code refreshes tokens during a session, so before switching away, ccswitch saves the live credential back into the account you are leaving. Skip that, and the next switch back would restore a stale token.
Other tools draw the line in different places. claude-switch saves and swaps subscription credentials with save and use, but it also snapshots and restores whole configuration profiles (settings, hooks, plugins, commands, skills). It runs on Bun, and Claude Code has to be restarted after a switch. A VS Code extension sets CLAUDE_CONFIG_DIR per window. Its “shared” account type symlinks settings.json, CLAUDE.md, agents, commands, skills and plugins back to ~/.claude and keeps only its own login. ccswitch touches the least of the three: one credentials file and two JSON keys, with everything else left on disk where it was.
Day to day there are only a few commands to learn. ccswitch login work opens Claude Code so you can run /login and then /exit. ccswitch add work captures an account you’re already signed in as, with no fresh login. After that, ccswitch personal (or the explicit ccswitch use personal) switches, and the next claude runs as that account. ccswitch use refuses to run while it detects a claude process, unless you pass --force. ccswitch list prints each account’s email and how long its access token has left. In the README’s sample output, a client account reads “expired 3h ago”. The rest of the set is housekeeping: current, save, rm, rename, backup and restore, a doctor that diagnoses the setup, and bash and zsh completion scripts.
Keeping parked accounts alive
Token lifetimes are where a stored account can quietly go bad. The access token lasts about eight hours, and Claude Code renews it on its own while the account is in use. Accounts parked in the vault are touched by nothing, though, and their refresh token, good for about 28 days, can lapse. When that happens, you need a full ccswitch login <name> with a browser round-trip.
ccswitch refresh --all is there to prevent that. It restores each stored account in turn, makes one tiny API call with no tools to exercise its token, saves the renewed credential back, and returns you to the account you started on. It only makes that call for accounts whose access token has actually expired, since a still-valid one means the refresh token isn’t at risk yet. A typical run does nothing at all, and the README says the call won’t burn much of an account’s session quota.
The README recommends running it daily and gives configs for both cron and a systemd user timer, plus two things that trip people up:
- Set
PATH. cron runs with a bare/usr/bin:/bin, and refresh needs bothccswitchand theclaudebinary, usually in~/.local/bin. Without it, the job dies becauseclaudewas not found on PATH. - Pick an hour you’re not working. Refresh refuses to run while a
claudeprocess is alive, so a job that fires mid-session just logs an error. A run where every account is skipped doesn’t check this and stays quiet either way.
On a laptop, the systemd timer is the better choice, because Persistent=true catches up on a run that was missed while the machine slept, where cron simply skips it. To have it run while you’re logged out, you also need sudo loginctl enable-linger $USER.
Tokens on disk, and the rules
The vault holds live session tokens. ~/.config/ccswitch is created with mode 700 and its files with mode 600, and the archive from ccswitch backup contains those tokens too. The README says to encrypt it if you keep it anywhere other than your own disk.
Moving over from per-account directories is a manual job. You unset CLAUDE_CONFIG_DIR (and remove it from your shell profile), because when it’s set, ccswitch works on that directory instead of ~/.claude, and doctor will warn about it. Then you pick the best-configured directory, make it the shared ~/.claude, and capture each remaining account. The README does this by dropping in that account’s credentials file and copying its oauthAccount and userID keys over with a short Python snippet before running ccswitch add.
Multiple accounts is a different problem from parallel work: a single account can already run many Claude Code sessions at once. A guide from AQ notes that Anthropic’s consumer terms prohibit sharing a login, and a separate guide warns against using multiple profiles to get around account or subscription rules. claude-switch, for its part, gives its motivation openly: Max usage limits reset periodically, and hitting the cap on one account is a reason to switch to another. Anthropic itself is reportedly building multi-account switching into the Claude mobile apps, per Testing Catalog. Claude Code still signs in one account at a time.
The macOS path
On macOS, Claude Code keeps the OAuth credential in the login keychain instead of ~/.claude/.credentials.json, so ccswitch reads and writes it with security(1). It derives the same item Claude Code does. The service is Claude Code-credentials, with an eight-character suffix from a SHA-256 of the config dir when CLAUDE_CONFIG_DIR is set. The account is $USER, or claude-code-user if that is unset or contains unusual characters. The first switch may trigger a keychain prompt, because macOS asks before a new binary reads an item it didn’t create.
So far, this path has been exercised against a stand-in for security(1) and not yet against a real Keychain, which is why it is labelled experimental. Windows is untested, though WSL behaves like Linux and should work. The keychain is used only when no ~/.claude/.credentials.json exists, so a file left behind by an older Claude Code still wins. To force either backend, set CCSWITCH_BACKEND=keychain or CCSWITCH_BACKEND=file.
Up next
Claude Code 2.1.261 prunes skills that eat context
Claude Code 2.1.261 shipped /skill-doctor, which names the loaded skills Claude never uses and what each one costs in context, so you can prune the ones quietly taking up room.
Related stories
- Claude’s mobile app is getting account switching
- lcc cut one Claude Code session 49.5% without a summary
- catnap keeps Claude Code from compacting mid-task
- Script checks whether your network breaks Claude API uploads
- Context-tax prices what Claude Code sends before you type
- Claude Design can draw with your real components
Comments
No comments yet. Be the first.
Join the conversation
Sign in to leave a comment. It appears after moderation.

