Core concepts
How cvm maps onto Claude Code configuration without modifying Claude Code itself.
CLAUDE_CONFIG_DIR
Claude Code locates its config via CLAUDE_CONFIG_DIR (default ~/.claude). cvm sets that variable to ~/.cvm/envs/<name> while an environment is active or for a single run/open child process.
CVM_ENV
Process-scoped name of the active environment. Used by cvm current, cvm list, and statusline scripts.
Activation protocol
The compiled binary cannot change the parent shell. Hidden resolvers print data the hook applies:
cvm __resolve-activate <env>→KEY=VALUElines (dotenv +CLAUDE_CONFIG_DIR+CVM_ENV)cvm __resolve-deactivate→ names to unset
Shell hooks additionally:
- Prefix the prompt with
(env) - Backup
PATHinCVM_OLD_PATHand prepend$CLAUDE_CONFIG_DIR/bin - Watch for project
.cvmfiles (auto-activate) - Deactivate the previous env before switching, so dotenv keys do not leak
PATH, PS1, CLAUDE_CONFIG_DIR, and any CVM_* key in an environment .env are ignored so activation state cannot be poisoned.Directory layout
~/.cvm/
├── bin/ # cvm binary (install.sh)
└── envs/
└── work/ # = CLAUDE_CONFIG_DIR when active
├── .env
├── skills/
├── bin/ # claude + skills shims
├── settings.json
└── ... # whatever Claude Code writes
Shims
Each env ships bin/claude and bin/skills (plus .cmd on Windows). They set CLAUDE_CONFIG_DIR/CVM_ENV from their parent directory, strip their own bin from PATH to avoid recursion, then exec the real tool. The skills shim runs npx --yes skills.
cvm.yaml surface
Export/import only touch settings.json (permissions + mcpServers), skill names, and .env keys. Credentials, history, and .env values are never read into the manifest.