Multi-Identity Management¶
Managing multiple AI accounts - Complete guide to setting up and switching between personal, educational, and work AI identities.
Table of Contents¶
- Overview
- The Problem
- The Solution
- Directory Structure
- Gemini Identity Setup
- Claude Identity Setup
- OpenAI Identity Setup
- Switching Identities
- Security Considerations
- Troubleshooting
Overview¶
What Is Multi-Identity?¶
Multi-Identity is the ability to use different AI accounts for different purposes without rebuilding Docker containers or logging out.
Example use cases: - Personal projects → Use personal Claude account - University assignments → Use educational Gemini account - Work projects → Use company-provided OpenAI account - Testing → Switch between accounts to test different API quotas
Supported Identities¶
| AI Agent | Identity Types | Storage Format |
|---|---|---|
| Gemini CLI | edu1, edu2, edu3, edu4 | OAuth JSON files |
| Claude Code | personal, edu1, edu2, work | Session JSON files |
| OpenAI/ChatGPT | chatgpt, edu1, edu2, work | Session JSON files |
The Problem¶
Without Multi-Identity¶
Old approach (single account only):
# ~/.config/claude/config.json - one file, one account
# To switch accounts:
# 1. Logout from Claude
# 2. Login with different account
# 3. Overwrite config.json
# 4. Restart container
# 5. Repeat for every switch
Problems: - ❌ Time-consuming to switch - ❌ Easy to forget which account is active - ❌ Risk of using wrong account for a project - ❌ Can't have multiple sessions simultaneously
With Multi-Identity¶
New approach (file-based identity switching):
# Multiple files, one per account
~/.claude/session-personal.json
~/.claude/session-edu1.json
~/.claude/session-work.json
# dev() prompts: "Which Claude account?"
# You select: edu1
# dev() mounts: ~/.claude/session-edu1.json
# Inside container: Claude uses edu1 account
Benefits: - ✅ Instant switching (just select in dev()) - ✅ Always know which account is active - ✅ No logout/login cycles - ✅ Each project can use different accounts
The Solution¶
File-Based Identity Storage¶
Key insight: Store each account's credentials in separate files on the host, then mount the desired file at runtime.
How it works:
- Setup Phase (one-time):
- Authenticate each AI account separately
- Save credentials to named files (edu1, personal, work, etc.)
-
Organize in
~/.gemini/,~/.claude/,~/.openai/ -
Runtime Phase (every dev() session):
- dev() prompts: "Which account?"
- You select: e.g., "edu1"
- dev() mounts that specific file into container
-
Agent uses that identity
-
Switching (anytime):
- Exit container
- Run dev() again
- Select different account
- New container uses new identity
Directory Structure¶
Complete Layout¶
~/.gemini/ # Gemini OAuth credentials
├── oauth-edu1.json # Educational account 1
├── oauth-edu2.json # Educational account 2
├── oauth-edu3.json # Educational account 3
└── oauth-edu4.json # Educational account 4
~/.claude/ # Claude session files
├── session-personal.json # Personal account
├── session-edu1.json # Educational account 1
├── session-edu2.json # Educational account 2
└── session-work.json # Work/company account
~/.openai/ # OpenAI/ChatGPT session files
├── session-chatgpt.json # Personal ChatGPT account
├── session-edu1.json # Educational account 1
├── session-edu2.json # Educational account 2
└── session-work.json # Work/company account
Create Directory Structure¶
Run on server:
# Create directories
mkdir -p ~/.gemini ~/.claude ~/.openai
# Verify
ls -la ~/.gemini ~/.claude ~/.openai
Gemini Identity Setup¶
Prerequisites¶
- Google account (personal or educational)
- Access to Google Cloud Console (for OAuth)
- Gemini CLI installed (pre-installed in Docker image)
Step 1: Obtain OAuth Credentials¶
Option A: Use Existing OAuth File
If you already have a Gemini OAuth file from another machine:
# Copy from local machine to server
scp ~/path/to/oauth.json kavi@100.80.53.55:~/.gemini/oauth-edu1.json
Option B: Create New OAuth Credentials
- Go to Google Cloud Console
- Create new project or select existing
- Enable Gemini API
- Create OAuth 2.0 Client ID (Desktop app)
- Download JSON file
- Rename and upload:
Step 2: Authenticate¶
On server:
# Create temp container to authenticate
docker run --rm -it \
-v ~/.gemini:/root/.gemini \
my-dev-env:latest \
/bin/bash
# Inside container
gemini auth login --credentials /root/.gemini/oauth-edu1.json
# Follow browser prompts to authenticate
# This updates oauth-edu1.json with refresh token
exit
Step 3: Verify¶
# Test authentication worked
docker run --rm \
-v ~/.gemini/oauth-edu1.json:/root/.gemini/oauth_creds.json:ro \
-e "GOOGLE_API_KEY=your-api-key" \
my-dev-env:latest \
gemini --version
Repeat for Additional Accounts¶
For edu2, edu3, edu4:
# Repeat steps with different Google accounts
# Save as oauth-edu2.json, oauth-edu3.json, oauth-edu4.json
Claude Identity Setup¶
Prerequisites¶
- Anthropic account (personal, educational, or work)
- Claude Code installed (pre-installed in Docker image)
- ANTHROPIC_API_KEY in Infisical
Step 1: Authenticate Account¶
On server:
# Create temp container with Infisical secrets
infisical export --env=dev --projectId=personal-vault > /tmp/env-$$.list
docker run --rm -it \
--env-file /tmp/env-$$.list \
-v ~/.claude:/root/.config/claude \
my-dev-env:latest \
/bin/bash
# Inside container
claude login
# Follow prompts (uses ANTHROPIC_API_KEY from env)
# This creates /root/.config/claude/config.json
exit
rm /tmp/env-$$.list
Step 2: Save Session with Identity Label¶
Step 3: Repeat for Other Accounts¶
For educational account:
# Get educational ANTHROPIC_API_KEY
# (If different from personal - otherwise same file works)
# Re-authenticate
docker run --rm -it \
-e "ANTHROPIC_API_KEY=sk-ant-edu-..." \
-v ~/.claude:/root/.config/claude \
my-dev-env:latest \
claude login
# Save as edu1
mv ~/.claude/config.json ~/.claude/session-edu1.json
For work account:
Step 4: Verify¶
# Test each session file works
docker run --rm \
-e "ANTHROPIC_API_KEY=sk-ant-..." \
-v ~/.claude/session-personal.json:/root/.config/claude/config.json:ro \
my-dev-env:latest \
claude --version
OpenAI Identity Setup¶
Prerequisites¶
- OpenAI account (personal or educational)
- API key or ChatGPT session
Step 1: Authenticate¶
On server:
# Create temp container with OpenAI credentials
infisical export --env=dev --projectId=personal-vault > /tmp/env-$$.list
docker run --rm -it \
--env-file /tmp/env-$$.list \
-v ~/.openai:/root/.openai \
my-dev-env:latest \
/bin/bash
# Inside container (if OpenAI CLI supports login)
# openai login
# OR manually create session file with API key
exit
rm /tmp/env-$$.list
Step 2: Save Session Files¶
# If login created session file
mv ~/.openai/session.json ~/.openai/session-chatgpt.json
# Or manually create
cat > ~/.openai/session-chatgpt.json << 'EOF'
{
"api_key": "sk-proj-...",
"organization": "org-..."
}
EOF
Step 3: Repeat for Additional Accounts¶
# For educational account
cat > ~/.openai/session-edu1.json << 'EOF'
{
"api_key": "sk-proj-edu-...",
"organization": "org-edu-..."
}
EOF
# For work account
cat > ~/.openai/session-work.json << 'EOF'
{
"api_key": "sk-proj-work-...",
"organization": "org-work-..."
}
EOF
Switching Identities¶
Using dev() Function¶
The dev() function handles identity switching automatically:
Example session:
Gemini Account Prompt:
You select2 → dev() mounts ~/.gemini/oauth-edu2.json
Claude Account Prompt:
🧠 Select Claude Account:
[1] personal (default)
[2] edu1
[3] edu2
[4] work
[0] Skip (no Claude session)
👉 Choose (0-4): 1
1 → dev() mounts ~/.claude/session-personal.json
OpenAI Account Prompt:
🔮 Select OpenAI/ChatGPT Account:
[1] chatgpt (default)
[2] edu1
[3] edu2
[4] work
[0] Skip (no OpenAI session)
👉 Choose (0-4): 0
0 → dev() skips OpenAI (no file mounted)
Result: Container launches with Gemini edu2, Claude personal, no OpenAI.
Behind the Scenes¶
What dev() does:
# Based on your selections, dev() builds Docker command:
docker run --rm -it \
--env-file /tmp/env-$$.list \
-v ~/.gemini/oauth-edu2.json:/root/.gemini/oauth_creds.json:ro \
-v ~/.claude/session-personal.json:/root/.config/claude/config.json:ro \
# (OpenAI skipped - no mount) \
-v ~/Coding:/app \
-w /app/my-project \
my-dev-env:latest \
/bin/bash
Inside container:
# Check which identities are active
ls -la /root/.gemini/oauth_creds.json # → edu2
ls -la /root/.config/claude/config.json # → personal
ls -la /root/.openai/session.json # → doesn't exist (skipped)
# Use agents
gemini # Uses edu2 account
claude # Uses personal account
Switching Mid-Session¶
To switch identities:
-
Exit container:
-
Re-run dev():
-
Select different accounts:
-
New container uses new identities:
Security Considerations¶
File Permissions¶
Critical: Identity files contain sensitive credentials.
Set correct permissions:
# Only owner can read/write
chmod 600 ~/.gemini/*.json
chmod 600 ~/.claude/*.json
chmod 600 ~/.openai/*.json
# Verify
ls -la ~/.gemini/
# Should show: -rw------- (600)
Read-Only Mounts¶
Why :ro flag?
dev() mounts identity files as read-only:
Benefits: - ✅ Container can't modify host credentials - ✅ Prevents accidental corruption - ✅ Prevents malicious code from stealing/changing credentials - ✅ Audit trail (host files never change)
Backup Identity Files¶
These files are critical - losing them means re-authenticating all accounts.
Backup strategy:
# Create backup directory
mkdir -p ~/identity-backups
# Backup all identity files (encrypted)
tar czf - ~/.gemini ~/.claude ~/.openai | \
gpg --symmetric --cipher-algo AES256 \
> ~/identity-backups/ai-identities-$(date +%Y%m%d).tar.gz.gpg
# Copy to secondary server
scp ~/identity-backups/ai-identities-*.gpg ubuntu@100.81.231.36:~/backups/
Restore if needed:
# Decrypt and extract
gpg --decrypt ~/identity-backups/ai-identities-20250115.tar.gz.gpg | \
tar xzf - -C ~/
Never Commit to Git¶
Add to .gitignore:
Why: These files contain secrets - committing them exposes credentials.
Separate Accounts by Purpose¶
Best practice: Use different accounts for different purposes:
| Account Type | Use For | Why |
|---|---|---|
| Personal | Personal projects, experiments | Quota isolation |
| Educational | School assignments, research | Compliance (school policies) |
| Work | Company projects | Legal (company owns output) |
Don't mix: Using work account for personal projects may violate employment agreements.
Troubleshooting¶
"OAuth file not found"¶
Symptom:
Causes: 1. File doesn't exist on host 2. dev() didn't mount the file 3. Wrong account selected
Solution:
# Check file exists
ls -la ~/.gemini/oauth-edu1.json
# If missing, set up that account (see Gemini Identity Setup above)
# If exists, verify dev() mounts it
# (Check dev() function selection logic)
"Session expired"¶
Symptom:
Cause: Session file is outdated (tokens expired)
Solution:
# Re-authenticate that account
# For Claude personal:
infisical export --env=dev --projectId=personal-vault > /tmp/env-$$.list
docker run --rm -it \
--env-file /tmp/env-$$.list \
-v ~/.claude:/root/.config/claude \
my-dev-env:latest \
claude login
# Save new session
mv ~/.claude/config.json ~/.claude/session-personal.json
rm /tmp/env-$$.list
"Wrong account being used"¶
Symptom: Selected edu1 but agent uses personal account
Cause: File mount is incorrect
Debug:
# Inside container, check which file is mounted
ls -la /root/.gemini/oauth_creds.json
ls -la /root/.config/claude/config.json
# If wrong file, exit and check dev() selection logic
exit
"Permission denied" reading identity file¶
Symptom:
Cause: File permissions too restrictive or mount failed
Solution:
# Check host file permissions
ls -la ~/.gemini/oauth-edu1.json
# Should be: -rw------- (600)
# If too restrictive (e.g., 400), fix:
chmod 600 ~/.gemini/oauth-edu1.json
Multiple files for same account¶
Symptom: Confused about which file is current
Solution: Use consistent naming and date backups:
# Current files (no date)
~/.claude/session-personal.json
# Backups (with date)
~/.claude/session-personal-20250115.json.bak
Summary¶
Multi-Identity Management: - ✅ Store each AI account in separate files on host - ✅ Use file-based switching via dev() prompts - ✅ Mount files read-only into container for security - ✅ Switch identities by exiting and re-running dev() - ✅ Backup files with GPG encryption - ✅ Never commit identity files to Git
Directory Structure:
~/.gemini/oauth-{edu1,edu2,edu3,edu4}.json
~/.claude/session-{personal,edu1,edu2,work}.json
~/.openai/session-{chatgpt,edu1,edu2,work}.json
File Permissions: chmod 600 (owner read/write only)
Best Practices:
1. Separate accounts by purpose (personal/edu/work)
2. Use read-only mounts (:ro)
3. Backup encrypted to secondary server
4. Re-authenticate when sessions expire
5. Never commit to Git
What's Next: - Learn about AI Agents Integration - how agents use identities - Learn about .ai-context.md Standard - project configuration - Learn about dev() Function - orchestration details