uvm keeps the familiar create / activate / deactivate / list / delete workflow, while using uv for environment creation and package management. Version 1.1.1 focuses on reliability: unified config resolution, safer metadata, managed shell integration blocks, upward auto-activation lookup, and first-line diagnostics through doctor and repair.
- Conda-style commands with a small Bash footprint
- Shared environments under
UVM_ENVS_DIRand tracked custom--pathenvironments - Upward auto-activation for both
.venvand.uvmrc - Safer metadata storage under
envs.d/instead of fragile JSON string assembly - Managed shell and mirror updates with stable start/end markers
- Diagnostics and recovery commands:
uvm doctor,uvm repair - Linux, macOS, and Windows Git Bash support
- Bash or Zsh
uv- Linux, macOS, or Windows with Git Bash
Notes:
- PowerShell and CMD are not supported in this release.
- On Windows, install
uvin PowerShell first, then useuvmfrom Git Bash.
Interactive installation needs a real script file, so download it first instead of piping it directly into bash.
Linux / macOS:
curl -fsSL https://raw.githubusercontent.com/Tendo33/uvm/main/install.sh -o install.sh
bash install.sh
rm install.shWindows (Git Bash):
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
curl -fsSL https://raw.githubusercontent.com/Tendo33/uvm/main/install.sh -o install.sh
bash install.sh
rm install.shThe installer:
- installs
uvmto~/.local/bin/uvm - installs libraries to
~/.local/lib/uvm - initializes
UVM_HOMEat${UVM_HOME:-~/.config/uvm} - initializes
UVM_ENVS_DIRat~/uv_envsunless overridden - registers existing managed environments in the default environment directory
- writes managed PATH and shell-hook blocks instead of appending loose lines
- updates the
uvmirror configuration through a managed block - when
install.shis fetched from a tagged release, remote file downloads stay pinned to that same tag by default
bash install.sh -yImportant:
- In non-interactive mode, missing
uvis a hard error. - Use this mode for CI, automation, or repeatable local setup.
- If
UVM_HOMEis already exported, the installer reuses it instead of forcing~/.config/uvm.
bash install.sh --envs-dir /path/to/envsThis writes the selected directory into $(uvm config show) through UVM_HOME/config.
When you download a release-scoped install.sh, the installer downloads bin/, lib/, and templates/ from the matching v<version> ref by default.
If you intentionally want another ref, override it explicitly:
UVM_DOWNLOAD_REF=main bash install.sh -ygit clone https://github.com/Tendo33/uvm.git
cd uvm
bash install.shuvm create myenv --python 3.11
source ~/.bashrc # or ~/.zshrc after install
uvm activate myenv
uvm list
uvm deactivate
uvm delete myenvuvm create myenv
uvm create myenv --python 3.12
uvm create myenv --path /work/envs/myenvBehavior:
- environment names are validated before any filesystem write
--pathcreates the environment at a custom location- custom-path environments are still tracked by metadata and show up in
uvm list
uvm activate myenvactivate must run inside shell integration because it needs to source the target environment into the current shell.
If it says shell integration is required, add this to your shell rc file:
eval "$(uvm shell-hook)"The installer can manage that block for you automatically.
uvm deactivateLike activate, this works through shell integration.
uvm list
uvm list --allBehavior:
- lists managed records from
envs.d/ - also discovers valid environments under the default
UVM_ENVS_DIR - marks the current active environment with
* --alladds the source column so you can see whether an entry ismanagedordiscovered
uvm delete myenv
uvm delete myenv --forceSafety rules:
- refuses invalid environment names
- refuses to delete the currently active environment
- refuses to delete unmanaged or out-of-scope paths
- removes both the directory and the corresponding metadata record
uvm scan
uvm scan /path/to/envsScans a directory and registers valid environments found there.
uvm initInitializes UVM_HOME, ensures the default environment directory exists, configures the mirror block, and scans the default environment directory.
uvm doctorReports:
- platform and shell
- resolved shell rc file
- shell hook status
UVM_HOMEUVM_ENVS_DIR- metadata record count
- whether
~/.local/binis inPATH - detected
uvversion - mirror block status
- current active environment
- whether the current environment came from auto-activation
Use this first when activate, list, or auto-activation does not behave as expected.
uvm repairRepairs safe, recoverable state by:
- pruning invalid metadata records
- rescanning the default
UVM_ENVS_DIR - rewriting the managed shell-hook block
- rewriting the managed mirror block
It does not delete valid environments automatically.
uvm config show
uvm config mirrorconfig show prints the effective config paths.
config mirror refreshes the managed mirror block in ~/.config/uv/uv.toml.
If uvm detects unmanaged mirror sections that would conflict, it warns and leaves the file unchanged.
eval "$(uvm shell-hook)"This command emits the shell runtime needed for:
uvm activateuvm deactivate- prompt-based auto-activation checks
The shell hook no longer overrides cd. It uses prompt/chpwd hooks instead.
uvm checks for activation targets upward from the current directory on every prompt.
Priority order:
- nearest parent
.venv - nearest parent
.uvmrc
That means:
- entering a project subdirectory still keeps the project environment active
- leaving the project tree deactivates auto-activated environments
.venvwins over.uvmrcwhen both exist in scope
Note: .venv detection is intentionally broad — any directory named .venv that contains a valid pyvenv.cfg and activation script is auto-activated, regardless of whether it was created by uvm or by python -m venv / another tool.
cd ~/project
uv venv
cd ~/project/src/moduleIf ~/project/.venv exists and is valid, it is auto-activated even from src/module.
uvm create shared-311 --python 3.11
echo "shared-311" > .uvmrcAny directory inside that project tree inherits the nearest parent .uvmrc.
UVM_HOME: defaults to~/.config/uvmUVM_ENVS_DIR: defaults to~/uv_envs- metadata directory:
~/.config/uvm/envs.d - the installer respects an already-exported
UVM_HOME
uvm now stores one record per environment:
~/.config/uvm/envs.d/
myenv.env
py311.env
Benefits:
- no manual JSON string assembly
- atomic record writes through temporary files + move
- stable add/update/remove behavior in pure Bash
- lock directory reserved for concurrent metadata writes
Legacy envs.json is only used for one-time migration when record files do not exist yet.
The installer and repair flow write stable markers such as:
# >>> uvm path >>>
export PATH="${HOME}/.local/bin:$PATH"
# <<< uvm path <<<
# >>> uvm shell >>>
eval "$(uvm shell-hook)"
# <<< uvm shell <<<These markers make install, repair, reinstall, and uninstall idempotent.
uvm config mirror and uvm repair update only the managed block inside ~/.config/uv/uv.toml:
# >>> uvm mirror >>>
[[index]]
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
default = true
[python-downloads]
url = "https://mirrors.tuna.tsinghua.edu.cn/python-releases/"
# <<< uvm mirror <<<If uv.toml already exists, uvm keeps a one-time backup as uv.toml.backup.
If unmanaged [[index]] or [python-downloads] sections are already present, uvm skips writing its managed mirror block to avoid producing an invalid or ambiguous TOML configuration.
Run:
source ~/.bashrc # or ~/.zshrc
uvm doctorIf PATH ~/.local/bin shows missing, add:
export PATH="${HOME}/.local/bin:$PATH"or rerun:
bash install.sh -yRun:
uvm repair
source ~/.bashrc # or ~/.zshrcThen verify with:
uvm doctorChecklist:
- if it was created with
uvm create --path, confirm the path still exists - run
uvm repairto prune stale records and rescan the default directory - run
uvm list --allto inspect source labels
Checklist:
- the shell rc file contains the managed
uvm shellblock - the shell has been reloaded
.venvis a validuvenvironment with an activation script.uvmrccontains a valid environment name- the referenced shared environment still exists
Use:
uvm doctor
uvm repairuvm does not bundle uv.
- interactive install can offer installation on Linux/macOS
- non-interactive install fails if
uvis missing - Windows users should install
uvin PowerShell first
bash uninstall.sh
bash uninstall.sh --force
bash uninstall.sh --keep-shell-configUninstall removes:
~/.local/bin/uvm~/.local/lib/uvm- the effective
UVM_HOMEdirectory - managed shell blocks, unless
--keep-shell-configis used
Uninstall keeps:
- your virtual environments
uv~/.config/uv/uv.toml
If you installed with a custom UVM_HOME, export the same value before uninstalling:
UVM_HOME=/custom/uvm-home bash uninstall.sh --forceDetails: project_document/UNINSTALL.md
- Linux: supported
- macOS: supported
- Windows Git Bash: supported
- PowerShell / CMD: not supported in this release
This repository currently includes:
- BATS tests for metadata, name validation, managed blocks,
doctor,repair,--path, and upward.uvmrcactivation - CI jobs for syntax checks, BATS, and Windows Git Bash smoke coverage
- environment export / import
- shell completion
- richer environment descriptions
- future shell adapters beyond Bash/Zsh after the current Bash core remains stable
MIT. See LICENSE.