โ ๏ธ Work in Progress โ Under active development. API may change.
๐ข Renamed in v0.15.0: the CLI command is now
scuv(formerlyscoop) โ renamed to coexist with Scoop, the Windows package manager. The crate/repo keep the namescoop-uv. LegacySCOOP_*/.scoop-*settings are still read (with a deprecation warning) until v0.16.0 โ see the CHANGELOG for migration notes.
One scoop, endless envs โ pyenv-style Python environment manager powered by uv
scuv scoops up uv's blazing speed โ centralizing all your Python virtual environments in one place.
๐จ Think of it like running an ice cream parlor:
- The Freezer (
~/.scuv/) keeps all your flavors fresh- Flavors are your virtualenvs โ mix once, serve anywhere
- One scoop is all you need to get the right env
| The Old Way (Yuck ๐ซ ) | The scuv Way (Fresh ๐จ) |
|---|---|
.venv scattered across projects |
~/.scuv/virtualenvs/ centralized |
Manual source .venv/bin/activate |
Auto-activate on directory entry |
| pyenv-virtualenv is slow | uv-powered, 100x+ faster |
| Which Python? Which venv? Chaos. | scuv doctor checks everything |
| Migrating envs? Manual nightmare. | scuv migrate all does it all |
| English-only CLI | Multi-language support (en, ko, ja, pt-BR) |
# 1. Install prerequisites
curl -LsSf https://astral.sh/uv/install.sh | sh # uv
cargo install scoop-uv # installs the scuv command
# 2. Initialize your shell (zsh example)
echo 'eval "$(scuv init zsh)"' >> ~/.zshrc && source ~/.zshrc
# 3. Create your first environment
scuv install 3.12
scuv create myproject 3.12
# 4. Use it (auto-activates when you enter the directory!)
scuv use myproject
(myproject) $ pip install -r requirements.txtThat's it! ๐ Your environment is ready. For detailed docs, see Full Documentation โ
Use this when you want new shell sessions to default to an environment built on Python 3.11.0:
scuv install 3.11.0
scuv create py311 3.11.0
scuv use py311 --globalThis writes py311 to ~/.scuv/version.
Priority still applies: SCUV_VERSION (shell override) and local .scuv-version take precedence.
Use this when you want a new project environment pinned to an exact Python patch version:
scuv install 3.9.5
scuv create myproject 3.9.5
scuv info myprojectIf 3.9.5 is missing, check available versions with uv python list and
scuv list --pythons, then install and retry.
Use this to remove one Python version and every environment using it:
# Optional preview
scuv list --python-version 3.12
# Remove Python 3.12 and all dependent environments
scuv uninstall 3.12 --cascade
# Verify cleanup
scuv list --pythons
scuv doctorFor CI/scripts, add --force to skip confirmation.
Use this to inspect what scuv currently manages:
# All managed Python versions
scuv list --pythons
# All environments and their Python versions
scuv list
# Environments associated with one Python version
scuv list --python-version 3.12For scripts, use --json or --bare.
If the required version is not available from default scuv/uv sources:
# Recommended: explicit interpreter path
scuv create myenv --python-path /opt/python-debug/bin/python3
# Alternative: PATH-based discovery
export PATH="/opt/python-debug/bin:$PATH"
scuv create myenv 3.13Verify integration with uv python list, scuv info myenv, and scuv doctor -v.
Need temporary or directory-specific behavior without touching global settings?
# Temporary: current shell only
export SCUV_NO_AUTO=1
unset SCUV_NO_AUTO
# Directory-local behavior (writes .scuv-version in current directory)
scuv use system # force system Python for this project
scuv use myproject # pin this project to a specific env
# Terminal-only override (no file changes)
scuv shell system
scuv shell --unset| Dependency | Install | Why |
|---|---|---|
| uv (>= 0.5.14) | curl -LsSf https://astral.sh/uv/install.sh | sh |
The secret ingredient ๐ฎ |
| Rust | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh |
Build from source |
Minimum supported
uvis 0.5.14. Runscuv doctorto verify your installation.
โ FAQ: How is scuv different from uv, and is it related to Scoop (Windows)?
They solve different problems, and scuv is built on top of uv โ it's a complement, not a fork or a competitor.
uv 0.11.25 added a preview feature (centralized-project-envs) that relocates a project's
.venv into uv's cache directory. The environment is still bound to that one project: its
identity is a cache key derived from the workspace path and interpreter (e.g.
my-project-cp3.12.4-0123abcd), it cannot be shared between projects, there is no activation
workflow, and uv cache clean / uv cache prune delete it unconditionally โ by design it is a
disposable cache entry that gets transparently recreated.
scuv environments are the opposite in every one of those dimensions: named, durable, and project-independent.
uv centralized-project-envs |
scuv | |
|---|---|---|
| Environment identity | hash cache key (not user-controlled) | a name you choose (scuv create ml 3.12) |
| Shared across projects | no (key includes workspace path) | yes โ any project with a .scuv-version file |
| Activation workflow | none (uv run-centric; .venv link for IDEs) |
shell auto-activation, scuv use, 4 shells |
| Lifecycle | wiped by uv cache clean/prune, auto-recreated |
durable; gc (dry-run first), verify, metadata (last_used) |
| Extras | โ | clone, diff, export/import, .scuv.toml sync, migration from pyenv / conda / virtualenvwrapper |
The uv team has stated there are "no current plans to support standalone environments not tied to a specific project". That standalone, named, pyenv-virtualenv-style workflow is exactly what scuv provides โ with uv doing the fast parts underneath.
No. scuv โ "a scoop of uv" ๐จ โ is a centralized Python virtual environment manager and
is unrelated to Scoop, the Windows package manager. The project was
originally command-named scoop; we renamed the command to scuv in v0.15.0 precisely so both
tools can coexist cleanly on Windows. Installing scuv does not shadow or conflict with scoop
in any shell, including PowerShell. (The repository and crate keep the historical name
scoop-uv.)
cargo install scoop-uv # installs the scuv command๐ก scuv: command not found?
Cargo installs binaries to ~/.cargo/bin. Ensure it's in your PATH:
# Add to ~/.zshrc or ~/.bashrc
export PATH="$HOME/.cargo/bin:$PATH"Or restart your terminal after installing Rust.
The CLI command was renamed in v0.15.0 (scoop โ scuv). One-time migration:
# 1. Update โ installs the new `scuv` binary
scoop self update # or: cargo install scoop-uv
# ("could not locate the freshly installed `scoop` binary" warning is
# expected across the rename โ the update itself already succeeded)
# 2. Remove the old binary if cargo left one behind
rm -f ~/.cargo/bin/scoop
# 3. Update your shell rc: scoop init โ scuv init
# ~/.zshrc / ~/.bashrc: eval "$(scuv init zsh)" # or bash
# fish: scuv init fish | source
# 4. Move your freezer
mv ~/.scoop ~/.scuv
# 5. Restart your shell, then verify
scuv doctor # flags anything left overLegacy SCOOP_* env vars and .scoop-version / .scoop.toml files keep
working (with a one-shot deprecation warning) until v0.16.0, and typing
scoop in bash/zsh/fish still works through a deprecated forwarder that
warns and calls scuv. Skipping step 2 is the one dangerous gap: a
leftover old binary keeps running 0.14.x silently, without any warning.
Zsh (macOS default):
echo 'eval "$(scuv init zsh)"' >> ~/.zshrc
source ~/.zshrcBash:
echo 'eval "$(scuv init bash)"' >> ~/.bashrc
source ~/.bashrcFish:
echo 'scuv init fish | source' >> ~/.config/fish/config.fish
source ~/.config/fish/config.fishPowerShell (Core or Windows PowerShell):
Add-Content $PROFILE 'Invoke-Expression (& scuv init powershell)'
. $PROFILEscuv --version
# โ scuv 0.15.0 ๐จ- โ
Auto-activation โ enter a directory with
.scuv-version, environment activates - โ Tab completion โ commands, environments, Python versions
- โ
Shell wrapper โ
scuv activate/deactivateworks correctly - โ Migration ready โ import from pyenv, conda, virtualenvwrapper
- โ Multi-language โ English, ํ๊ตญ์ด, ๆฅๆฌ่ช, Portuguรชs (BR)
Add scuv after pyenv in your rc file (order matters โ scuv gets the last scoop! ๐จ):
# ~/.zshrc
eval "$(pyenv init -)" # 1. pyenv first
eval "$(scuv init zsh)" # 2. scuv second| Variable | Effect |
|---|---|
SCUV_NO_AUTO=1 |
Disable auto-activation |
SCUV_HOME=/path |
Custom freezer location (default: ~/.scuv) |
# Example: disable auto-activation
echo 'export SCUV_NO_AUTO=1' >> ~/.zshrcYour ice cream parlor lives here:
~/.scuv/ # ๐ง The Freezer
โโโ virtualenvs/ # ๐จ All your flavors
โ โโโ myproject/ # โ Python 3.12 flavor
โ โโโ webapp/ # โ Python 3.11 flavor
โ โโโ experiment/ # โ Python 3.13 flavor
โโโ version # ๐ฅ Default scuv preference
Version file priority (first match wins):
SCUV_VERSION (env) โ "Override for this shell session" (set by scuv shell)
.scuv-version โ "I want THIS flavor here" (local + parent walk)
~/.scuv/version โ "My usual order" (global default)
Note:
.python-versionis not supported. Use.scuv-versionfor version pinning.
Tip: Most commands support
--jsonfor machine-readable output.
| Command | Description |
|---|---|
scuv create <name> [version] |
Create a new environment |
scuv use <name> |
Activate environment (auto-activates in directory) |
scuv list |
List all environments (--sort name|created|last-used) |
scuv status |
Show the currently active environment (includes Last used:) |
scuv which <exe> |
Resolve an executable inside the active env |
scuv run <env> -- <cmd> |
Run a command inside an env without activating |
scuv sync |
Apply .scuv.toml (create env + install packages) |
scuv export <name> |
Snapshot an env as portable JSON |
scuv import <file> |
Recreate an env from an export file |
scuv clone <src> <dst> |
Duplicate an environment |
scuv diff <a> <b> |
Compare two environments (Python, packages, metadata) |
scuv remove <name> |
Delete an environment |
scuv install [version] |
Install Python version |
scuv gc |
Garbage-collect orphan virtualenvs (--yes to remove, --older-than <n>d/w/y for stale envs) |
scuv prune |
Prune the uv cache |
scuv verify |
Per-env health check (metadata, python, pyvenv.cfg, ...) |
scuv doctor |
Health check your setup |
scuv self update |
Update scuv itself to the latest version |
For the complete command reference, see Commands Documentation โ
๐ Full command reference (click to expand)
| Command | Description |
|---|---|
scuv create <name> [version] |
Mix a new flavor (default: latest Python) |
scuv create <name> <ver> --install-python |
Mix a flavor, installing Python first if missing |
scuv use <name> |
Pick your flavor (auto-activates) |
scuv use <name> --link |
Also create .venv symlink for IDE |
scuv use <name> --global |
Set as your usual order |
scuv list |
What's in the freezer? |
scuv list --pythons |
What Python versions do we have? |
scuv list --sort last-used |
Newest activity first (also name / created) |
scuv list --json |
Output as JSON |
scuv info <name> |
Show detailed info (incl. Last used:) |
scuv info <name> --json |
Output info as JSON |
scuv status |
Which flavor am I scooping right now? (incl. Last used:) |
scuv which <exe> |
Where's that scoop in my freezer? |
scuv run <env> -- <cmd> |
Scoop on demand โ run without unpacking |
scuv sync |
Read .scuv.toml and serve the flavor |
scuv sync --with dev --dry-run |
Preview the plan, no scooping yet |
scuv export <name> |
Bottle a flavor as portable JSON |
scuv import <file> |
Unbottle it on another machine |
scuv clone <src> <dst> |
Twin scoop โ same flavor, new cup |
scuv diff <a> <b> |
Spot the difference between two flavors |
scuv remove <name> |
Melt a flavor away |
| Command | Description |
|---|---|
scuv install [version] |
Stock up on Python (default: latest) |
scuv install --stable |
Get the oldest supported Python (3.10) |
scuv uninstall <version> |
Remove a Python version |
| Command | Description |
|---|---|
scuv doctor |
Is everything fresh? Check your setup! |
scuv doctor --fix |
Auto-fix issues where possible |
scuv doctor --json |
Output diagnostics as JSON |
| Command | Description |
|---|---|
scuv migrate list |
Show environments to migrate |
scuv migrate @env <name> |
Migrate a single environment |
scuv migrate all |
Migrate all environments (parallel) |
Supported sources: pyenv-virtualenv, virtualenvwrapper, conda
Flags:
--source {pyenv|virtualenvwrapper|conda},--dry-run,--force,--yes,--strict,--delete-source,--json;@envalso--rename/--auto-rename.
| Command | Description |
|---|---|
scuv verify |
Per-env health diagnosis โ 6 checks per env |
scuv verify --strict |
Same, but exit 1 on any issue (CI gate) |
scuv gc |
Preview orphan virtualenvs (missing metadata or broken Python) |
scuv gc --yes |
Actually remove the orphans |
scuv gc --aggressive |
Also flag unused uv-managed Python versions |
scuv gc --older-than 30d |
Also flag envs idle past the cutoff (no last_used never matches) |
scuv prune |
Prune the uv download/wheel cache (uv cache prune wrapper) |
| Command | Description |
|---|---|
scuv man |
Print top-level scuv.1 to stdout (pipe to man -l -) |
scuv man <DIR> |
Write scuv.1 + one scuv-<sub>.1 per subcommand into <DIR> |
| Command | Description |
|---|---|
scuv lang |
Show current language |
scuv lang <code> |
Set language (en, ko, ja, pt-BR) |
scuv lang --list |
List supported languages |
scuv lang --reset |
Reset to system default |
๐ Want to help translate? We welcome translations in any language! See #44 to contribute.
| Command | Description |
|---|---|
scuv init <shell> |
Output shell initialization script |
scuv completions <shell> |
Generate completion script |
scuv use system |
Switch to system Python |
scuv shell <name> |
Set shell env (eval required) |
scuv shell --unset |
Clear shell env setting |
Shells supported:
bash,zsh,fish,powershell
๐ Read the Full Documentation โ
| Guide | Description |
|---|---|
| Installation Guide | Prerequisites, shell setup, and troubleshooting |
| Quick Start | Get productive in 5 minutes |
| Command Reference | Detailed documentation for every command |
| Shell Integration | Auto-activation, version files, and configuration |
| Migration Guide | Move from pyenv, conda, or virtualenvwrapper |
| Contributing | Development setup and contribution guidelines |
Current MSRV: 1.88 (required by Rust Edition 2024)
scuv follows an N-1 MSRV policy โ we support the current stable Rust and one previous version (~6 week lag).
| User Type | MSRV Impact | Action |
|---|---|---|
| Binary users | โ None | Download from releases or cargo install |
| Source builders | Run rustup update if needed |
|
| Contributors | ๐ง Test on MSRV before PR | cargo +1.88 test --all-features |
๐ Full MSRV policy (click to expand)
We support the current stable Rust and one previous version (~6 week lag). MSRV updates are considered non-breaking for binary users per Cargo RFC 3537.
โ We bump when:
- New Rust features provide significant user benefits
- Critical dependencies require newer versions
- Security fixes only available in newer Rust
โ We don't bump for:
- Time-based schedules without clear benefits
- Minor syntax sugar or aesthetic preferences
- Personal developer preferences
All MSRV changes are documented in CHANGELOG.md with clear rationale.
scuv uses Rust Edition 2024, which requires:
- Minimum Rust 1.85 (hard floor)
- MSRV-aware resolver enabled by default
- Cannot downgrade below 1.85 without changing edition to 2021
- CI: Tests on both MSRV (1.88) and stable automatically
- cargo-msrv: Verifies MSRV on Cargo.toml changes in CI
- Badge: README badge auto-updates from Cargo.toml via shields.io
- Local: rust-toolchain.toml auto-selects 1.88 in project directory
For more details, see our MSRV bump guide in CONTRIBUTING.md.
๐๏ธ Architecture (for contributors and curious minds)
Built with Rust for speed and reliability:
src/
โโโ cli/ # ๐ฎ Command parsing (clap)
โ โโโ commands/ # Individual command handlers
โโโ core/ # ๐ง Domain logic
โ โโโ version # Version file resolution
โ โโโ metadata # Virtualenv metadata (JSON)
โ โโโ virtualenv # Virtualenv entity
โ โโโ doctor # Health diagnostics
โ โโโ migrate/ # Migration (pyenv, conda, venvwrapper)
โโโ shell/ # ๐ Shell integration (bash, zsh, fish, powershell)
โโโ uv/ # โก uv CLI wrapper
โโโ output/ # ๐จ Terminal UI & JSON output
โโโ i18n.rs # ๐ Internationalization (en, ko, ja, pt-BR)
โโโ config.rs # โ๏ธ User configuration
โโโ error, paths, validate # Utilities
Design principle: The CLI outputs shell code to stdout, your shell evaluates it. Just like pyenv โ battle-tested pattern.
Licensed under either of:
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this work shall be dual licensed as above, without any additional terms or conditions.
If you find this project useful, consider buying me a coffee (or an ice cream ๐จ)!
Thanks goes to these wonderful people (emoji key):
azamarassy ๐ |
Murillo Bazilio ๐ |
Tosinibikunle ๐ |
This project stands on the shoulders of giants:
-
uv by Astral โ The blazing-fast Python package manager that powers scuv's backend. Without uv's incredible speed and reliability, scuv wouldn't exist. Thank you to Charlie Marsh and the entire Astral team for revolutionizing Python tooling.
-
pyenv & pyenv-virtualenv โ The original inspiration for scuv's workflow. pyenv taught us how Python version management should feel, and pyenv-virtualenv showed us how to centralize virtual environments elegantly.
-
virtualenv by PyPA โ The pioneer of Python virtual environments. Thank you to Ian Bicking for the original concept that changed how we isolate Python projects.
-
Python โ The language that made programming accessible to everyone. scuv exists to make Python development even more delightful. Thank you to Guido van Rossum and the Python community.
-
Rust โ The language that makes scuv fast, safe, and reliable. Thank you to the Rust team and Ferris ๐ฆ for proving that systems programming can be both powerful and enjoyable.
I built scuv because I needed it โ and now it's yours too. ๐จ
Grab a scoop, enjoy the flavor, and if you have thoughts to share, the door to the ice cream parlor is always open.
Issues ยท Discussions ยท PRs Welcome