Managing Multiple Claude Code Profiles

When working with multiple Claude accounts (work, personal, client projects), you need an easy way to switch between profiles without manually changing configuration files or OAuth tokens every time.

This tutorial shows how to set up a profile switcher that handles both configuration directories and authentication tokens seamlessly.

Why Multiple Profiles?

Common use cases:

  • Work vs Personal: Separate API usage and conversation history
  • Client Projects: Different billing accounts per client
  • Team Accounts: Switch between team and personal accounts
  • Testing: Sandbox environment for experimenting

Architecture Overview

The setup consists of three components:

  1. Profile directories - Store settings, history, and tokens separately
  2. Symlink switcher - Point to the active profile
  3. Shell function - Update current session immediately
~/.claude/
├── current -> profiles/work  # Symlink to active profile
└── profiles/
    ├── work/
    │   ├── settings.json
    │   ├── history.jsonl
    │   └── token           # OAuth token
    ├── personal/
    │   ├── settings.json
    │   ├── history.jsonl
    │   └── token
    └── project-a/
        ├── settings.json
        ├── history.jsonl
        └── token

Setup Instructions

Step 1: Create Profile Structure

First, create the directory structure:

# Create profiles directory
mkdir -p ~/.claude/profiles

# Move existing config to a profile (if you have one)
if [ -d ~/.claude ] && [ ! -L ~/.claude/current ]; then
  mkdir -p ~/.claude/profiles/work
  mv ~/.claude/settings.json ~/.claude/profiles/work/ 2>/dev/null || true
  mv ~/.claude/history.jsonl ~/.claude/profiles/work/ 2>/dev/null || true
fi

# Create additional profiles
mkdir -p ~/.claude/profiles/personal
mkdir -p ~/.claude/profiles/project-a

# Create initial symlink to work profile
ln -sfn ~/.claude/profiles/work ~/.claude/current

Step 2: Store Authentication Tokens

Store your authentication tokens securely in each profile. Claude Code supports two types of tokens:

OAuth tokens (recommended for standard Claude.ai accounts):

# Work profile OAuth token
echo "sk-ant-oat01-YOUR_WORK_TOKEN_HERE" > ~/.claude/profiles/work/.oauth-token
chmod 600 ~/.claude/profiles/work/.oauth-token

# Personal profile OAuth token
echo "sk-ant-oat01-YOUR_PERSONAL_TOKEN_HERE" > ~/.claude/profiles/personal/.oauth-token
chmod 600 ~/.claude/profiles/personal/.oauth-token

API tokens (for custom endpoints or API-based authentication):

# Project A profile with API token (takes precedence over OAuth)
echo "sk-ant-api03-YOUR_API_TOKEN_HERE" > ~/.claude/profiles/project-a/.auth-token
chmod 600 ~/.claude/profiles/project-a/.auth-token

Getting OAuth tokens: Run claude setup-token for each account you want to configure.

Step 2b (Optional): Configure Custom Base URLs

If you’re using a custom Claude endpoint (e.g., enterprise deployment, proxy, or alternative API), you can configure the base URL per profile:

# Configure custom endpoint for project-a profile
echo "https://api.custom-claude.company.com" > ~/.claude/profiles/project-a/.base-url
chmod 600 ~/.claude/profiles/project-a/.base-url

This sets the ANTHROPIC_BASE_URL environment variable for that profile.

Step 3: Update Shell Configuration

Add these exports to your shell profile (~/.bashrc or ~/.zshrc):

# Claude Code configuration
export CLAUDE_CONFIG_DIR="$HOME/.claude/current"

# Load base URL if configured
if [[ -f "$HOME/.claude/current/.base-url" ]]; then
  export ANTHROPIC_BASE_URL=$(cat "$HOME/.claude/current/.base-url")
fi

# Load authentication token from current profile
# Auth token takes precedence over OAuth token
if [[ -f "$HOME/.claude/current/.auth-token" ]]; then
  export ANTHROPIC_AUTH_TOKEN=$(cat "$HOME/.claude/current/.auth-token")
elif [[ -f "$HOME/.claude/current/.oauth-token" ]]; then
  export CLAUDE_CODE_OAUTH_TOKEN=$(cat "$HOME/.claude/current/.oauth-token")
fi

This ensures:

  • CLAUDE_CONFIG_DIR points to the active profile
  • ANTHROPIC_BASE_URL is set if you’re using a custom endpoint
  • Authentication tokens are loaded automatically (API token takes precedence over OAuth)

Step 4: Create Profile Switcher Function

Add this function to your shell profile (after the exports above):

# Claude profile switcher
# Usage: switch-claude <profile-name>
switch-claude() {
  local profile="$1"

  if [[ -z "$profile" ]]; then
    echo "Usage: switch-claude <profile-name>"
    echo ""
    echo "Available profiles:"
    ls -1 "$HOME/.claude/profiles/" 2>/dev/null || echo "  (none found)"
    return 1
  fi

  # Validate profile exists
  if [[ ! -d "$HOME/.claude/profiles/$profile" ]]; then
    echo "Error: Profile '$profile' not found"
    echo ""
    echo "Available profiles:"
    ls -1 "$HOME/.claude/profiles/"
    return 1
  fi

  # Switch the symlink
  ln -sfn "$HOME/.claude/profiles/$profile" "$HOME/.claude/current"

  # Update current session
  export CLAUDE_CONFIG_DIR="$HOME/.claude/current"

  # Load base URL if configured
  if [[ -f "$HOME/.claude/current/.base-url" ]]; then
    export ANTHROPIC_BASE_URL=$(cat "$HOME/.claude/current/.base-url")
  else
    unset ANTHROPIC_BASE_URL
  fi

  # Load authentication token (auth token takes precedence)
  local token_loaded=false
  if [[ -f "$HOME/.claude/current/.auth-token" ]]; then
    export ANTHROPIC_AUTH_TOKEN=$(cat "$HOME/.claude/current/.auth-token")
    unset CLAUDE_CODE_OAUTH_TOKEN
    token_loaded=true
  elif [[ -f "$HOME/.claude/current/.oauth-token" ]]; then
    export CLAUDE_CODE_OAUTH_TOKEN=$(cat "$HOME/.claude/current/.oauth-token")
    unset ANTHROPIC_AUTH_TOKEN
    token_loaded=true
  else
    unset CLAUDE_CODE_OAUTH_TOKEN
    unset ANTHROPIC_AUTH_TOKEN
  fi

  # Display status
  echo "✓ Switched to Claude profile: $profile"
  echo "  CLAUDE_CONFIG_DIR: $CLAUDE_CONFIG_DIR"

  if [[ -n "$ANTHROPIC_BASE_URL" ]]; then
    echo "  Base URL: $ANTHROPIC_BASE_URL"
  fi

  if [[ "$token_loaded" == true ]]; then
    echo "  Token: loaded"
  else
    echo "  Warning: No token file found"
  fi
}

Step 5: Apply Changes

Reload your shell configuration:

# Reload shell config
source ~/.zshrc  # or source ~/.bashrc

Usage

Switch Profiles

# Switch to work profile
switch-claude work

# Switch to personal profile
switch-claude personal

# Switch to project-a profile
switch-claude project-a

Output example:

✓ Switched to Claude profile: work
  CLAUDE_CONFIG_DIR: /Users/username/.claude/current
  Token loaded from profile

List Available Profiles

# Show all profiles
switch-claude

Output:

Usage: switch-claude <profile-name>

Available profiles:
personal
project-a
work

Verify Current Profile

# Check which profile is active
readlink ~/.claude/current

# Check current token (first 20 chars)
echo ${CLAUDE_CODE_OAUTH_TOKEN:0:20}...

How It Works

Current Session (Immediate)

When you run switch-claude:

  1. Symlink updated: ~/.claude/current~/.claude/profiles/<profile>
  2. Environment updated: Function exports CLAUDE_CONFIG_DIR and CLAUDE_CODE_OAUTH_TOKEN
  3. Ready to use: Next claude command uses the new profile immediately

Future Sessions (Persistent)

When you open a new terminal:

  1. Shell config loads: Sources ~/.bashrc or ~/.zshrc
  2. Exports run: Sets CLAUDE_CONFIG_DIR to ~/.claude/current
  3. Token loaded: Reads token from current profile’s token file
  4. Active profile used: Symlink points to the profile you last switched to

Advanced: Per-Profile Settings

Each profile can have its own settings:

// ~/.claude/profiles/work/settings.json
{
  "alwaysThinkingEnabled": true,
  "model": "claude-sonnet-4-5-20250929",
  "verbose": false
}
// ~/.claude/profiles/personal/settings.json
{
  "alwaysThinkingEnabled": false,
  "model": "claude-3-5-haiku-20250311",
  "verbose": true
}

When you switch profiles, Claude Code automatically loads the corresponding settings.

Security Notes

Token File Permissions

Always set restrictive permissions on token and configuration files:

# Correct permissions (owner read/write only)
chmod 600 ~/.claude/profiles/*/.oauth-token 2>/dev/null || true
chmod 600 ~/.claude/profiles/*/.auth-token 2>/dev/null || true
chmod 600 ~/.claude/profiles/*/.base-url 2>/dev/null || true

# Verify permissions
ls -l ~/.claude/profiles/*/.oauth-token ~/.claude/profiles/*/.auth-token 2>/dev/null

Expected output:

-rw-------  1 username  staff  109 Oct 11 12:56 .../.oauth-token
-rw-------  1 username  staff  109 Oct 11 12:56 .../.auth-token
-rw-------  1 username  staff   38 Oct 11 12:56 .../.base-url

Git Ignore

If you store your dotfiles in git, add sensitive files to .gitignore:

# Add to ~/.gitignore or your dotfiles .gitignore
cat >> ~/.gitignore << 'EOF'
.claude/profiles/*/.oauth-token
.claude/profiles/*/.auth-token
.claude/profiles/*/.base-url
EOF

Troubleshooting

“Profile not found” Error

Issue: Profile directory doesn’t exist

Solution: Create the profile directory

mkdir -p ~/.claude/profiles/<profile-name>

Token Not Loading

Issue: Token file missing or wrong permissions

Solution: Check file exists and is readable

# Check token files exist
ls -l ~/.claude/current/.oauth-token ~/.claude/current/.auth-token 2>/dev/null

# Fix permissions if needed
chmod 600 ~/.claude/current/.oauth-token 2>/dev/null || true
chmod 600 ~/.claude/current/.auth-token 2>/dev/null || true

Wrong Profile After Restart

Issue: New terminal session uses old profile

Solution: Check symlink points to correct profile

# Verify current profile
readlink ~/.claude/current

# Re-run switch if needed
switch-claude work

Function Not Found

Issue: switch-claude: command not found

Solution: Function not loaded in shell

# Reload shell config
source ~/.zshrc  # or source ~/.bashrc

# Or add function to correct file
# Make sure function is in ~/.zshrc (for zsh) or ~/.bashrc (for bash)

Comparison: Before and After

Before (Manual Switching)

# Change config directory
export CLAUDE_CONFIG_DIR=~/.claude-work
export CLAUDE_CODE_OAUTH_TOKEN="sk-ant-oat01-WORK_TOKEN..."

# Later, switch to personal
export CLAUDE_CONFIG_DIR=~/.claude-personal
export CLAUDE_CODE_OAUTH_TOKEN="sk-ant-oat01-PERSONAL_TOKEN..."

# Have to remember to do this in every terminal
# Have to copy-paste tokens from password manager
# Easy to use wrong token with wrong config

After (Profile Switcher)

# Switch to work
switch-claude work

# Switch to personal
switch-claude personal

# All new terminals automatically use the last selected profile
# No manual token management
# Profile and token always match

Advanced: Profile-Specific Accessor Functions

While switch-claude is great for switching between profiles, you can take it further with profile-specific accessor functions that let you run commands directly with a specific profile without switching your default.

This approach is inspired by the Nix configuration pattern and is particularly useful when you need to:

  • Quickly run a one-off command with a different profile
  • Keep your current profile active while checking something in another
  • Script automated tasks that use different profiles

The Concept

Instead of just switch-claude work, you create functions like:

  • claude-work - Run claude with the work profile
  • claude-personal - Run claude with the personal profile
  • happy-work - Run happy (if installed) with the work profile

Implementation

Add this to your shell configuration (~/.bashrc or ~/.zshrc):

# List of Claude profiles to create accessor functions for
CLAUDE_PROFILES=("work" "personal" "project-a")

# Generate profile-specific accessor function
# Usage: claude-work, claude-personal, etc.
_mk_claude_profile_function() {
  local profile="$1"
  local command="$2"

  eval "${command}-${profile}() {
    local profile_dir=\"\$HOME/.claude/profiles/${profile}\"
    local oauth_token_file=\"\$profile_dir/.oauth-token\"
    local auth_token_file=\"\$profile_dir/.auth-token\"
    local base_url_file=\"\$profile_dir/.base-url\"

    # Set up environment variables
    local env_vars=(
      \"CLAUDE_CONFIG_DIR=\$profile_dir\"
    )

    # Add base URL if available
    if [[ -f \"\$base_url_file\" ]]; then
      env_vars+=(\"ANTHROPIC_BASE_URL=\$(cat \"\$base_url_file\")\")
    fi

    # Add auth token if available (takes precedence over OAuth token)
    if [[ -f \"\$auth_token_file\" ]]; then
      env_vars+=(\"ANTHROPIC_AUTH_TOKEN=\$(cat \"\$auth_token_file\")\")
    elif [[ -f \"\$oauth_token_file\" ]]; then
      env_vars+=(\"CLAUDE_CODE_OAUTH_TOKEN=\$(cat \"\$oauth_token_file\")\")
    fi

    # Execute command with profile-specific environment
    env \"\${env_vars[@]}\" ${command} \"\$@\"
  }"
}

# Generate accessor functions for all profiles
for profile in "${CLAUDE_PROFILES[@]}"; do
  _mk_claude_profile_function "$profile" "claude"
  _mk_claude_profile_function "$profile" "happy"
done

Usage Examples

# Run claude with work profile (doesn't change your default)
claude-work

# Run claude with personal profile
claude-personal

# Run happy with work profile
happy-work

# Pass additional arguments
claude-work --help
claude-personal /chat "What's the weather like?"

# Meanwhile, your default profile stays unchanged
echo $CLAUDE_CONFIG_DIR
# Still points to: ~/.claude/current

The best setup uses both the switcher and the accessor functions:

  1. Switcher (switch-claude) - Set your default profile for the session
  2. Accessors (claude-work, etc.) - Quick one-off commands with other profiles
# Complete shell configuration example
# Add this to ~/.zshrc or ~/.bashrc

# ====================================
# Claude Code Configuration
# ====================================

# Default profile location
export CLAUDE_CONFIG_DIR="$HOME/.claude/current"

# Load base URL if configured
if [[ -f "$HOME/.claude/current/.base-url" ]]; then
  export ANTHROPIC_BASE_URL=$(cat "$HOME/.claude/current/.base-url")
fi

# Load authentication token from current profile
# Auth token takes precedence over OAuth token
if [[ -f "$HOME/.claude/current/.auth-token" ]]; then
  export ANTHROPIC_AUTH_TOKEN=$(cat "$HOME/.claude/current/.auth-token")
elif [[ -f "$HOME/.claude/current/.oauth-token" ]]; then
  export CLAUDE_CODE_OAUTH_TOKEN=$(cat "$HOME/.claude/current/.oauth-token")
fi

# Profile switcher function
switch-claude() {
  local profile="$1"

  if [[ -z "$profile" ]]; then
    echo "Usage: switch-claude <profile-name>"
    echo ""
    echo "Available profiles:"
    ls -1 "$HOME/.claude/profiles/" 2>/dev/null || echo "  (none found)"
    return 1
  fi

  if [[ ! -d "$HOME/.claude/profiles/$profile" ]]; then
    echo "Error: Profile '$profile' not found"
    echo ""
    echo "Available profiles:"
    ls -1 "$HOME/.claude/profiles/"
    return 1
  fi

  ln -sfn "$HOME/.claude/profiles/$profile" "$HOME/.claude/current"
  export CLAUDE_CONFIG_DIR="$HOME/.claude/current"

  # Load base URL if configured
  if [[ -f "$HOME/.claude/current/.base-url" ]]; then
    export ANTHROPIC_BASE_URL=$(cat "$HOME/.claude/current/.base-url")
  else
    unset ANTHROPIC_BASE_URL
  fi

  # Load authentication token (auth token takes precedence)
  local token_loaded=false
  if [[ -f "$HOME/.claude/current/.auth-token" ]]; then
    export ANTHROPIC_AUTH_TOKEN=$(cat "$HOME/.claude/current/.auth-token")
    unset CLAUDE_CODE_OAUTH_TOKEN
    token_loaded=true
  elif [[ -f "$HOME/.claude/current/.oauth-token" ]]; then
    export CLAUDE_CODE_OAUTH_TOKEN=$(cat "$HOME/.claude/current/.oauth-token")
    unset ANTHROPIC_AUTH_TOKEN
    token_loaded=true
  else
    unset CLAUDE_CODE_OAUTH_TOKEN
    unset ANTHROPIC_AUTH_TOKEN
  fi

  echo "✓ Switched to Claude profile: $profile"
  [[ -n "$ANTHROPIC_BASE_URL" ]] && echo "  Base URL: $ANTHROPIC_BASE_URL"
  [[ "$token_loaded" == true ]] && echo "  Token: loaded" || echo "  Warning: No token found"
}

# List of profiles for accessor functions
CLAUDE_PROFILES=("work" "personal" "project-a")

# Generate profile-specific accessor function
_mk_claude_profile_function() {
  local profile="$1"
  local command="$2"

  eval "${command}-${profile}() {
    local profile_dir=\"\$HOME/.claude/profiles/${profile}\"
    local oauth_token_file=\"\$profile_dir/.oauth-token\"
    local auth_token_file=\"\$profile_dir/.auth-token\"
    local base_url_file=\"\$profile_dir/.base-url\"
    local env_vars=(\"CLAUDE_CONFIG_DIR=\$profile_dir\")

    # Add base URL if available
    if [[ -f \"\$base_url_file\" ]]; then
      env_vars+=(\"ANTHROPIC_BASE_URL=\$(cat \"\$base_url_file\")\")
    fi

    # Add auth token if available (takes precedence over OAuth token)
    if [[ -f \"\$auth_token_file\" ]]; then
      env_vars+=(\"ANTHROPIC_AUTH_TOKEN=\$(cat \"\$auth_token_file\")\")
    elif [[ -f \"\$oauth_token_file\" ]]; then
      env_vars+=(\"CLAUDE_CODE_OAUTH_TOKEN=\$(cat \"\$oauth_token_file\")\")
    fi

    env \"\${env_vars[@]}\" ${command} \"\$@\"
  }"
}

# Generate accessor functions for all profiles
for profile in "${CLAUDE_PROFILES[@]}"; do
  _mk_claude_profile_function "$profile" "claude"
  _mk_claude_profile_function "$profile" "happy"
done

# Clean up helper function
unset -f _mk_claude_profile_function

Adding New Profiles

To add a new profile to the accessor functions:

  1. Add the profile name to the CLAUDE_PROFILES array:

    CLAUDE_PROFILES=("work" "personal" "project-a" "new-client")
    
  2. Create the profile directory:

    mkdir -p ~/.claude/profiles/new-client
    
  3. Add the token:

    # For OAuth token (standard accounts)
    echo "sk-ant-oat01-YOUR_TOKEN" > ~/.claude/profiles/new-client/.oauth-token
    chmod 600 ~/.claude/profiles/new-client/.oauth-token
    
    # OR for API token (custom endpoints)
    echo "sk-ant-api03-YOUR_TOKEN" > ~/.claude/profiles/new-client/.auth-token
    chmod 600 ~/.claude/profiles/new-client/.auth-token
    
    # Optionally configure custom base URL
    echo "https://api.custom.com" > ~/.claude/profiles/new-client/.base-url
    chmod 600 ~/.claude/profiles/new-client/.base-url
    
  4. Reload your shell:

    source ~/.zshrc  # or source ~/.bashrc
    
  5. Use the new accessor:

    claude-new-client
    

Benefits of Profile Accessors

No context switching - Keep working in one profile while checking another ✅ Scripting friendly - Easy to automate tasks across multiple profiles ✅ Explicit profile selection - Clear which profile you’re using ✅ Parallel usage - Open multiple terminals with different profiles simultaneously ✅ No side effects - Doesn’t change your default CLAUDE_CONFIG_DIR

Real-World Workflow Example

# Morning: Switch to work profile for the day
switch-claude work

# Work on project all morning
claude
# (uses work profile)

# Lunch break: Quick check on personal project
# Don't want to switch default profile
claude-personal /chat "Show me the latest commit in my blog repo"

# Back to work (still on work profile)
claude
# (still uses work profile)

# Evening: Switch to personal for the rest of the day
switch-claude personal

# Meanwhile in scripts: Always use specific profiles
#!/bin/bash
# backup-all-conversations.sh
claude-work /history export work-history.json
claude-personal /history export personal-history.json
claude-project-a /history export project-a-history.json

Alternative: Custom Profile Location

If you prefer a different base directory (like /dt/claude/profiles/), just update the paths:

# Use /dt/claude instead of ~/.claude
CLAUDE_BASE="/dt/claude"
export CLAUDE_CONFIG_DIR="$CLAUDE_BASE/current"

# Update profile accessor to use custom base
_mk_claude_profile_function() {
  local profile="$1"
  local command="$2"

  eval "${command}-${profile}() {
    local profile_dir=\"$CLAUDE_BASE/profiles/${profile}\"
    local oauth_token_file=\"\$profile_dir/.oauth-token\"
    local auth_token_file=\"\$profile_dir/.auth-token\"
    local base_url_file=\"\$profile_dir/.base-url\"
    local env_vars=(\"CLAUDE_CONFIG_DIR=\$profile_dir\")

    # Add base URL if available
    if [[ -f \"\$base_url_file\" ]]; then
      env_vars+=(\"ANTHROPIC_BASE_URL=\$(cat \"\$base_url_file\")\")
    fi

    # Add auth token if available (takes precedence over OAuth token)
    if [[ -f \"\$auth_token_file\" ]]; then
      env_vars+=(\"ANTHROPIC_AUTH_TOKEN=\$(cat \"\$auth_token_file\")\")
    elif [[ -f \"\$oauth_token_file\" ]]; then
      env_vars+=(\"CLAUDE_CODE_OAUTH_TOKEN=\$(cat \"\$oauth_token_file\")\")
    fi

    env \"\${env_vars[@]}\" ${command} \"\$@\"
  }"
}

Integration with Other Tools

Tmux Session Names

Automatically show current profile in tmux:

# Add to ~/.tmux.conf
set -g status-right "Claude: #(readlink ~/.claude/current | xargs basename)"

Shell Prompt

Show current profile in your prompt:

# Add to ~/.zshrc (for zsh with oh-my-zsh)
claude_profile() {
  local profile=$(readlink ~/.claude/current 2>/dev/null | xargs basename)
  if [[ -n "$profile" ]]; then
    echo "claude:$profile"
  fi
}

# Add $(claude_profile) to your PROMPT variable

Starship Prompt

Add to ~/.config/starship.toml:

[custom.claude_profile]
command = "readlink ~/.claude/current 2>/dev/null | xargs basename"
when = "test -L ~/.claude/current"
format = "[$output]($style) "
style = "bold blue"

Summary

The profile switcher provides:

Instant switching - No manual file editing ✅ Persistent profiles - Survives terminal restarts ✅ Secure tokens - Stored with proper permissions ✅ Isolated history - Separate conversation history per profile ✅ Per-profile settings - Different configurations per account ✅ Simple usage - One command to switch everything

Complete Setup Script

Copy-paste this entire script to set up everything:

#!/usr/bin/env bash
set -e

echo "Setting up Claude Code profile switcher..."

# Create profile structure
mkdir -p ~/.claude/profiles/{work,personal,project-a}

# Move existing config if present
if [ -f ~/.claude/settings.json ] && [ ! -d ~/.claude/profiles/work/settings.json ]; then
  mv ~/.claude/settings.json ~/.claude/profiles/work/settings.json 2>/dev/null || true
fi
if [ -f ~/.claude/history.jsonl ]; then
  mv ~/.claude/history.jsonl ~/.claude/profiles/work/history.jsonl 2>/dev/null || true
fi

# Create current symlink
ln -sfn ~/.claude/profiles/work ~/.claude/current

# Detect shell config file
SHELL_CONFIG="$HOME/.bashrc"
if [[ "$SHELL" == *"zsh"* ]]; then
  SHELL_CONFIG="$HOME/.zshrc"
fi

# Add configuration if not already present
if ! grep -q "CLAUDE_CONFIG_DIR" "$SHELL_CONFIG"; then
  cat >> "$SHELL_CONFIG" << 'EOF'

# Claude Code Profile Switcher
export CLAUDE_CONFIG_DIR="$HOME/.claude/current"

# Load base URL if configured
if [[ -f "$HOME/.claude/current/.base-url" ]]; then
  export ANTHROPIC_BASE_URL=$(cat "$HOME/.claude/current/.base-url")
fi

# Load authentication token from current profile
# Auth token takes precedence over OAuth token
if [[ -f "$HOME/.claude/current/.auth-token" ]]; then
  export ANTHROPIC_AUTH_TOKEN=$(cat "$HOME/.claude/current/.auth-token")
elif [[ -f "$HOME/.claude/current/.oauth-token" ]]; then
  export CLAUDE_CODE_OAUTH_TOKEN=$(cat "$HOME/.claude/current/.oauth-token")
fi

# Profile switcher function
switch-claude() {
  local profile="$1"

  if [[ -z "$profile" ]]; then
    echo "Usage: switch-claude <profile-name>"
    echo ""
    echo "Available profiles:"
    ls -1 "$HOME/.claude/profiles/" 2>/dev/null || echo "  (none found)"
    return 1
  fi

  if [[ ! -d "$HOME/.claude/profiles/$profile" ]]; then
    echo "Error: Profile '$profile' not found"
    echo ""
    echo "Available profiles:"
    ls -1 "$HOME/.claude/profiles/"
    return 1
  fi

  ln -sfn "$HOME/.claude/profiles/$profile" "$HOME/.claude/current"
  export CLAUDE_CONFIG_DIR="$HOME/.claude/current"

  # Load base URL if configured
  if [[ -f "$HOME/.claude/current/.base-url" ]]; then
    export ANTHROPIC_BASE_URL=$(cat "$HOME/.claude/current/.base-url")
  else
    unset ANTHROPIC_BASE_URL
  fi

  # Load authentication token (auth token takes precedence)
  local token_loaded=false
  if [[ -f "$HOME/.claude/current/.auth-token" ]]; then
    export ANTHROPIC_AUTH_TOKEN=$(cat "$HOME/.claude/current/.auth-token")
    unset CLAUDE_CODE_OAUTH_TOKEN
    token_loaded=true
  elif [[ -f "$HOME/.claude/current/.oauth-token" ]]; then
    export CLAUDE_CODE_OAUTH_TOKEN=$(cat "$HOME/.claude/current/.oauth-token")
    unset ANTHROPIC_AUTH_TOKEN
    token_loaded=true
  else
    unset CLAUDE_CODE_OAUTH_TOKEN
    unset ANTHROPIC_AUTH_TOKEN
  fi

  echo "✓ Switched to Claude profile: $profile"
  [[ -n "$ANTHROPIC_BASE_URL" ]] && echo "  Base URL: $ANTHROPIC_BASE_URL"
  [[ "$token_loaded" == true ]] && echo "  Token: loaded" || echo "  Warning: No token found"
}
EOF

  echo "✓ Added configuration to $SHELL_CONFIG"
else
  echo "✓ Configuration already present in $SHELL_CONFIG"
fi

echo ""
echo "Setup complete!"
echo ""
echo "Next steps:"
echo "1. Run 'claude setup-token' for each account and save tokens:"
echo "   # For OAuth tokens (standard accounts):"
echo "   echo 'sk-ant-oat01-YOUR_TOKEN' > ~/.claude/profiles/work/.oauth-token"
echo "   echo 'sk-ant-oat01-YOUR_TOKEN' > ~/.claude/profiles/personal/.oauth-token"
echo "   # For API tokens (custom endpoints):"
echo "   echo 'sk-ant-api03-YOUR_TOKEN' > ~/.claude/profiles/project-a/.auth-token"
echo ""
echo "2. (Optional) Configure custom base URLs:"
echo "   echo 'https://api.custom.com' > ~/.claude/profiles/project-a/.base-url"
echo ""
echo "3. Secure token files:"
echo "   chmod 600 ~/.claude/profiles/*/.oauth-token ~/.claude/profiles/*/.auth-token 2>/dev/null || true"
echo ""
echo "4. Reload your shell:"
echo "   source $SHELL_CONFIG"
echo ""
echo "5. Switch profiles:"
echo "   switch-claude work"
echo "   switch-claude personal"

Save as setup-claude-profiles.sh, make executable, and run:

chmod +x setup-claude-profiles.sh
./setup-claude-profiles.sh

References