Most developers hitting the "work versus personal" problem with Claude Code reach for the same first instinct: symlinks, aliases, or a shared config directory they point both accounts at. All three are wrong, and one of them will silently erase your MCP server registrations with no warning and no undo.

The cleaner path has been sitting in the CLI this entire time. CLAUDE_CONFIG_DIR is a first-class environment variable that overrides where Claude Code reads and writes every piece of state it owns — credentials, MCP server configs, hooks, skills, project history, and the .claude.json that controls onboarding and folder trust. Two shell functions and ten minutes of setup give you accounts that are structurally isolated, not just conventionally separated.

The Problem With Sharing State

Claude Code stores everything under a single config directory, defaulting to ~/.claude. That directory is not just an OAuth token cache. It contains:

  • Credentials: the tokens that authenticate your CLI sessions to Anthropic
  • MCP server registrations: which Model Context Protocol servers the agent can reach, including their connection parameters and any embedded credentials
  • Hooks: shell commands that fire on specific agent lifecycle events
  • Skills: packaged instruction sets for recurring task types
  • Project history: session transcripts stored at <config-dir>/projects/<project>/<session-id>.jsonl
  • .claude.json: a top-level file tracking MCP server list, folder trust grants, onboarding state, and other global settings

When your employer mandates specific MCP servers — say, one that indexes an internal documentation system or wraps a proprietary database — those registrations live in this directory. So does their connection configuration. In a default setup, your personal Claude Code sessions inherit all of that automatically. Not by accident, just by default.

Before CLAUDE_CONFIG_DIR usage became documented community practice, developers handled this in a few ways:

OS-level user switching: log in as a different macOS or Linux user for work. Gives true isolation but is deeply impractical for mid-day context switches. Opening a new terminal as a different user and back again multiple times per afternoon is friction that compounds.

Docker containers: mount the project directory and run Claude Code inside a container per account. Achieves isolation but breaks features that depend on direct local filesystem access — Claude Code's ability to read and modify files in your working tree, follow local symlinks, and interact with local processes. The overhead is also non-trivial for a tool you reach for constantly.

Symlinks and shared-brain configs: the most popular improvised approach, and the one that introduces the dangerous edge case described later. Symlinking individual config files between directories seems clean but creates partial-state sharing that's hard to reason about.

None of these approaches uses the mechanism that was already there.

How CLAUDE_CONFIG_DIR Actually Works

Claude Code reads CLAUDE_CONFIG_DIR at startup before any other config resolution. If the variable is set and points to a directory, the CLI uses that directory as its entire config root. If the directory doesn't exist yet, Claude Code creates it and initializes a fresh config tree on first run. There is no global config that partially bleeds through — the override is total.

This means you can have completely separate authentication states. Logging out in one config directory does not affect the other. OAuth tokens from your personal Anthropic account stay in one directory; your employer's organization-level credentials stay in another.

The implementation pattern recommended for this isolation is shell functions, not aliases:

# ~/.zshrc or ~/.bashrc

claude-personal() {
  CLAUDE_CONFIG_DIR="$HOME/.claude-personal" claude "$@"
}

claude-work() {
  CLAUDE_CONFIG_DIR="$HOME/.claude-work" claude "$@"
}

The "$@" matters. It passes all arguments to the underlying claude command intact — flags, subcommands, file paths, everything. A shell function with "$@" is transparent to the CLI; an alias would require more careful quoting to handle arguments with spaces or special characters correctly.

Critically, environment variables set inside a shell function do not persist in the parent shell after the function returns. CLAUDE_CONFIG_DIR="$HOME/.claude-work" claude "$@" sets the variable only for the duration of that invocation. Your next bare claude call in the same terminal session will not be contaminated.

Session Transcripts and --resume

One practical question when splitting accounts: does --resume still work? Yes, because session transcripts live under the config directory. When Claude Code records a session, it writes to <config-dir>/projects/<project>/<session-id>.jsonl — JSONL format, one event per line. Because the path is rooted at CLAUDE_CONFIG_DIR, each account maintains its own independent session history.

Running claude-work --resume will only surface sessions from ~/.claude-work/projects/. There is no shim, no session ID namespacing, no additional configuration required. The isolation falls out of the directory structure automatically.

The .claude.json Overwrite Hazard

The most consequential risk in this setup comes from the "shared-brain" alternative — pointing CLAUDE_CONFIG_DIR at a directory that already has content.

When Claude Code initializes a new config directory, it creates a .claude.json file. If you point CLAUDE_CONFIG_DIR at a directory that already contains a .claude.json, Claude Code can overwrite it with a blank or minimal version. That file holds your MCP server registrations. If it gets blanked, every MCP server you had configured in that account disappears — no warning, no backup, no undo dialog.

The failure mode is specific to a tempting pattern: creating one "canonical" config directory and pointing both account functions at it to share things like skill libraries or hook configurations. The moment you run the second account's first initialization against that directory, you risk the overwrite. The same hazard applies to any path typo that happens to resolve to an existing directory with a .claude.json in it.

The safe practice is to use completely distinct, initially empty directories — ~/.claude-personal and ~/.claude-work — and never point both accounts at the same path. Sharing skills and hooks across accounts requires a deliberate sync step (more on this below), not a shared config root.

The Real Story Is MCP Server Isolation

Framing CLAUDE_CONFIG_DIR as a credential-separation tool undersells what it actually does. The deeper value is structural isolation of MCP server registrations.

Credentials are visible and auditable — you know when you're logged in under one account versus another because the CLI tells you. MCP server registrations are quieter. A work MCP server that exposes internal API endpoints, a private documentation index, or proprietary tooling is registered in your config directory and will be available to every Claude Code session that reads that directory. In a shared-config or accidentally-merged setup, your personal Claude Code session can reach your employer's internal systems without any explicit action on your part. You open a terminal, start a personal coding session, and the agent has access to tools it should never have in that context.

CLAUDE_CONFIG_DIR makes work MCP servers structurally invisible during personal sessions — not absent by convention or dependent on remembering to deactivate them, but genuinely unreachable. There is no registration in the personal config directory for those servers. The agent cannot accidentally use them because it has no knowledge they exist. This is exactly the failure mode that surfaces in post-incident reviews when engineers violate employer data-handling agreements: not intentional misuse, but context bleed under deadline pressure when someone forgot to switch modes.

What's notable about this is the implementation cost. Achieving hard isolation between work tooling registrations and personal sessions — the kind of isolation that security teams can point to during a SOC 2 or HIPAA compliance review — requires no infrastructure, no containerization, no third-party tooling. A single environment variable serves as the isolation primitive, and the audit boundary is a filesystem directory that can be inspected, backed up, and wiped like any other directory.

Anthropic built CLAUDE_CONFIG_DIR as a first-class feature, not an undocumented escape hatch. The community is now documenting the obvious consequence of that design decision.

What Teams Should Actually Do With This

For individual developers, the setup is genuinely ten minutes. Create two config directories, add the two shell functions to your rc file, source it, and run the initial --auth flow for each account. The reported maintenance overhead — approximately ten minutes over four months — reflects a single developer with minimal shared configuration. That figure is credible for someone whose primary difference between accounts is credentials and MCP server registrations.

For teams with shared hooks or skill libraries, the maintenance picture changes. If your team standardizes a set of hooks (pre-commit validators, output formatters, logging wrappers) or ships shared skills to all developers, a shared config directory is dangerous and symlinks are fragile. The correct abstraction is a dotfiles repository with a copy script: maintain canonical versions of shared hooks and skills in source control, and run a sync script to copy them into the appropriate config directories. This is more explicit than symlinking — changes to shared config require a deliberate sync — and it avoids the .claude.json overwrite hazard entirely.

For compliance-sensitive environments, treat this pattern as a foundation, not a complete solution. The shell function pattern enforces isolation at invocation time, but it relies on developers remembering to use the right function. A developer who opens a fresh terminal without sourcing their functions file and types claude directly will silently fall back to ~/.claude — whichever account that maps to, probably the personal one — with no indication they are in the wrong context.

Mitigations worth considering: add a check to your shell's prompt that displays the current CLAUDE_CONFIG_DIR when it's set, or configure a PS1/RPROMPT element that shows "work" or "personal" based on the variable. Some developers alias the bare claude command to print an error requiring explicit account selection, forcing deliberate choice every time. For regulated workloads where provable isolation matters more than daily convenience, containers remain the stronger guarantee.

The MCP credential audit question deserves explicit attention. Even with separate config directories, verify that work MCP server credentials are not being cached outside the designated config directory by any MCP server implementation you're running. Some MCP servers manage their own credential caches in application-specific locations (~/.config/<server>, ~/.cache/<server>) independent of Claude Code's config directory. CLAUDE_CONFIG_DIR isolates Claude Code's knowledge of which MCP servers exist; it does not prevent an MCP server binary from writing credentials elsewhere on the filesystem.

Take the Isolation Seriously

The developers reaching for this pattern because they want to keep their Anthropic account credentials separate are solving the right problem with a slightly incomplete framing. The credential separation is real and useful. The MCP server isolation is more important, because MCP server registrations carry access that credentials alone don't reveal — they carry the topology of what internal systems your agent can reach.

CLAUDE_CONFIG_DIR gives you a filesystem-level audit boundary for the entirety of Claude Code's state: one directory per account, each independently inspectable, each wiped or rotated without touching the other. For something as operationally sensitive as an agent that reads your codebase, executes shell commands, and can reach authenticated internal APIs, a clean isolation primitive that requires no infrastructure to deploy is the right default.

Use the shell functions. Keep the config directories separate and non-overlapping. Add a prompt indicator if your team has compliance requirements. And recognize that the ten-minute setup cost buys you structural guarantees that convention-based approaches — aliases, symlinks, reminders to "remember to switch" — can never provide.


Sources & Editorial Disclosure

This article was researched and written with AI assistance (Claude by Anthropic) as part of StackRadar's automated editorial pipeline. Content was synthesised from the following public developer community sources: Dev.to.

All technical claims, version numbers, benchmarks, and project details should be independently verified against official documentation or the original sources listed above. StackRadar analyses and synthesises publicly available information and does not claim original authorship of the underlying events, projects, or research described. Mention of any project, product, or organisation does not constitute an endorsement by StackRadar. This content is provided for informational purposes only — 2026-07-21.