Skip to content

Settings

Everything is configured through environment variables, set in your rc file before the source line that loads the shell layer.

How a profile gets chosen

Before the variables, the rule they fit into. On every cd - and before the first prompt of a new terminal - the shell layer walks up from the current directory looking for a .claude-profile file:

~/projects/<project-name>/api/src    no marker, go up
~/projects/<project-name>/api        no marker, go up
~/projects/<project-name>            .claude-profile -> "work"   <- first match wins
  1. The nearest .claude-profile walking upward, if there is one.
  2. Otherwise CLAUDE_DEFAULT_PROFILE, if you set it.
  3. Otherwise default, the original ~/.claude.

So markers answer "in this project, use that account", and CLAUDE_DEFAULT_PROFILE answers "and everywhere else, use this one".

Marking a project

Create the file in any directory - a single repo, or a folder containing several:

echo work > ~/projects/<project-name>/.claude-profile

It contains nothing but a profile name. From then on, cd anywhere at or below that directory selects work automatically, and claude uses that account without you switching anything.

~/projects/<project-name>/          .claude-profile -> "work"
  ├── api/                       -> work
  ├── web/                       -> work
  └── infra/                     -> work

Putting it one level above your repos, as here, covers all of them from one file and keeps it outside version control - nothing to commit or gitignore. Put it inside a repo instead if only that repo should differ.

A deeper marker beats a shallower one, so a single repo can opt out of its parent's rule:

echo personal > ~/projects/<project-name>/experiment/.claude-profile

Markers are just files. Delete one to remove the rule, or cat one to see it. claude-doctor reports any that name a profile which does not exist.

See Per-project accounts for the full guide.

CLAUDE_DEFAULT_PROFILE

Which profile an unmarked directory falls back to. Defaults to default, i.e. the original ~/.claude.

export CLAUDE_DEFAULT_PROFILE=work
source "$HOME/.claude-tools/shell/claude-profiles.zsh"

Set it before the source line, in ~/.zshrc or ~/.bashrc.

This is the machine-wide fallback, not a per-project setting - it applies wherever no marker matches.

It is worth setting when default is not the account you want to land on - after logging out of it, for instance, or if your original ~/.claude belongs to an account you rarely use.

A marker always wins

Setting this does not disturb directories that already have a .claude-profile. It only changes what happens everywhere else.

If you would rather not set an environment variable, a marker at your home directory does much the same job:

echo work > ~/.claude-profile

The difference is small. The variable applies wherever your rc file is loaded. A marker at ~ is a real file, so anything walking upward finds it too.

CLAUDE_PROFILE_PROMPT

Show the active profile in your prompt, so you cannot use the wrong account by accident.

export CLAUDE_PROFILE_PROMPT=1
source "$HOME/.claude-tools/shell/claude-profiles.zsh"

zsh appends it to RPROMPT; bash prepends it to PS1.

It stays quiet on whichever profile is your normal one - default, or whatever CLAUDE_DEFAULT_PROFILE is set to. So the prompt only speaks up when you are somewhere unusual, which is when it matters:

~/projects/personal %                            (nothing - your usual account)
~/projects/client-work %         claude:client   (flagged)
Variable Effect
CLAUDE_PROFILE_PROMPT=1 turn the indicator on
CLAUDE_PROFILE_PROMPT_PREFIX text before the name (default claude:)
CLAUDE_PROFILE_SHOW_DEFAULT=1 show it everywhere, including your usual profile

Building your own prompt? Call claude_profile_prompt directly - it prints the indicator or nothing, and touches no other state.

PROMPT='%~ $(claude_profile_prompt) %# '

Knowing which profile is active

Two indicators cover two different places, and you probably want both:

Where you are What tells you Set up with
Your shell the prompt indicator CLAUDE_PROFILE_PROMPT=1, above
Inside a Claude Code session the status line claude-profiles statusline --install-all

The shell prompt disappears the moment Claude Code takes over the terminal, which is exactly when knowing the account matters most - so the status line is not a duplicate of it.

claude-profiles statusline --install-all
work │ you@company.com │ ⎇ main │ ctx 52%/1000k │ 5h 2% │ 7d 3%

Choose what it shows with --show; the segments are listed in the command reference. Settings are per-profile, which is why --install-all exists.

CLAUDE_HANDOFF_COPY

Make claude-handoff copy instead of move. By default a handoff moves: the source transcript is renamed to <session-id>.jsonl.bak once the target is verified identical.

export CLAUDE_HANDOFF_COPY=1
source "$HOME/.claude-tools/shell/claude-profiles.zsh"

--move and --copy on the command line override it. See Move or copy.

CLAUDE_PROFILE_HOME

Where account data lives. Defaults to ~/.claude-profiles. Set it before running install.sh if you want it elsewhere.

CLAUDE_CONFIG_DIR

Read by Claude Code itself, not by this tool - claude-profile sets it for you. Setting it by hand works too, and claude-doctor warns if it points somewhere that does not exist.

NO_COLOR

Honoured by every command. Output is also uncoloured automatically when piped.

Overrides you rarely need

The shell layer works these out for itself. Set one only when the guess is wrong on your machine, before the source line in your rc file.

Variable What it points at Default
CLAUDE_TOOLS_DIR where this tool is installed derived from the sourced file's own path
CLAUDE_PROFILE_PY the core script $CLAUDE_TOOLS_DIR/bin/claude-profiles.py
CLAUDE_PY the Python to run it with python3, else python, whichever is on PATH

The usual reason is a machine where Python is installed under another name, or a pinned interpreter:

export CLAUDE_PY=/usr/local/bin/python3.12
source "$HOME/.claude-tools/shell/claude-profiles.zsh"

claude-doctor reports which Python it found, so check there first.