claude-lm
v0.1.0
Published
nvm-style profile manager for Claude Code — switch between work/personal Claude profiles on one machine by managing CLAUDE_CONFIG_DIR.
Downloads
112
Maintainers
Readme
claude-lm
Claude Local Manager — an nvm-style profile switcher for Claude Code. Keep separate work and personal Claude setups on the same machine and switch between them per-terminal, instantly.
A profile is just a CLAUDE_CONFIG_DIR. Claude Code stores everything —
account/auth, projects, settings, history, even .claude.json — inside that
directory. claude-lm manages a set of these dirs and flips the env var for you,
exactly like nvm flips your PATH.
$ clm ls
profile type target
● work linked /Users/you/.claude-work default
personal system /Users/you/.claude (CLAUDE_CONFIG_DIR unset)
$ clm use personal
Switched to personal (system default — CLAUDE_CONFIG_DIR unset)
$ clm run work -- claude # one-off in the work profile, no shell switchWorks on macOS and Linux, with zsh, bash, and fish. Zero runtime dependencies (Node ≥ 18).
Install
npm install -g claude-lmThen enable the shell shortcut once (this is what lets clm use change your
current shell, the same way nvm requires a line in your rc):
# zsh (macOS default)
clm init --shell zsh >> ~/.zshrc
# bash (common on Linux)
clm init --shell bash >> ~/.bashrc
# fish
clm init --shell fish >> ~/.config/fish/config.fishRestart your shell (or source the file). Running clm init with no --shell
auto-detects from $SHELL and prints the snippet plus the exact command to run.
Without the shell integration you can still use everything except
clm use/clm deactivate(which must modify the parent shell). Useeval "$(clm use work)"orclm run <profile> -- …instead.
Quick start
Adopt your existing setups as profiles (nothing is moved or copied):
clm register personal --system # your current ~/.claude (CLAUDE_CONFIG_DIR unset)
clm register work ~/.claude-work # an existing alternate config dir
clm default personal # what new shells start asSwitch any time:
clm use work # this terminal is now "work"
clm use personal # back to personal
clm current # -> work
clm ls # see them allOpen two terminals and run clm use work in one and clm use personal in the
other — they stay independent, because each just has its own CLAUDE_CONFIG_DIR.
Commands
Switching (needs clm init)
| Command | What it does |
| --- | --- |
| clm use <profile> | Switch the current shell to a profile |
| clm deactivate | Clear the active profile (back to system default) |
| clm current | Print the active profile name |
| clm default [<profile>] | Show / set the default profile for new shells |
Managing
| Command | What it does |
| --- | --- |
| clm list (ls) | List profiles — ● marks active, default is flagged |
| clm create <name> [--from <p>] | Create a new managed profile, optionally copying another |
| clm register <name> <dir> | Register an existing config dir as a profile |
| clm register <name> --system | Register the system default (~/.claude, unset) |
| clm rename <old> <new> | Rename a profile (moves the dir if managed) |
| clm rm <name> [--purge] [--force] | Remove a profile; --purge deletes its files |
| clm path [<profile>] | Print a profile's CLAUDE_CONFIG_DIR |
Running
| Command | What it does |
| --- | --- |
| clm run <profile> [-- cmd…] | Run a command (default: claude) under a profile. Works without shell integration. |
Setup
| Command | What it does |
| --- | --- |
| clm init [--shell zsh\|bash\|fish] | Print the shell integration snippet |
| clm doctor | Show platform, env, and integration status |
claude-lm and clm are the same command.
How it works
- Profile =
CLAUDE_CONFIG_DIR. Each profile maps to a config directory. Selecting one exportsCLAUDE_CONFIG_DIR(plusCLAUDE_PROFILEfor your prompt/statusline). The special system profile unsets the variable so Claude uses its default~/.claude. clm usechanges the current shell via a tiny shell function (installed byclm init) thatevals the export/unset lines — the same tricknvm useuses. Everything human-readable is printed to stderr so stdout stays clean foreval.- The default for new shells is written to
$CLAUDE_LM_HOME/default.sh(anddefault.fish), which the init snippet sources at startup. Changing it withclm default <name>regenerates those files — no node process runs on shell startup. - State lives in
$CLAUDE_LM_HOME/profiles.json(default~/.claude-profiles/). Managed profiles are created under~/.claude-profiles/profiles/<name>/; linked profiles just reference an existing directory and are never moved or deleted unless you pass--force.
Environment variables
| Variable | Purpose |
| --- | --- |
| CLAUDE_LM_HOME | Where claude-lm keeps its state + managed profiles (default ~/.claude-profiles) |
| CLAUDE_CONFIG_DIR | The lever claude-lm sets — read by Claude Code itself |
| CLAUDE_PROFILE | Set by claude-lm to the active profile name (handy for statuslines) |
macOS vs Linux
claude-lm is written entirely with Node's fs/path/os APIs (no shelling
out to platform tools), so it behaves the same on both. The only OS-sensitive
bits are handled for you:
- Default shell differs (zsh on modern macOS, often bash on Linux) —
clm initauto-detects via$SHELLand picks the right syntax/rc path. - Default config dir is
~/.claudeon both platforms. - Paths are resolved with
os.homedir()andpath, so~expansion and separators are correct everywhere.
Windows is not supported for the shell integration (PowerShell would be needed);
core commands and clm run still work.
License
MIT
