If you use Claude Code with more than one account — personal and work, or one per client — you know the dance: log out, log back in, forget which account you’re on, and burn the wrong subscription’s usage on a client project. I did that dance for months as a solo consultant juggling per-client accounts before accepting it was a tooling problem, not a discipline problem.
This post covers both fixes: the manual one built into Claude Code, and csm, the open-source session manager I built to automate it.
Why switching Claude Code accounts is painful
Claude Code keeps exactly one login. Credentials, settings, and session history all live in ~/.claude, and there’s one of it. Running /login for a different account replaces the current one, and nothing in your prompt tells you which account you’re on. So the failure mode isn’t hypothetical: you finish a personal experiment at midnight, open a client project the next morning, and spend the day burning your personal plan’s usage — or worse, the client’s.
What you actually want is what nvm gave us for Node versions a decade ago: log in once per account, pin each project to one, and never think about it again.
The manual fix: CLAUDE_CONFIG_DIR
Claude Code officially supports the CLAUDE_CONFIG_DIR environment variable, which tells it where to keep its config. Point it somewhere else and you get a second, fully isolated login:
CLAUDE_CONFIG_DIR=~/claude-work claude # log in once with the work account
CLAUDE_CONFIG_DIR=~/claude-work claude # every later run: work account
claude # plain command: your original login
That’s the whole trick — every “account” is just a folder. No credential-file editing, no keychain surgery, no third-party service holding your tokens.
The problem is ergonomics. You have to remember the right export in every terminal, every tmux pane, every SSH session. Forget once and you’re back to burning the wrong subscription. The environment variable is the mechanism; what’s missing is something that picks the right value per project, automatically.
csm: pin an account per project, like nvm
csm (Claude Session Manager) is that missing piece. It works the way nvm and fvm work for runtime versions:
csm login personal # log in once per account
csm login client-acme
cd ~/projects/acme-app
csm use client-acme # writes .csmrc — this folder is now pinned
claude # just works — runs as client-acme, here and in subfolders
Each account gets its own config directory under ~/.csm/accounts/<name>/, and a small shell wrapper resolves which one applies whenever you run claude:
$CSM_ACCOUNT, if set — for one-off overrides- the nearest
.csmrcfile, walking up from the current directory (exactly like.nvmrc) - the global default, set with
csm global <name>
The .csmrc file is plain text containing an account name. Commit it if your teammates should use the same account name; gitignore it if the name itself is sensitive — a client’s name, say. csm current tells you which account applies here and why, and csm exec <name> runs a one-off command as any account without changing pins.
Two design constraints I held onto throughout:
- csm never touches
~/.claude. Your existing login keeps working in any directory with no pin. Uninstall csm and everything is exactly as before. - csm never reads or transmits credentials. Claude Code manages its own login normally inside each directory; csm only decides which directory is active. The whole tool is 356 lines of bash — short enough to audit over coffee, which is my bar for anything that sits near credentials.
The failure mode I didn’t expect: idle accounts log themselves out
The most useful feature came from a problem I only hit after multiple accounts worked. Claude Code’s OAuth tokens are short-lived — roughly eight hours — and an account you haven’t used in a few days can miss its refresh window entirely. It then fails silently until the moment you need it, usually mid-flow, forcing a full re-login.
csm keepalive fixes this by sending a trivial claude --print "ok" through every account — one tiny prompt per account, at most once a day — exercising each refresh token and reporting which accounts have genuinely gone stale. It runs automatically from the shell integration, in the background, piggybacking on real usage. For days you don’t open a terminal, there’s a launchd agent for macOS (which catches up after sleep, unlike cron) and a systemd user timer for Linux.
One honest gap: if the machine is fully off for an extended period, nothing local can run. An always-on host is the only real fix for that, and it isn’t built yet.
Installing csm
Homebrew on macOS or Linux (via the imadrashid/tap):
brew install imadrashid/tap/csm
Or the install script:
curl -fsSL https://raw.githubusercontent.com/ImadRashid/claude-session-manager/main/install.sh | bash
Then enable the shell integration and check the install:
echo 'eval "$(csm shell)"' >> ~/.zshrc # or ~/.bashrc
csm doctor
It supports macOS and Linux, bash and zsh — including macOS’s stock bash 3.2 — with no dependencies beyond curl. Windows works via WSL. There’s a dependency-free test suite, CI on both platforms, and csm upgrade for updates. MIT-licensed, with the caveat that it’s an independent community tool, not affiliated with or endorsed by Anthropic.
FAQ
Can you use multiple accounts with Claude Code? Yes — via the officially supported CLAUDE_CONFIG_DIR environment variable, one isolated config directory per account. csm automates picking the right directory per project.
Will this break my existing Claude Code login? No. csm never touches ~/.claude; plain claude keeps working exactly as before in unpinned directories.
Is it safe? csm never reads or transmits credentials — each account is a folder Claude Code itself manages through its normal login flow. The source is short enough to read in one sitting.
Why does Claude Code keep logging me out of idle accounts? Short-lived OAuth tokens (~8h) miss their refresh window when an account sits idle. csm keepalive exercises every account’s refresh token daily so they stay logged in.
Does it work in VS Code or JetBrains? Not automatically — extensions don’t inherit shell functions. Set CLAUDE_CONFIG_DIR in the workspace’s terminal environment, pointed at $(csm which <name>).
Does it work on Windows? Via WSL, yes. Native Windows is untested.
If you’re juggling one Claude account per client like I am, this removes an entire category of “wait, which account am I on?” from your week. The code, issues, and PRs live on GitHub — if csm saves you the login dance, a star on the repo helps other people find it. And if you’re curious how the rest of my tooling fits together, there’s a full breakdown on the stack page.