Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Switch between different Claude Code API configurations

License

jroth55/claude-profile

Repository files navigation

Claude Profile Management System

Version License Shell Platform

A drop-in shell function that gives you claude-profile [name] on macOS and Linux. Specifically designed for developers using Claude Code (the AI-powered coding assistant CLI tool), this system allows you to seamlessly switch between different API providers and configurations for the same claude command.

Who This Is For

This tool is specifically for developers using Claude Code - the agentic coding assistant CLI tool (invoked with the claude command). It allows you to:

  • Switch between work and personal Anthropic accounts
  • Use different API providers (Anthropic, AWS Bedrock, third-party providers)
  • Maintain separate configurations for different projects or environments
  • Keep API keys and settings isolated per shell session

Note: This is not for general Claude API development or the Claude Desktop application. This tool configures environment variables that the Claude Code CLI reads to determine which API provider and credentials to use.

Quick Start

# One-line installation
curl -fsSL https://raw.githubusercontent.com/jroth55/claude-profile/main/install.sh | bash

# Or manual installation
git clone https://github.com/jroth55/claude-profile.git
cd claude-profile
make install

Features

  • Per-shell scoping: Profile changes only affect the current shell session
  • Environment isolation: Each profile loads its own API keys and settings
  • Keychain integration: Optional macOS Keychain support for secure API key storage
  • Runtime namespacing: Separate ephemeral cache/log directories per profile with secure per-user namespacing
  • Config vs Runtime separation: Persistent config in ~/.claude/profiles/, ephemeral runtime in temp directories
  • Tab completion: Auto-complete profile names and commands in zsh (when completion system is available)
  • Enhanced Security:
    • Strict input validation and variable name validation
    • .env file ownership and permission verification
    • Symlink attack prevention in runtime directories
    • Command injection protection in keychain operations
    • Internal variable protection against override attempts
    • Per-user namespace in world-writable directories
  • Cross-shell compatibility: Works in zsh and bash (requires zsh for completion)
  • Robust parsing: Supports .env files with optional export, quotes, and whitespace trimming

Installation

Step 1: Create Profile Directories and Configuration Files

# Create the profiles directory structure
mkdir -p ~/.claude/profiles/{work,personal}

# Create work profile configuration
cat > ~/.claude/profiles/work/.env <<'EOF'
# Environment variables for "work" profile
# ⚠ WARNING: Replace these placeholder keys with real API keys
ANTHROPIC_API_KEY=sk-ant-api-03-your-actual-work-key-here
ANTHROPIC_MODEL=claude-3-5-sonnet-latest

# Secondary/smaller model for background tasks (third-party providers)
ANTHROPIC_SMALL_FAST_MODEL=provider/small-model-name

# Optional toggles:
# CLAUDE_CODE_USE_BEDROCK=false
# DISABLE_TELEMETRY=1
EOF

# Create personal profile configuration  
cat > ~/.claude/profiles/personal/.env <<'EOF'
# Environment variables for "personal" profile
# ⚠ WARNING: Replace these placeholder keys with real API keys
ANTHROPIC_API_KEY=sk-ant-api-03-your-actual-personal-key-here
ANTHROPIC_MODEL=claude-3-5-haiku-latest

# Secondary/smaller model for background tasks (third-party providers)
ANTHROPIC_SMALL_FAST_MODEL=provider/small-fast-model-name
EOF

# Set secure permissions (readable only by you)
chmod 600 ~/.claude/profiles/work/.env
chmod 600 ~/.claude/profiles/personal/.env

Step 2: Download the Claude Profile Function

The installation script automatically downloads the latest version of the Claude profile function from this repository. The function provides secure profile management with comprehensive security features.

For manual installation, you can download the script directly:

# Download the claude-profile.zsh script
curl -fsSL https://raw.githubusercontent.com/jroth55/claude-profile/main/claude-profile.zsh -o ~/.claude/claude-profile.zsh
chmod +x ~/.claude/claude-profile.zsh

The script includes:

  • Secure environment variable management
  • Profile validation and cleanup
  • macOS Keychain integration
  • Runtime directory isolation
  • Tab completion support for zsh

Step 3: Add to Your Shell Configuration

Add this line to your shell's startup file:

# For zsh users, add to ~/.zshrc:
if ! grep -q "claude-profile.zsh" ~/.zshrc 2>/dev/null;
 then
  echo "source ~/.claude/claude-profile.zsh" >> ~/.zshrc
fi

# For bash users, add to ~/.bashrc:
if ! grep -q "claude-profile.zsh" ~/.bashrc 2>/dev/null;
 then
  echo "source ~/.claude/claude-profile.zsh" >> ~/.bashrc
fi

Step 4: Enable Tab Completion (Optional, zsh only)

For zsh users who want tab completion, ensure your completion system is initialized in your ~/.zshrc:

# Add these lines to ~/.zshrc if not already present
autoload -Uz compinit
compinit

Note: The claude-profile system no longer auto-initializes the completion system for security and performance reasons. If you don't have completion enabled, the system will work perfectly but without tab completion.

Step 5: Reload Your Shell

source ~/.zshrc   # for zsh
# or
source ~/.bashrc  # for bash

Usage

Basic Commands

# List available profiles
claude-profile list

# Switch to a profile
claude-profile work

# Check current active profile
claude-profile current

# Switch back to previous profile  
claude-profile -

# Clear all profile environment variables
claude-profile off

Example Session

$ claude-profile list
personal
work

$ claude-profile work
→ active profile: work
⚠ Warning: API key appears to be a placeholder - update with real key

$ echo $CLAUDE_PROFILE
work

$ env | grep -E '^(ANTHROPIC|CLAUDE)_'
ANTHROPIC_API_KEY=sk-ant-api-03-your-actual-work-key-here
ANTHROPIC_MODEL=claude-3-5-sonnet-latest
CLAUDE_PROFILE=work
CLAUDE_RUNTIME_DIR=/tmp/claude-501/work

# Now run Claude Code - it will use the work profile settings
$ claude chat

# Switch to personal profile
$ claude-profile personal
→ active profile: personal

# Quick toggle back to work
$ claude-profile -
→ active profile: work

# Clear all profile settings
$ claude-profile off
→ profile off

$ claude-profile current
none

Configuration

Environment Variables

Each profile's .env file supports these variable prefixes:

  • ANTHROPIC_* - Anthropic API settings
  • CLAUDE_* - Claude Code specific settings
  • MCP_* - Model Context Protocol settings
  • DISABLE_* - Feature toggles
  • AWS_* - AWS Bedrock configuration
  • OPENROUTER_* - OpenRouter API settings
  • HTTP_PROXY, HTTPS_PROXY, NO_PROXY - Proxy configuration

Key Environment Variables

Primary Model Configuration:

  • ANTHROPIC_API_KEY - Your API key for the Anthropic service
  • ANTHROPIC_MODEL - Primary model to use (e.g., claude-3-5-sonnet-latest)
  • ANTHROPIC_BASE_URL - API endpoint (for third-party providers)

Secondary Model Configuration (Third-party Providers):

  • ANTHROPIC_SMALL_FAST_MODEL - Smaller/faster model for background tasks, parsing, and quick operations. The profile script will show a helpful tip if this is not set when using a third-party provider.

Example Third-party Provider Setup:

# Configure both primary and secondary models
export ANTHROPIC_BASE_URL="https://your-provider.com/v1"
export ANTHROPIC_API_KEY="your-api-key"
export ANTHROPIC_MODEL="provider/large-model-name"
export ANTHROPIC_SMALL_FAST_MODEL="provider/small-model-name"

Protected Variables: The system prevents .env files from overriding internal control variables (CLAUDE_PROFILE, CLAUDE_RUNTIME_DIR, CLAUDE_PROFILE_KEYS, CLAUDE_PROFILE_PREV).

Variable Name Validation: Only valid shell identifiers are accepted (must match ^[A-Za-z_][A-Za-z0-9_]*$)).

Configuration vs Runtime Directory Structure

The system uses two types of directories for different purposes:

Configuration Directories (~/.claude/profiles/):

  • Purpose: Persistent configuration that should be backed up
  • Contents: .env files with API keys and settings
  • Lifetime: Permanent until manually deleted
  • Backup: Should be included in backups (but be careful with API keys)

Runtime Directories (${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}}/claude(-$UID)/):

  • Purpose: Ephemeral runtime space for caches, logs, and temporary files
  • Contents: Per-profile cache/log directories created by tools that respect CLAUDE_RUNTIME_DIR
  • Lifetime: Temporary, typically cleaned on reboot
  • Backup: Should NOT be backed up
  • Permissions: Created with 700 (owner-only access) for security

This separation ensures:

  • Isolation: Prevents caches/logs from "work" polluting "personal" profiles
  • Security: Runtime data is isolated and not accidentally backed up
  • OS Conventions: Follows XDG standards for temporary vs persistent data

.env File Format

The parser supports flexible formatting with robust whitespace handling:

# All of these formats work:
ANTHROPIC_API_KEY=sk-ant-api-03-...
export ANTHROPIC_MODEL=claude-3-5-sonnet-latest
ANTHROPIC_BASE_URL="https://api.anthropic.com"
MCP_SERVER_CONFIG_PATH='/path/to/config.json'

# Leading/trailing whitespace is trimmed from both keys and values:
  DISABLE_TELEMETRY = 1  

# Full-line comments are supported:
# This is a comment
CLAUDE_CODE_USE_BEDROCK=false

Note on Comments: Only full-line comments starting with # are supported. Inline comments (e.g., KEY=value # comment) are not supported and would be included in the value.

Note on Quoted Values: The parser removes matching single or double quotes that surround the entire value. It does not support escaped quotes or quotes embedded within the value.

Profile Name Restrictions

Profile names are restricted to alphanumeric characters, underscores, and hyphens only (A-Z, a-z, 0-9, _, -) with a maximum length of 255 characters. This prevents shell injection and ensures compatibility.

# Valid profile names:
claude-profile work
claude-profile personal-2024
claude-profile dev_env

# Invalid profile names:
claude-profile "my profile"    # spaces not allowed
claude-profile ../hack         # path traversal blocked
claude-profile test.profile    # dots not allowed

Security Features

macOS Keychain Integration (Recommended)

Store API keys securely in macOS Keychain instead of plaintext .env files:

# Store API key in Keychain securely (avoids shell history exposure)
printf "Enter API key for work profile: " && read -rs api_key && echo
# Use -w flag with the password as argument
security add-generic-password -a "$USER" -s "claude:work:ANTHROPIC_API_KEY" -w "$api_key"
unset api_key

# Remove the key from .env file - it will be auto-loaded from Keychain
# For macOS:
sed -i '' '/^ANTHROPIC_API_KEY=/d' -- "${HOME}/.claude/profiles/work/.env"
# For Linux:
sed -i '/^ANTHROPIC_API_KEY=/d' -- "${HOME}/.claude/profiles/work/.env"

Built-in Security Protections

  • Input validation: Profile names restricted to safe characters with length limits
  • Path traversal prevention: Cannot access parent directories
  • Variable prefix filtering: Only allows safe environment variable prefixes
  • Variable name validation: Ensures only valid shell identifiers are exported
  • Internal variable protection: Prevents .env from overriding system variables
  • Enhanced runtime directory security:
    • Per-user namespacing in world-writable directories (e.g., /tmp/claude-$UID/)
    • Symlink attack prevention - refuses to use symlinked paths
    • Ownership verification when possible
    • Created with 700 permissions atomically with TOCTOU protection
    • Existing directories have permissions enforced
    • Comprehensive validation prevents directory traversal attacks
  • .env file validation:
    • Ownership verification - must be owned by current user
    • Permission validation - refuses group/world-writable files
    • Comprehensive error reporting for security violations
  • Keychain security:
    • Username validation to prevent command injection
    • Enhanced error handling for keychain access issues
    • Process list protection - API keys never visible in process arguments
  • Placeholder detection:
    • Comprehensive case-insensitive pattern matching
    • Detects wide variety of placeholder formats and dummy keys
  • Safe variable cleanup: Uses glob-safe iteration to prevent expansion attacks
  • Performance optimizations: Shell-native parsing eliminates external process overhead

Privacy Considerations

Warning: Commands like env | grep ANTHROPIC will display your API key in terminal output and shell history. For security:

# Check if API key is set without revealing it
if [ -n "${ANTHROPIC_API_KEY:-}" ]; then echo "API key is set: YES"; else echo "API key is set: NO"; fi

# Or check current profile status
claude-profile current && printf "Profile active with %s\n" "$([ -n "${ANTHROPIC_API_KEY:-}" ] && printf "API key" || printf "NO API key")"

Verification Checklist

Test the installation with these commands:

# 1. Test empty profile directory handling (zsh null_glob fix)
rm -rf ~/.claude/profiles/*
claude-profile list            # Should print "(no profiles yet)" without errors

# 2. Test profile creation and switching
mkdir -p ~/.claude/profiles/{test1,test2}
echo "CLAUDE_TEST=value1" > ~/.claude/profiles/test1/.env
echo "CLAUDE_TEST=value2" > ~/.claude/profiles/test2/.env
claude-profile test1
echo "Test1: $CLAUDE_TEST"     # Should show "value1"
claude-profile test2  
echo "Test2: $CLAUDE_TEST"     # Should show "value2" (test1 vars cleaned)
claude-profile off
env | grep CLAUDE_TEST         # Should show nothing

# 3. Test profile name validation
claude-profile "invalid name"     # Should reject with error message
claude-profile ../etc             # Should reject path traversal
claude-profile test.profile       # Should reject dots

# 4. Test .env parsing with various formats
cat > ~/.claude/profiles/test1/.env <<'EOF'
export CLAUDE_EXPORT_VAR="exported value"
  CLAUDE_SPACED_VAR = spaced value  
CLAUDE_QUOTED='single quoted'
CLAUDE_INVALID-NAME=should_be_ignored
EOF
claude-profile test1
echo "Export: $CLAUDE_EXPORT_VAR"    # Should work
echo "Spaced: $CLAUDE_SPACED_VAR"    # Should be "spaced value" (trimmed)
echo "Quoted: $CLAUDE_QUOTED"        # Should be "single quoted"
env | grep CLAUDE_INVALID            # Should show nothing (invalid name)

# 5. Test tab completion (zsh only)
# Type: claude-profile <TAB>
# Should show: list, current, off, -, test1, test2

# 6. Test runtime directory creation with secure permissions and per-user namespacing
claude-profile test1
ls -ld "$CLAUDE_RUNTIME_DIR"         # Should show drwx------ (700 permissions)
echo "$CLAUDE_RUNTIME_DIR"           # Should include your UID in path (e.g., /tmp/claude-501/)

# 7. Test .env file security validation
chmod 664 ~/.claude/profiles/test1/.env   # Make group-writable
claude-profile test1                       # Should refuse to load with security error
chmod 600 ~/.claude/profiles/test1/.env   # Fix permissions

# 8. Test placeholder detection
echo 'ANTHROPIC_API_KEY=your-key-here' > ~/.claude/profiles/test1/.env
claude-profile test1                       # Should warn about placeholder

Advanced Usage

Project-Specific Auto-Switching with direnv

# Install direnv
brew install direnv  # macOS
# or
apt install direnv   # Ubuntu/Debian

# Add to your shell config (after claude-profile source line)
eval "$(direnv hook zsh)"    # for zsh
eval "$(direnv hook bash)"   # for bash

# In your project directory:
echo 'claude-profile work >/dev/null' > .envrc
direnv allow

# Now cd into the directory automatically activates the work profile

Multiple Environment Setups

mkdir -p ~/.claude/profiles/{dev,staging,prod,testing}

# Development environment
cat > ~/.claude/profiles/dev/.env <<'EOF'
ANTHROPIC_API_KEY=sk-ant-api-03-dev-key
ANTHROPIC_MODEL=claude-3-haiku-20240307
ANTHROPIC_SMALL_FAST_MODEL=claude-3-haiku-20240307
ANTHROPIC_BASE_URL=https://dev-api.example.com
DISABLE_TELEMETRY=1
EOF

# Production environment
cat > ~/.claude/profiles/prod/.env <<'EOF'
ANTHROPIC_API_KEY=sk-ant-api-03-prod-key
ANTHROPIC_MODEL=claude-3-5-sonnet-latest
ANTHROPIC_SMALL_FAST_MODEL=claude-3-5-haiku-latest
ANTHROPIC_BASE_URL=https://api.anthropic.com
CLAUDE_CODE_USE_BEDROCK=false
EOF

# Third-party provider environment (OpenRouter example)
cat > ~/.claude/profiles/openrouter/.env <<'EOF'
ANTHROPIC_BASE_URL=https://openrouter.ai/api/v1
ANTHROPIC_API_KEY=sk-or-your-openrouter-key-here
ANTHROPIC_MODEL=anthropic/claude-3.5-sonnet
ANTHROPIC_SMALL_FAST_MODEL=anthropic/claude-3-haiku
OPENROUTER_API_KEY=sk-or-your-openrouter-key-here
# Proxy configuration if needed
HTTP_PROXY=http://proxy.company.com:8080
HTTPS_PROXY=http://proxy.company.com:8080
NO_PROXY=localhost,127.0.0.1,.local
DISABLE_TELEMETRY=1
EOF

# AWS Bedrock environment
cat > ~/.claude/profiles/bedrock/.env <<'EOF'
CLAUDE_CODE_USE_BEDROCK=true
AWS_PROFILE=claude-bedrock
AWS_REGION=us-west-2
AWS_ACCESS_KEY_ID=your-aws-access-key
AWS_SECRET_ACCESS_KEY=your-aws-secret-key
ANTHROPIC_MODEL=anthropic.claude-3-5-sonnet-20241022-v2:0
ANTHROPIC_SMALL_FAST_MODEL=anthropic.claude-3-haiku-20240307-v1:0
EOF

Shell Prompt Integration

Add the current profile to your prompt:

# For zsh with Oh My Zsh, add to your theme:
PROMPT='%{$fg[cyan]%}$([ -n "$CLAUDE_PROFILE" ] && echo "[$CLAUDE_PROFILE] ")%{$reset_color%}'$PROMPT

# For bash, add to PS1:
PS1="\$([ -n \"\$CLAUDE_PROFILE\" ] && echo \"[\$CLAUDE_PROFILE] \")\$PS1"

Troubleshooting

Command Not Found

# Check if function is loaded
type claude_profile

# Reload the function
source ~/.claude/claude-profile.zsh

# Check shell configuration
grep claude-profile ~/.zshrc ~/.bashrc

Variables Not Cleaning Up

If switching profiles leaves old variables set:

# Check if you're in zsh
echo $ZSH_VERSION

# Verify CLAUDE_PROFILE_KEYS format
claude-profile work
echo "Keys: $CLAUDE_PROFILE_KEYS"    # Should be space-separated list

Permission Errors

# Fix file and directory permissions (secure)
chmod 700 ~/.claude ~/.claude/profiles ~/.claude/profiles/*
chmod 600 ~/.claude/profiles/*/.env
chmod 755 ~/.claude/claude-profile.zsh

Profile Name Validation Errors

The system only allows alphanumeric characters, underscores, and hyphens:

# These will be rejected:
claude-profile "my profile"      # spaces
claude-profile work.2024         # dots  
claude-profile test/env          # slashes

# These are valid:
claude-profile work_2024         # underscore
claude-profile personal-backup   # hyphen
claude-profile dev123            # alphanumeric

API Key Not Loading

# Check .env file syntax and variable names
cat ~/.claude/profiles/work/.env

# Test placeholder detection
claude-profile work  # Should warn if key looks like placeholder

# Check Keychain (macOS only)
security find-generic-password -a "$USER" -s "claude:work:ANTHROPIC_API_KEY" -w

Security Validation Errors

The enhanced security system may produce these error messages:

File Ownership Issues:

$ claude-profile work
error: refusing to load /Users/user/.claude/profiles/work/.env (not owned by current user)

# Fix: Ensure you own the .env file
sudo chown "$USER" ~/.claude/profiles/work/.env

File Permission Issues:

$ claude-profile work
error: refusing to load /Users/user/.claude/profiles/work/.env (group/other writable permissions: 664)

# Fix: Set secure permissions
chmod 600 ~/.claude/profiles/work/.env

Runtime Directory Issues:

$ claude-profile work
error: runtime path is a symlink (refusing): /tmp/claude-501

# Fix: Remove the symlink and let the system create a proper directory
rm /tmp/claude-501

Username Validation for Keychain:

$ claude-profile work
error: invalid username for keychain access

# This indicates an issue with the USER environment variable
# Check: echo "$USER"

Platform Compatibility

Shell Compatibility

  • zsh: Full support including tab completion and null_glob handling
  • bash: Core functionality only (no tab completion or zsh-specific features)

Operating System Compatibility

  • macOS: Full support including Keychain integration
  • Linux: Core functionality (no Keychain support)
  • Windows: Not tested (may work in WSL)

Cross-Platform sed Commands

The installation uses platform-specific sed syntax:

# macOS (BSD sed):
sed -i '' '/pattern/d' file

# Linux (GNU sed):
sed -i '/pattern/d' file

# Portable approach used in scripts:
if [[ "$OSTYPE" == "darwin"* ]]; then
  sed -i '' '/pattern/d' -- "${file}"
else
  sed -i '/pattern/d' -- "${file}"
fi

File Structure

Configuration Files (Persistent)

~/.claude/
├── claude-profile.zsh                    # Main function file  
└── profiles/                             # Profile configurations (persistent)
    ├── work/
    │   └── .env                          # Work profile settings
    ├── personal/
    │   └── .env                          # Personal profile settings
    └── dev/                              # Additional profiles
        └── .env

Runtime Directories (Ephemeral)

# Default location (recommended - follows OS conventions):
${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}}/claude/
├── work/                                 # Work profile runtime (cache/logs)
├── personal/                             # Personal profile runtime  
└── dev/                                  # Dev profile runtime

# Example paths:
# Linux (XDG_RUNTIME_DIR available): /run/user/1000/claude/work/
# Linux (fallback): /tmp/claude-1000/work/
# macOS (XDG_RUNTIME_DIR available): /run/user/501/claude/work/  
# macOS (fallback): /var/folders/xx/yyyyyyy/T/claude-501/work/

Alternative: Persistent Runtime Directories

If you prefer runtime directories under your home directory (e.g., for persistence across reboots), modify the code:

# In claude-profile.zsh, change this line:
export CLAUDE_RUNTIME_DIR="${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}}/claude/${name}"

# To this:
export CLAUDE_RUNTIME_DIR="${HOME}/.claude/runtime/${name}"

This creates:

~/.claude/
├── claude-profile.zsh
├── profiles/                             # Configurations
│   ├── work/.env
│   └── personal/.env
└── runtime/                              # Persistent runtime (if modified)
    ├── work/
    └── personal/

Uninstallation

# Remove source lines from shell configs (cross-platform)
if [[ "$OSTYPE" == "darwin"* ]]; then
  sed -i '' '/claude-profile/d' ~/.zshrc ~/.bashrc 2>/dev/null || true
else
  sed -i '/claude-profile/d' ~/.zshrc ~/.bashrc 2>/dev/null || true
fi

# Remove the claude directory
rm -rf ~/.claude

# Remove runtime directories  
rm -rf "${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}}/claude"

# Remove Keychain entries (macOS only)
security delete-generic-password -a "$USER" -s "claude:work:ANTHROPIC_API_KEY" 2>/dev/null || true
security delete-generic-password -a "$USER" -s "claude:personal:ANTHROPIC_API_KEY" 2>/dev/null || true

# Reload shell
exec $SHELL

License

This configuration is provided as-is for personal and commercial use. Feel free to modify and distribute.

About

Switch between different Claude Code API configurations

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •