Skip to content

Instantly share code, notes, and snippets.

@weslien
Created February 10, 2026 12:09
Show Gist options
  • Select an option

  • Save weslien/70af6c7b5e8a595b8b35af11fbef1702 to your computer and use it in GitHub Desktop.

Select an option

Save weslien/70af6c7b5e8a595b8b35af11fbef1702 to your computer and use it in GitHub Desktop.
Keep 2 different claude code accounts using aliases and symlinks
#!/usr/bin/env bash
#
# multi-claude-setup.sh
#
# Helper script to run multiple Claude Code accounts (e.g. work + personal)
# on macOS with zsh, using:
# - one config directory per account
# - a shared ~/.claude for non-secret data
# - per-account .claude.json (tokens/session) kept separate
#
# Usage:
# chmod +x multi-claude-setup.sh
# ./multi-claude-setup.sh
#
# After running:
# - `claude-w` will start Claude Code with your "work" account
# - `claude-p` will start Claude Code with your "personal" account
#
# Then:
# 1) Run `claude-w` once, log in with work credentials in the browser.
# 2) Run `claude-p` once, log in with personal credentials.
#
# Inspired by community patterns for multi-account config dirs. [web:4][web:6][web:11]
set -euo pipefail
# ---- CONFIG ----
BASE="${HOME}/.claude" # canonical/shared directory
WORK="${HOME}/.claude-work" # work account config dir
PERSONAL="${HOME}/.claude-personal" # personal account config dir
ZSHRC="${HOME}/.zshrc"
# Files/dirs we will NOT symlink (account-specific)
# .claude.json is where Claude stores per-account session / MCP state.[web:12][web:40]
EXCLUDE_REGEX='^\.?\.$|^\.claude\.json'
# ---- FUNCTIONS ----
make_dir_if_missing() {
local dir="$1"
if [ ! -d "$dir" ]; then
echo "Creating directory: $dir"
mkdir -p "$dir"
fi
}
link_shared_items() {
local target_dir="$1"
echo
echo "Linking shared items into: $target_dir"
cd "$target_dir"
# Iterate all items in BASE (including dotfiles) except . and .. and .claude.json* [web:46][web:47]
# We use 'ls -A' to include dotfiles but skip . and ...
for item in $(ls -A "${BASE}"); do
if echo "$item" | grep -Eq "$EXCLUDE_REGEX"; then
# Skip files we know should remain per-account
continue
fi
# If something already exists, leave it alone
if [ -e "$item" ] || [ -L "$item" ]; then
continue
fi
echo " ln -s ${BASE}/${item} -> ${target_dir}/${item}"
ln -s "${BASE}/${item}" "${item}"
done
}
ensure_alias() {
local alias_name="$1"
local alias_value="$2"
if grep -Fq "$alias_name" "$ZSHRC"; then
echo "Alias '$alias_name' already present in ${ZSHRC}, skipping."
else
echo "Adding alias '$alias_name' to ${ZSHRC}"
{
echo ""
echo "# Claude Code multi-account alias: ${alias_name}"
echo "alias ${alias_name}='CLAUDE_CONFIG_DIR=\"${alias_value}\" claude'"
} >> "$ZSHRC"
fi
}
# ---- MAIN ----
echo "=== Claude Code multi-account setup (work + personal) ==="
# Ensure base shared dir exists
make_dir_if_missing "$BASE"
# Ensure work/personal dirs exist
make_dir_if_missing "$WORK"
make_dir_if_missing "$PERSONAL"
# Link shared content into work + personal
link_shared_items "$WORK"
link_shared_items "$PERSONAL"
# Add convenient aliases to .zshrc [web:4][web:41]
ensure_alias "claude-w" "$WORK"
ensure_alias "claude-p" "$PERSONAL"
echo
echo "Done."
echo
echo "Next steps:"
echo " 1) Restart your terminal or run: source \"$ZSHRC\""
echo " 2) Run 'claude-w' and log in with your WORK account."
echo " 3) Run 'claude-p' and log in with your PERSONAL account."
echo
echo "Notes:"
echo " - ${BASE} holds your shared settings, history, projects, etc."
echo " - ${WORK} and ${PERSONAL} keep their own .claude.json (tokens / sessions)."
echo " - If new credential files appear under ${BASE} in future releases,"
echo " move them into WORK/PERSONAL and keep them out of the shared dir.[web:22][web:29]"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment