I hit my Claude Code usage limit mid-week. I have a second subscription, but switching accounts the naive way — /logout, /login, repeat — is miserable, and it turns out "switching accounts" in Claude Code silently means switching everything: skills, MCP servers, settings, hooks, memory, session history. All of it. What I actually wanted: one brain, two wallets. Same skills, same MCP servers, same muscle memory — just a different subscription getting billed. Here's the setup that got me there. ~20 minutes, fully reversible. Step 1: Two config dirs, two aliases Claude Code keeps all its state in a config directory — ~/.claude by default — and honors a CLAUDE_CONFIG_DIR env var to point elsewhere. That's the whole trick: # ~/.zshrc # Claude Code multi-account aliases alias claude-work='CLAUDE_CONFIG_DIR=~/.claude claude' alias claude-personal='CLAUDE_CONFIG_DIR=~/.claude-personal claude' Enter fullscreen mode Exit fullscreen mode mkdir ~/.claude-personal source ~/.zshrc claude-personal # prompts OAuth login for the second account — one time Enter fullscreen mode Exit fullscreen mode Credentials land in whichever dir is active. Bare claude still defaults to ~/.claude, so nothing about your existing workflow changes. Gotcha #1: .claude.json moves when you set the env var Claude Code's user-level config file (~/.claude.json — MCP servers, folder trust, onboarding state) lives next to ~/.claude, not inside it. But when CLAUDE_CONFIG_DIR is set, it's read from inside the config dir instead. So claude-work — even though it points at the same ~/.claude you've always used — creates a fresh, empty ~/.claude/.claude.json and suddenly has zero MCP servers. Fix: symlink it to the master, since it's the same account: ln -s ~/.claude.json ~/.claude/.claude.json Enter fullscreen mode Exit fullscreen mode Now bare claude and claude-work are byte-for-byte identical. Step 2: Share the brain The second account starts as a blank slate. Since only billing should differ, symlink everything shareable from the main dir: cd ~/.claude-personal ln -s ~/.claude/skills skills ln -s ~/.claude/CLAUDE.md CLAUDE.md ln -s ~/.claude/settings.json settings.json # hooks, permissions, env ln -s ~/.claude/settings.local.json settings.local.json ln -s ~/.claude/plugins plugins Enter fullscreen mode Exit fullscreen mode One source of truth: add a skill or tweak a hook once, both accounts see it. MCP servers need more care. They live in .claude.json, which also holds the account identity (oauthAccount) — so you can't symlink the whole file across accounts. Merge just the mcpServers block: jq --slurpfile mcp /tmp/merged.json && mv /tmp/merged.json ~/.claude-personal/.claude.json Enter fullscreen mode Exit fullscreen mode Gotcha #2: --resume doesn't know about accounts Session transcripts live at /projects//.jsonl. Resume a personal session under the work account and Claude just says the session doesn't exist. Worse, anything that launches bare claude for you — crash-restore scripts, launchd jobs — always resumes against the default dir. The fix is a tiny shim earlier in $PATH than the real binary. Every session ID exists in exactly one account's tree, so ownership is the routing signal: #!/bin/bash # ~/.local/bin/claude — routes --resume to the account that owns the session REAL=/opt/homebrew/bin/claude # wherever `command -v claude` pointed before if [[ -z "$CLAUDE_CONFIG_DIR" ]]; then id="" prev="" for arg in "$@"; do if [[ $prev == "--resume" || $prev == "-r" ]]; then id=$arg; break; fi if [[ $arg == --resume=* ]]; then id=${arg#--resume=}; break; fi prev=$arg done if [[ -n $id ]] && compgen -G "$HOME/.claude-personal/projects/*/$id.jsonl" >/dev/null; then export CLAUDE_CONFIG_DIR="$HOME/.claude-personal" fi fi exec "$REAL" "$@" Enter fullscreen mode Exit fullscreen mode Now claude --resume just works, from anywhere, for either account. Explicit CLAUDE_CONFIG_DIR (your aliases) passes through untouched. Bonus: moving a conversation between wallets The whole reason I did this was running out of credits mid-conversation. Since a session is just a transcript file, "continue this work conversation on my personal account" is a copy + resume: #!/bin/bash # ~/.local/bin/claude-pickup — continue a work session as personal set -euo pipefail id=${1:?usage: claude-pickup } src=$(ls ~/.claude/projects/*/"$id".jsonl 2>/dev/null | head -1) [[ -n $src ]] || { echo "session $id not found" >&2; exit 1; } proj=$(basename "$(dirname "$src")") mkdir -p ~/.claude-personal/projects/"$proj" cp -n "$src" ~/.claude-personal/projects/"$proj"/ CLAUDE_CONFIG_DIR=~/.claude-personal exec claude --resume "$id" Enter fullscreen mode Exit fullscreen mode The work account keeps its copy as history; new turns land only in the personal copy. And since the shim checks the personal tree first, future bare claude --resume of that ID follows the conversation to its new wallet automatically. What stays separate (and should) Credentials and billing — the entire point. Session transcripts — the shim depends on separate trees. Folder trust — each account re-asks "do you trust this folder?" once per directory. Expected, answer once. OAuth'd MCP servers (Linear, Notion, …) — tokens are per config dir; run /mcp once in the new account to re-auth. CLI-based MCP servers that use machine credentials work immediately. The result claude # work (default, unchanged) claude-personal # second subscription, same brain claude --resume X # figures out the account itself claude-pickup X # mid-conversation wallet swap Enter fullscreen mode Exit fullscreen mode Same skills, same MCP servers, same hooks, same memory. The only thing that changes is who gets the bill.
One Brain, Two Wallets: Two Claude Code Accounts on One Machine
Full Article
Original Source
Read the full article at Dev →KhanList aggregates and links to publicly available news content. We do not host full articles from third-party sources. Always verify important information with original sources.