Profile manager for Claude Code.
Why? · Quick Start · How It Works · Commands · Tips · Caveats
Claude Code stores everything — auth, history, settings, rules — in a single ~/.claude directory. Great if you're one person with one life. Less great if you:
- Switch between personal and work accounts
- Use different auth methods (OAuth vs AWS Bedrock vs API key)
- Want isolated chat histories per context
- Need different rules/skills/agents per project category
- Are just generally the kind of person who has opinions about config organization 🫠
claudep leverages Claude Code's officially supported CLAUDE_CONFIG_DIR env var to point at different config directories per profile. Profiles symlink to shared templates for common config, so you're not copy-pasting CLAUDE.md files around like an animal.
This is user-level profile swapping. Claude Code's settings hierarchy (project settings.local.json → project settings.json → user config) is fully respected — claudep just swaps which user config directory Claude sees.
Other typical ~/.claude directories like cache, debug, plugins, todos, and history are auto-created by Claude Code per profile and stay fully isolated — no leakage between profiles. The only things shared are the dirs claudep explicitly manages via symlinks (settings, rules, agents, skills, statusline, CLAUDE.md). This does mean some light redundancy per profile as caches and plugins are downloaded independently. An acceptable tradeoff for now — a more pnpm-style content-addressable symlink approach may come later if it becomes painful. 📦
Claude Code has no built-in profile management — Anthropic's official stance is that CLAUDE_CONFIG_DIR is the answer. Fair enough.
There are a handful of third-party account switchers (ccs, cc-account-switcher, claude-switch, etc.) that swap auth credentials between accounts. They solve the "which account am I logged into" problem.
claudep solves a different problem: shared config management across profiles. Rather than duplicating your rules, agents, skills, and instructions into every profile directory, claudep symlinks them from templates. Update a template, every linked profile gets the change. Need one profile to diverge? Eject just that item. The rest keeps inheriting. None of the existing tools do this — they're account switchers, not config managers.
That said, claudep is also an account switcher — each profile has its own isolated auth state, so switching profiles switches accounts. It just gets there as a side effect of managing entire config directories rather than swapping credentials directly. 🤝
chmod +x ./install.sh
# install (creates symlink to /usr/local/bin/claudep) (may require sudo) (run once)
./install.sh
# initialize (~/.claudep with default template) (run once)
claudep init
# create a profile
claudep profile add personal
# launch claude with that profile
claudep start personalThat's it. You now have a personal profile that symlinks to the default template. Claude Code sees it as its config directory.
~/.claudep/
templates/
default/ ← shared config (rules, agents, skills, etc.)
agents/
rules/
skills/
statusline/
CLAUDE.md
settings.json
profiles/
personal/ ← symlinks → templates/default/*
work/ ← symlinks → templates/default/*
- Templates hold shared config. Every profile symlinks to a template.
- Profiles are what Claude Code actually runs against (
CLAUDE_CONFIG_DIRpoints here). - Eject breaks individual symlinks into independent copies when a profile needs to diverge.
Think of it as template inheritance, minus the inheritance. One level of symlinks. No magic. ✨
Sets up claudep's directory structure and default template.
claudep init # defaults to ~/.claudep
claudep init --path ~/my-dir # custom location
claudep init --force # re-init, overwrite template (no prompt)Re-running init on an existing install prompts you to refresh or fill missing files.
Launch Claude Code with the given profile. Any additional args are passed through to claude.
claudep start work
claudep start work --resume
claudep start work -p "fix the tests"Also available as claudep profile start <profile> if you enjoy typing.
Profiles represent distinct Claude Code environments — different accounts, auth methods, or project contexts. Each profile is its own CLAUDE_CONFIG_DIR with isolated history, auth state, and todos. Shared config (rules, agents, etc.) is symlinked from a template until you eject it.
Create a new profile. Symlinks to the default template unless --template is specified.
claudep profile add personal
claudep profile add work --template corpList available profiles.
Delete a profile (with confirmation). Just removes the profile directory — templates are untouched.
Convert symlinked items to independent copies. For when a profile needs its own version of something.
# eject everything
claudep profile eject work --all
# eject specific items
claudep profile eject work --items settings,instructionsEjectable items: agents, rules, skills, statusline, instructions (CLAUDE.md), settings (settings.json)
Eject resolves from wherever the symlink currently points — not hardcoded to default. So profiles extending custom templates eject correctly. 👍
Templates are optional if you only need one shared config — default is created by init and most users never need another. They become useful when you want different base configurations for categories of work: a dev template with coding-focused agents and strict rules, a research template with exploratory skills, a corp template with your org's blessed settings. Profiles extend a template, so updating the template propagates to all linked profiles.
Create a new template by copying from an existing one (defaults to default).
claudep template add corp
claudep template add research --template devAfter creation, edit the template's files directly in ~/.claudep/templates/<name>/.
List available templates.
Delete a template. Refuses to remove default (it's not a democracy 🗳️). Also refuses if any profiles are still linked to it — eject or remove them first.
Removes the claudep symlink and optionally cleans up all data.
Requirements: zsh, jq (for statusline only)
# clone/download, then:
chmod +x ./install.sh
./install.sh # may require sudo
# custom install location
./install.sh /path/to/bin/claudepThe installer creates a symlink — the actual scripts stay wherever you cloned them.
claudep includes a statusline script that displays the active profile and context window usage in Claude Code's status bar.
[claudep:personal | ctx: 84/200k | <current-dir>]
This is configured automatically via the template's settings.json. Uses jq to parse the context metrics Claude Code pipes to stdin. If you don't have jq, the statusline just won't work — everything else is fine.
The typical lifecycle:
claudep profile add work— fresh profile, fully symlinked to template- Use it for a while, realize you need different settings for this profile
claudep profile eject work --items settings— settings.json is now an independent copy- Edit
~/.claudep/profiles/work/settings.jsondirectly - Everything else still inherits from the template
You can eject individual items incrementally. No need to go all-or-nothing unless you want to.
- Do: Edit template files directly in
~/.claudep/templates/<name>/. Changes propagate to all profiles linked to that template. - Do: Edit ejected files directly in
~/.claudep/profiles/<name>/. They're independent copies — no side effects. - Don't: Edit a profile's symlinked files. The symlink points back to the template, so you're actually editing the template — which silently affects every other profile using it. If you need a profile-specific change,
claudep profile ejectthe item first.
The default template ships a rules/_claudep.md rule file that gives Claude ambient awareness of the claudep environment - config directory layout, symlink behavior, and the eject workflow.
One of the more compelling reasons to use profiles: per-profile AWS auth without polluting your global shell environment.
The Claude Code docs suggest exporting AWS_PROFILE and friends in your .zshrc. This works right up until you accidentally run a Bedrock request against your personal account because you forgot which profile was exported globally. 🙃
With claudep, each profile's settings.json scopes the env vars to that Claude session:
Workflow:
claudep profile add work-bedrockclaudep profile eject work-bedrock --items settings- Edit the ejected
settings.jsonwith your Bedrock/SSO config claudep start work-bedrock— AWS auth is scoped to this session only
Your personal profile keeps using OAuth (or whatever), your work profile uses Bedrock via SSO, and neither knows the other exists. No global env vars. No accidents. No "why is this billing to the wrong account" Slack messages at 2am. 🫡
- JetBrains plugin /
/idecommand: There's a known Claude Code issue where the/idecommand and JetBrains plugin use hardcoded paths for lock files, which breaks whenCLAUDE_CONFIG_DIRis set. This is a Claude Code bug, not a claudep bug. Workaround: use Claude Code from the IDE's built-in terminal (claudep start <profile>) rather than through the plugin. Works fine — you just don't get the plugin's UI integration. - Empty template directories: Git doesn't track empty directories, so some directories (
agents/,rules/, etc) in the default template use.gitkeepfiles to persist in the repo. These are automatically removed during initialization. keybindings.jsonenter key: There's a known Claude Code bug wherekeybindings.jsonis ignored for theenterkey — setting"enter": nullto unbind submit has no effect. Not aclaudepissue.
{ // in ~/.claudep/profiles/work-bedrock/settings.json (after eject) "awsAuthRefresh": "aws sso login --profile my-corp-sso", "env": { "AWS_PROFILE": "my-corp-sso", "AWS_REGION": "us-east-2", "CLAUDE_CODE_USE_BEDROCK": "1", "ANTHROPIC_MODEL": "sonnet", // models may ref arns, us.anthropic, etc -> check with your org for which to use "ANTHROPIC_DEFAULT_OPUS_MODEL": "arn:aws:bedrock:us-east-2:...:application-inference-profile/...", "ANTHROPIC_DEFAULT_SONNET_MODEL": "arn:aws:bedrock:us-east-2:...:application-inference-profile/...", "ANTHROPIC_DEFAULT_HAIKU_MODEL": "arn:aws:bedrock:us-east-2:...:application-inference-profile/..." } }