One Mac, Two Claude Code Accounts (and the Right One Picks Itself)
For a long time, I had just one Claude account, and I used it for everything, work and personal projects alike. That changed recently when work moved to a team account. Suddenly I had two accounts to deal with: a work one and a personal one, both on the same machine.
Here's the catch: Claude Code keeps one login at a time under ~/.claude. So switching from work to a personal side project meant a /logout followed by a /login, every time. Nothing gets deleted when you do this; your sessions and settings stay on disk, but only one account can be active at any moment, and both accounts end up sharing the same directory. So the switching gets old fast, and work and personal history just pile into the same place with no separation between them.
I wanted both accounts usable on one computer, seamlessly, without the login and logout dance.
While looking for a way to do this, I found a FrontendHire walkthrough on running multiple Claude accounts. I liked the core idea a lot, and it's what got me started. But it still meant I had to run claude-work or claude-personal myself, and I wanted something more automatic than that. I wanted the setup to make the choice for me.
The one variable that makes it possible
Claude Code keeps everything for an account (the login, history, projects, and settings) tied to a single config directory. And you can change which directory it uses with one environment variable: CLAUDE_CONFIG_DIR.
Point it somewhere else, and Claude Code happily reads and writes there instead:
- Separate credentials, so each account stays logged in independently
- Separate history, so work and personal conversations never mix
- Separate
projects/,sessions/, andsettings.json
Two directories, two fully isolated accounts, one machine. No more logging out to switch.
So the plan is simple:
~/.claude-workfor the work account~/.claude-personalfor the personal account
Bringing my existing sessions along
I was already logged in under the default ~/.claude, and I wanted to keep that history and project memory with my work account. So before setting anything up, I copied it over:
$ cp -R ~/.claude ~/.claude-workAll my sessions, projects, and settings came right along.
But when I checked the auth status, it complained about a missing config file. Small gotcha: the main config file isn't inside ~/.claude/, it lives one level up in your home directory as ~/.claude.json (a sibling, not a child). So cp -R never touched it. One more copy fixed it:
$ cp ~/.claude.json ~/.claude-work/.claude.jsonThe macOS Keychain nuance
Here's a detail worth knowing, especially on a Mac. On macOS, the login itself isn't stored in the config folder at all; it lives in the encrypted Keychain. On Linux and Windows it sits in a .credentials.json file inside the directory, but macOS keeps it in the Keychain.
What this means in practice: copying the folder brings over your sessions and settings, but not your login. That's not a problem. Each CLAUDE_CONFIG_DIR gets its own Keychain entry, so you just run /login once per account and they stay isolated from then on.
The aliases (the starting point)
The straightforward way to wire this up is two shell aliases. In ~/.zshrc:
alias claude-personal="CLAUDE_CONFIG_DIR=~/.claude-personal claude"
alias claude-work="CLAUDE_CONFIG_DIR=~/.claude-work claude"Reload the shell, launch each once, and /login with the matching account:
$ source ~/.zshrc
$ claude-work # then /login with your work account
$ claude-personal # then /login with your personal accountAfter that, each alias remembers its own login, and the logout-and-login loop is gone.
This already works well. But it still leaves the choice up to me every time, and picking the wrong alias is an easy mistake to make. Starting a work session inside a directory meant for my personal account (or the other way round) is exactly what I wanted to rule out. So I kept going.
The part that made this possible: how my projects are organised
Before the automatic setup, one thing deserves credit, because without it none of this would work: I keep my projects organised in a strict, predictable directory structure on my machine.
That structure is what lets a tool look at where you are and infer which identity you want. It's the same reason my multi-profile git setup has worked seamlessly for years. My ~/.gitconfig uses conditional includes so my commit identity changes automatically based on which directory I'm in:
[includeIf "gitdir:~/DEV/personal/"]
path = ~/.gitconfig-personal
[includeIf "gitdir:~/DEV/opensource/"]
path = ~/.gitconfig-opensourceIf my projects were scattered around the filesystem with no pattern, even that git setup would have been very difficult, if not impossible. The directory layout is the foundation. Everything else is just reading it.
That git setup has been quietly doing its job for years, and it's exactly the experience I wanted for Claude Code.
Making the right account pick itself
Claude Code doesn't have a built-in equivalent of git's includeIf. But a small shell function does the job nicely. The goal: default to work everywhere, and automatically switch to personal inside my personal project folders.
Instead of hardcoding paths in ~/.zshrc, I kept the mapping in a small JSON file at ~/.claude-code-multi-account-config.json:
{
"default": "work",
"accounts": {
"work": "~/.claude-work",
"personal": "~/.claude-personal"
},
"rules": [
{ "prefix": "~/DEV/personal", "account": "personal" },
{ "prefix": "~/DEV/opensource", "account": "personal" }
]
}default is what applies when nothing matches (work, in my case), and each rule maps a directory prefix to an account.
Quick setup on macOS
This uses jq, a tiny command-line JSON processor, to read the config. Most dev Macs already have it; if not:
$ brew install jqThen drop this function into ~/.zshrc. If you already added the two plain aliases from the previous step, remove those first so they don't clash, since this block redefines them:
# --- Claude Code: directory-aware account selection ---
claude() {
local cfg="$HOME/.claude-code-multi-account-config.json"
local config_dir="${CLAUDE_CONFIG_DIR:-}" # explicit override wins
if [[ -z "$config_dir" ]]; then
if [[ -r "$cfg" ]] && command -v jq >/dev/null 2>&1; then
config_dir="$(
jq -r --arg pwd "$PWD/" --arg home "$HOME" '
([ .rules[]
| (.prefix | sub("^~"; $home)) + "/" as $p
| select($pwd | startswith($p))
| .account ] | first) as $matched
| ($matched // .default) as $account
| .accounts[$account]
' "$cfg"
)"
config_dir="${config_dir/#\~/$HOME}" # expand leading ~
fi
[[ -z "$config_dir" || "$config_dir" == "null" ]] && config_dir="$HOME/.claude-work"
fi
CLAUDE_CONFIG_DIR="$config_dir" command claude "$@"
}
# manual overrides, still handy
alias claude-personal="CLAUDE_CONFIG_DIR=~/.claude-personal claude"
alias claude-work="CLAUDE_CONFIG_DIR=~/.claude-work claude"A couple of things worth knowing about that function:
command claudeis what stops the function from calling itself. It skips the function and runs the real binary.- The
VAR=val command ...prefix scopesCLAUDE_CONFIG_DIRto that one launch, so it never leaks into the rest of your shell. - If
CLAUDE_CONFIG_DIRis already set (for example, from those manual aliases), it wins, so you always have an escape hatch.
Reload and test both branches:
$ source ~/.zshrc
$ cd ~/DEV/personal && claude # personal
$ cd ~ && claude # work (default)Run /status inside each session to confirm the right account picked up. The first time you land in a personal folder, remember to /login once, since that config directory is still empty.
Why I like it
- The right account is always chosen for me. No thinking, and no risk of starting a session with the wrong account in the wrong directory.
- Work is the safe default. Everywhere except my personal folders, it's work, which is exactly what I want on a work Mac.
- The mapping lives in data, not code. I only touch the JSON file when I want to add a new group of paths.
- Nothing mixes. Credentials, history, and project memory stay in their own lanes.
One honest difference from git: includeIf re-checks on every git command, while this decides once, at the moment you launch claude, based on where you are. That's a fair trade for how I actually work, and the manual aliases are always there when I want to force a specific account.
That's the whole trick: one environment variable, a small function, and a JSON file that maps folders to accounts, all resting on a directory structure that was already there. Two accounts on one Mac, no logging out, and the correct one just shows up.
References
- Claude Code, Credential management: Anthropic's docs on where credentials live and how
CLAUDE_CONFIG_DIRrelocate them. - Using Multiple Claude Accounts in Claude Code: the FrontendHire walkthrough that got me started on the two-directory approach.