๐จ scuv
โ ๏ธ 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
What is scuv? ๐จ
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) |
60-Second Quick Start โก
# 1. Install prerequisites
|
# 2. Initialize your shell (zsh example)
&&
# 3. Create your first environment
# 4. Use it (auto-activates when you enter the directory!)
()
That's it! ๐ Your environment is ready. For detailed docs, see Full Documentation โ
Set Python 3.11.0 as Global Default
Use this when you want new shell sessions to default to an environment built on Python 3.11.0:
This writes py311 to ~/.scuv/version.
Priority still applies: SCUV_VERSION (shell override) and local .scuv-version take precedence.
Create a Project Env with Python 3.9.5
Use this when you want a new project environment pinned to an exact Python patch version:
If 3.9.5 is missing, check available versions with uv python list and
scuv list --pythons, then install and retry.
Uninstall Python + Associated Envs
Use this to remove one Python version and every environment using it:
# Optional preview
# Remove Python 3.12 and all dependent environments
# Verify cleanup
For CI/scripts, add --force to skip confirmation.
List Python Versions + Associated Envs
Use this to inspect what scuv currently manages:
# All managed Python versions
# All environments and their Python versions
# Environments associated with one Python version
For scripts, use --json or --bare.
Integrate Custom or Pre-Existing Python
If the required version is not available from default scuv/uv sources:
# Recommended: explicit interpreter path
# Alternative: PATH-based discovery
Verify integration with uv python list, scuv info myenv, and scuv doctor -v.
Project-Scoped Auto-Activation Control
Need temporary or directory-specific behavior without touching global settings?
# Temporary: current shell only
# Directory-local behavior (writes .scuv-version in current directory)
# Terminal-only override (no file changes)
Installation ๐จ
Prerequisites
| 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.
How is scuv different from uv's centralized-project-envs preview?
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.
Is scuv related to Scoop, the Windows package manager?
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.)
Install scuv
Cargo installs binaries to ~/.cargo/bin. Ensure it's in your PATH:
# Add to ~/.zshrc or ~/.bashrc
Or restart your terminal after installing Rust.
Upgrading from scoop (โค 0.14.x) ๐
The CLI command was renamed in v0.15.0 (scoop โ scuv). One-time migration:
# 1. Update โ installs the new `scuv` binary
# ("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
# 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
# 5. Restart your shell, then verify
Legacy 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.
Shell Setup
Step 1: Add to your shell config
Zsh (macOS default):
Bash:
Fish:
echo 'scuv init fish | source' >> ~/.config/fish/config.fish
source ~/.config/fish/config.fish
PowerShell (Core or Windows PowerShell):
Add-Content $PROFILE 'Invoke-Expression (& scuv init powershell)'
. $PROFILE
Step 2: Verify
# โ scuv 0.15.0 ๐จ
What this enables
- โ
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)
Using with pyenv
Add scuv after pyenv in your rc file (order matters โ scuv gets the last scoop! ๐จ):
# ~/.zshrc
Options
| Variable | Effect |
|---|---|
SCUV_NO_AUTO=1 |
Disable auto-activation |
SCUV_HOME=/path |
Custom freezer location (default: ~/.scuv) |
# Example: disable auto-activation
The Freezer ๐ง
Your 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.
Commands ๐จ
Tip: Most commands support
--jsonfor machine-readable output.
Essential Commands
| 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 โ
Everyday Scooping
| 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 |
Managing the Freezer
| 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 |
Health Check ๐ฉบ
| 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 |
Migration ๐
| 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.
Cleanup ๐งน
| 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) |
Packaging ๐ฆ
| 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> |
Language ๐
| 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.
Shell Integration
| 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
Documentation ๐
๐ 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 |
Minimum Supported Rust Version (MSRV) ๐ฆ
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 | โ ๏ธ Rust >= 1.88 required | Run rustup update if needed |
| Contributors | ๐ง Test on MSRV before PR | cargo +1.88 test --all-features |
About N-1 Policy
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.
When We Bump MSRV
โ 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.
Edition 2024 Constraints
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
Automation
- 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.
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.
License
Licensed under either of:
at your option.
Contribution
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.
Support ๐จ
If you find this project useful, consider buying me a coffee (or an ice cream ๐จ)!
Contributors โจ
Thanks goes to these wonderful people (emoji key):
Acknowledgments ๐จ
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