npm.io
0.1.0 • Published 5d agoCLI

claude-lm

Licence
MIT
Version
0.1.0
Deps
0
Size
37 kB
Vulns
0
Weekly
0

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 switch

Works on macOS and Linux, with zsh, bash, and fish. Zero runtime dependencies (Node ≥ 18).


Install

npm install -g claude-lm

Then 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.fish

Restart 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). Use eval "$(clm use work)" or clm 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 as

Switch any time:

clm use work        # this terminal is now "work"
clm use personal    # back to personal
clm current         # -> work
clm ls              # see them all

Open 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 exports CLAUDE_CONFIG_DIR (plus CLAUDE_PROFILE for your prompt/statusline). The special system profile unsets the variable so Claude uses its default ~/.claude.
  • clm use changes the current shell via a tiny shell function (installed by clm init) that evals the export/unset lines — the same trick nvm use uses. Everything human-readable is printed to stderr so stdout stays clean for eval.
  • The default for new shells is written to $CLAUDE_LM_HOME/default.sh (and default.fish), which the init snippet sources at startup. Changing it with clm 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 init auto-detects via $SHELL and picks the right syntax/rc path.
  • Default config dir is ~/.claude on both platforms.
  • Paths are resolved with os.homedir() and path, 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

Keywords