One Brain, Two Wallets: Two Claude Code Accounts on One Machine

작성자

카테고리:

← 피드로
DEV Community · Daksh Gargas · 2026-07-21 개발(SW)

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 <(jq '.mcpServers' ~/.claude.json) \
   '.mcpServers = $mcp[0]' ~/.claude-personal/.claude.json \
   > /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 <config-dir>/projects/<project>/<session-id>.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 <id> 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 <session-id> — continue a work session as personal
set -euo pipefail
id=${1:?usage: claude-pickup <session-id>}
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.

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다