Introduction
scoop is a centralized Python virtual environment manager powered by uv.
One scoop, endless envs — pyenv-style workflow with uv’s blazing speed.
What is scoop?
Think of it like running an ice cream parlor:
- The Freezer (
~/.scoop/) 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 | The scoop Way |
|---|---|
.venv scattered across projects | ~/.scoop/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. | scoop doctor checks everything |
Quick Example
# Install Python
scoop install 3.12
# Create a virtualenv
scoop create myproject 3.12
# Use it (auto-activates!)
scoop use myproject
(myproject) $ pip install requests
# Check what's available
scoop list
Features
- Fast — Powered by uv, virtualenv creation is nearly instant
- Centralized — All environments live in
~/.scoop/virtualenvs/ - Auto-activation — Enter a directory, environment activates automatically
- Shell integration — Works with bash and zsh
- pyenv compatible — Reads
.python-versionfiles - Health checks —
scoop doctordiagnoses your setup
Getting Started
Ready to scoop? Head to the Installation guide to get started.
Links
Installation
Prerequisites
| Dependency | Version | Install Command |
|---|---|---|
| uv | Latest | curl -LsSf https://astral.sh/uv/install.sh | sh |
| Rust | 1.85+ | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh |
Install via Cargo
cargo install scoop-uv
The binary is installed to ~/.cargo/bin/scoop.
Verify Installation
scoop --version
# scoop 0.2.10
Troubleshooting
scoop: command not found
Ensure ~/.cargo/bin is in your PATH:
# Add to ~/.zshrc or ~/.bashrc
export PATH="$HOME/.cargo/bin:$PATH"
Then restart your terminal or run:
source ~/.zshrc # or ~/.bashrc
uv not found
scoop requires uv to be installed and available in PATH. Verify:
uv --version
If not installed, run:
curl -LsSf https://astral.sh/uv/install.sh | sh
Next Steps
After installation, set up Shell Integration to enable auto-activation and tab completion.
Quick Start
This guide walks you through the basic scoop workflow.
1. Set Up Shell Integration
Zsh (macOS default):
echo 'eval "$(scoop init zsh)"' >> ~/.zshrc
source ~/.zshrc
Bash:
echo 'eval "$(scoop init bash)"' >> ~/.bashrc
source ~/.bashrc
2. Install Python
# Install latest Python
scoop install 3.12
# Verify installation
scoop list --pythons
3. Create a Virtual Environment
scoop create myproject 3.12
This creates a virtual environment at ~/.scoop/virtualenvs/myproject/.
4. Use the Environment
cd ~/projects/myproject
scoop use myproject
This:
- Creates
.scoop-versionfile in the current directory - Activates the environment (prompt shows
(myproject))
5. Work With Your Environment
(myproject) $ pip install requests
(myproject) $ python -c "import requests; print(requests.__version__)"
6. Auto-Activation
Once configured, entering a directory with .scoop-version automatically activates the environment:
cd ~/projects/myproject
# (myproject) appears in prompt automatically
Common Commands
| Task | Command |
|---|---|
| List environments | scoop list |
| List Python versions | scoop list --pythons |
| Show environment info | scoop info myproject |
| Remove environment | scoop remove myproject |
| Check installation | scoop doctor |
IDE Integration
Create a .venv symlink for IDE compatibility:
scoop use myproject --link
This creates .venv pointing to the scoop environment, recognized by VS Code, PyCharm, etc.
Next Steps
- See Shell Integration for advanced configuration
- See Commands for full command reference
Shell Integration
scoop uses a shell wrapper pattern (like pyenv) where the CLI outputs shell code that gets evaluated by the shell.
How It Works
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ User runs │ --> │ CLI outputs │ --> │ Shell evals │
│ scoop use │ │ export ... │ │ the output │
└─────────────┘ └─────────────┘ └─────────────┘
The scoop shell function wraps the CLI binary:
scoop() {
case "$1" in
use)
command scoop "$@"
eval "$(command scoop activate "$name")"
;;
activate|deactivate|shell)
eval "$(command scoop "$@")"
;;
*)
command scoop "$@"
;;
esac
}
Setup
Zsh
echo 'eval "$(scoop init zsh)"' >> ~/.zshrc
source ~/.zshrc
Bash
echo 'eval "$(scoop init bash)"' >> ~/.bashrc
source ~/.bashrc
Fish
echo 'eval (scoop init fish)' >> ~/.config/fish/config.fish
source ~/.config/fish/config.fish
Auto-Activation
When enabled, scoop automatically activates environments based on version files.
Zsh: Uses chpwd hook (runs on directory change)
autoload -Uz add-zsh-hook
add-zsh-hook chpwd _scoop_hook
Bash: Uses PROMPT_COMMAND
PROMPT_COMMAND="_scoop_hook;$PROMPT_COMMAND"
Fish: Uses --on-variable PWD event handler
function _scoop_hook --on-variable PWD
# Check for version file and activate/deactivate
end
The hook checks for version files and activates/deactivates accordingly.
Version Resolution Priority
scoop checks these sources in order (first match wins):
| Priority | Source | Set by |
|---|---|---|
| 1 | SCOOP_VERSION env var | scoop shell |
| 2 | .scoop-version file | scoop use |
| 3 | .python-version file | pyenv compatibility |
| 4 | ~/.scoop/version file | scoop use --global |
The “system” Value
When any source contains the value system, scoop deactivates the current virtual environment and uses the system Python.
scoop use system # Write "system" to .scoop-version
scoop shell system # Set SCOOP_VERSION=system (this terminal only)
Environment Variables
| Variable | Description | Default |
|---|---|---|
SCOOP_HOME | Base directory | ~/.scoop |
SCOOP_VERSION | Override version (highest priority) | (unset) |
SCOOP_NO_AUTO | Disable auto-activation | (unset) |
SCOOP_ACTIVE | Currently active environment | (set by scoop) |
SCOOP_RESOLVE_MAX_DEPTH | Limit parent directory traversal | (unlimited) |
Disable Auto-Activation
export SCOOP_NO_AUTO=1
Custom Home Directory
export SCOOP_HOME=/custom/path
Network Filesystem Optimization
For slow network filesystems (NFS, SSHFS), limit directory traversal depth:
# Only check current directory and up to 3 parents
export SCOOP_RESOLVE_MAX_DEPTH=3
# Only check current directory (fastest)
export SCOOP_RESOLVE_MAX_DEPTH=0
Using with pyenv
Add scoop after pyenv in your shell config:
# ~/.zshrc
eval "$(pyenv init -)" # 1. pyenv first
eval "$(scoop init zsh)" # 2. scoop second (takes precedence)
Tab Completion
Shell integration includes completion for:
- Commands and subcommands
- Environment names
- Python versions
- Command options
Completion is automatically enabled by scoop init.
Supported Shells
| Shell | Status |
|---|---|
| Zsh | Full support (auto-activation, completion) |
| Bash | Full support (auto-activation, completion) |
| Fish | Full support (auto-activation, completion) |
| PowerShell | Planned (P3) |
Frequently Asked Questions
What’s the difference between scoop and pyenv?
While both tools help you manage Python, they focus on different parts of the workflow:
pyenv is primarily a version manager. It focuses on:
- Installing multiple versions of the Python interpreter (e.g., 3.9.0, 3.12.1)
- Switching between them globally or per folder
scoop is an environment and workflow manager powered by uv. It focuses on:
- Creating and managing isolated virtual environments
- Fast project-specific environment workflows
Summary: You might use pyenv to install Python 3.11 on your machine, but you use scoop to actually build and run your application within a lightning-fast virtual environment using that Python version.
Can I use scoop with conda environments?
Not directly. They serve different purposes and operate independently:
conda is a package and environment manager. It handles:
- Its own binaries and non-Python dependencies
- Heavy data science libraries (MKL, CUDA, cuDNN, etc.)
scoop is a lightweight environment manager powered by uv. It:
- Leverages your existing Python installations
- Creates fast, portable virtual environments
When to use what: For heavy data science requiring non-Python libraries → conda. For almost everything else → scoop (significantly faster and more portable).
How do I uninstall scoop completely?
To remove scoop from your system:
1. Delete the data folder
rm -rf ~/.scoop
2. Remove the shell hook
Edit your shell config file and remove the scoop init line:
| Shell | Config File | Line to Remove |
|---|---|---|
| Bash | ~/.bashrc | eval "$(scoop init bash)" |
| Zsh | ~/.zshrc | eval "$(scoop init zsh)" |
| Fish | ~/.config/fish/config.fish | scoop init fish | source |
3. (Optional) Remove config
rm -rf ~/.config/scoop
4. Restart your terminal
Does scoop work on Windows?
Yes! Since scoop is built on top of uv, it has excellent cross-platform support.
You can use it via:
- PowerShell (Recommended)
- Command Prompt (cmd.exe)
- Git Bash or WSL
Note: Make sure to follow the Windows-specific shell integration steps in the Installation guide.
Command Reference
Complete reference for all scoop commands.
Commands Overview
| Command | Aliases | Description |
|---|---|---|
scoop list | ls | List virtualenvs or Python versions |
scoop create | - | Create virtualenv |
scoop use | - | Set + activate environment |
scoop remove | rm, delete | Remove virtualenv |
scoop install | - | Install Python version |
scoop uninstall | - | Uninstall Python version |
scoop doctor | - | Diagnose installation |
scoop info | - | Show virtualenv details |
scoop migrate | - | Migrate from pyenv/conda/venvwrapper |
scoop lang | - | Get/set display language |
scoop init | - | Shell init script |
scoop completions | - | Completion script |
Global Options
Available for all commands:
| Option | Description |
|---|---|
-q, --quiet | Suppress all output |
--no-color | Disable colored output |
-h, --help | Show help message |
-V, --version | Show version |
Environment Variables
| Variable | Description | Default |
|---|---|---|
SCOOP_HOME | Base directory for scoop | ~/.scoop |
SCOOP_NO_AUTO | Disable auto-activation | (unset) |
SCOOP_LANG | Display language (en, ko) | System locale |
NO_COLOR | Disable colored output | (unset) |
Directory Layout
| Location | Purpose |
|---|---|
~/.scoop/virtualenvs/ | Virtual environments storage |
~/.scoop/version | Global default environment |
.scoop-version | Local environment preference |
.python-version | pyenv compatibility (fallback) |
.venv | Symlink to active environment (with --link) |
list
List all virtual environments or installed Python versions.
Aliases: ls
Usage
scoop list [options]
Options
| Option | Description |
|---|---|
--pythons | Show Python versions instead of virtualenvs |
--bare | Output names only (for scripting) |
--json | Output as JSON |
Examples
scoop list # List all virtualenvs
scoop list --pythons # List installed Python versions
scoop list --bare # Names only, one per line
scoop list --json # JSON output
create
Create a new virtual environment.
Usage
scoop create <name> [python-version]
Arguments
| Argument | Required | Default | Description |
|---|---|---|---|
name | Yes | - | Name for the new virtualenv |
python-version | No | 3 (latest) | Python version (e.g., 3.12, 3.11.8) |
Options
| Option | Description |
|---|---|
--force, -f | Overwrite existing virtualenv |
Examples
scoop create myproject 3.12 # Create with Python 3.12
scoop create webapp # Create with latest Python
scoop create myenv 3.11 --force # Overwrite if exists
use
Set a virtual environment for the current directory and activate it.
Usage
scoop use <name> [options]
scoop use system [options]
scoop use --unset [options]
Arguments
| Argument | Required | Description |
|---|---|---|
name | No | Name of the virtualenv, or system for system Python |
Options
| Option | Description |
|---|---|
--unset | Remove version file (local or global) |
--global, -g | Set as global default |
--link | Create .venv symlink for IDE compatibility |
--no-link | Do not create .venv symlink (default) |
Behavior
- Creates
.scoop-versionfile in current directory - Immediately activates the environment (if shell hook installed)
- With
--global: writes to~/.scoop/version - With
--link: creates.venv -> ~/.scoop/virtualenvs/<name>
Special Value: system
Using system as the name tells scoop to use the system Python:
scoop use system # Use system Python in this directory
scoop use system --global # Use system Python as global default
This writes the literal string system to the version file, which the shell hook interprets as “deactivate any virtual environment.”
The --unset Flag
Removes the version file entirely:
scoop use --unset # Delete .scoop-version in current directory
scoop use --unset --global # Delete ~/.scoop/version
After unsetting, scoop falls back to the next priority level in version resolution.
Examples
# Use a virtual environment in this directory
scoop use myproject
# Also create .venv symlink (for IDE support)
scoop use myproject --link
# Set global default environment
scoop use myproject --global
# Use system Python in this directory
scoop use system
# Use system Python globally
scoop use system --global
# Remove local version setting
scoop use --unset
# Remove global version setting
scoop use --unset --global
Version File Format
The .scoop-version file contains a single line with either:
- An environment name (e.g.,
myproject) - The literal string
system
$ cat .scoop-version
myproject
remove
Remove a virtual environment.
Aliases: rm, delete
Usage
scoop remove <name> [options]
Arguments
| Argument | Required | Description |
|---|---|---|
name | Yes | Name of the virtualenv to remove |
Options
| Option | Description |
|---|---|
--force, -f | Skip confirmation prompt |
Examples
scoop remove myproject # Remove with confirmation
scoop remove myproject --force # Remove without asking
scoop rm old-env -f # Using alias
install
Install a Python version.
Usage
scoop install [version] [options]
Arguments
| Argument | Required | Default | Description |
|---|---|---|---|
version | No | latest | Python version (e.g., 3.12, 3.11.8) |
Options
| Option | Description |
|---|---|
--latest | Install latest stable Python (default) |
--stable | Install oldest fully-supported Python (3.10) |
Version Resolution
- No argument or
--latest: installs latest Python 3.x --stable: installs Python 3.10 (oldest with active security support)3.12: installs latest 3.12.x patch3.12.3: installs exact version
Examples
scoop install # Install latest
scoop install --latest # Same as above
scoop install --stable # Install Python 3.10
scoop install 3.12 # Install latest 3.12.x
scoop install 3.12.3 # Install exact 3.12.3
Note: Python versions are managed by uv.
uninstall
Remove an installed Python version.
Usage
scoop uninstall <version>
Arguments
| Argument | Required | Description |
|---|---|---|
version | Yes | Python version to remove |
Examples
scoop uninstall 3.12 # Remove Python 3.12
scoop uninstall 3.11.8 # Remove specific version
doctor
Check scoop installation health and diagnose issues.
Usage
scoop doctor [options]
Options
| Option | Description |
|---|---|
-v, --verbose | Show more details (can repeat: -vv) |
--json | Output diagnostics as JSON |
--fix | Auto-fix issues where possible |
Checks Performed
- uv installation and version
- Shell integration status
- Environment integrity
- Path configuration
- Version file validity
Examples
scoop doctor # Quick health check
scoop doctor -v # Verbose diagnostics
scoop doctor --fix # Fix what can be fixed
scoop doctor --json # JSON output for scripting
info
Show detailed information about a virtual environment.
Usage
scoop info <name>
Arguments
| Argument | Required | Description |
|---|---|---|
name | Yes | Name of the virtualenv |
Examples
scoop info myproject # Show details for myproject
migrate
Migrate virtual environments from other tools (pyenv-virtualenv, virtualenvwrapper, conda).
Usage
# List migratable environments
scoop migrate list
# Migrate a single environment
scoop migrate @<name>
# Migrate all environments
scoop migrate --all
Subcommands
| Subcommand | Description |
|---|---|
list | List environments available for migration |
@<name> | Migrate a single environment by name |
--all | Migrate all discovered environments |
Supported Sources
| Source | Detection |
|---|---|
| pyenv-virtualenv | ~/.pyenv/versions/ (non-system virtualenvs) |
| virtualenvwrapper | $WORKON_HOME or ~/.virtualenvs/ |
| conda | conda info --envs |
Options
| Option | Description |
|---|---|
--json | Output as JSON |
--quiet | Suppress output |
--no-color | Disable colored output |
Examples
List Migratable Environments
$ scoop migrate list
📦 Migratable Environments
pyenv-virtualenv:
• myproject (Python 3.12.0)
• webapp (Python 3.11.8)
conda:
• ml-env (Python 3.10.4)
Migrate Single Environment
$ scoop migrate @myproject
✓ Migrated 'myproject' from pyenv-virtualenv
Source: ~/.pyenv/versions/myproject
Target: ~/.scoop/virtualenvs/myproject
Migrate All
$ scoop migrate --all
✓ Migrated 3 environments
• myproject (pyenv-virtualenv)
• webapp (pyenv-virtualenv)
• ml-env (conda)
JSON Output
$ scoop migrate list --json
{
"status": "success",
"data": {
"environments": [
{
"name": "myproject",
"source": "pyenv",
"python_version": "3.12.0"
}
]
}
}
Migration Process
- Discovery: Scans configured source paths for virtual environments
- Extraction: Identifies Python version and installed packages
- Recreation: Creates new scoop environment with same Python version
- Package Install: Reinstalls packages using
uv pip install - Cleanup: Original environment is preserved (not deleted)
Notes
- Original environments are not deleted during migration
- Package versions are preserved where possible
- Migration creates fresh environments using
uvfor improved performance
lang
Get or set the display language for scoop CLI messages.
Usage
# Show current language
scoop lang
# Set language
scoop lang <code>
# List supported languages
scoop lang --list
# Reset to system default
scoop lang --reset
Arguments
| Argument | Description |
|---|---|
<code> | Language code to set (e.g., en, ko) |
Options
| Option | Description |
|---|---|
--list | List all supported languages |
--reset | Reset to system default language |
--json | Output as JSON |
Supported Languages
| Code | Language |
|---|---|
en | English (default) |
ko | 한국어 (Korean) |
Language Detection Priority
SCOOP_LANGenvironment variable~/.config/scoop/config.tomlsetting- System locale (via
sys-locale) - Default:
en
Examples
Show Current Language
$ scoop lang
Current language: en (English)
Set Korean
$ scoop lang ko
✓ Language set to Korean (한국어)
List Languages
$ scoop lang --list
Supported languages:
en - English
ko - 한국어 (Korean)
Reset to System Default
$ scoop lang --reset
✓ Language reset to system default
JSON Output
$ scoop lang --json
{
"status": "success",
"data": {
"current": "ko",
"name": "한국어",
"source": "config"
}
}
Configuration
Language preference is stored in:
# ~/.config/scoop/config.toml
lang = "ko"
Environment Variable Override
# Temporarily use English regardless of config
SCOOP_LANG=en scoop list
# Set for current session
export SCOOP_LANG=ko
Notes
- CLI help text (
--help) remains in English (industry standard) - JSON output keys remain in English (machine-readable)
- Error messages, success messages, and prompts are translated
init
Output shell initialization script.
Usage
scoop init <shell>
Arguments
| Argument | Required | Description |
|---|---|---|
shell | Yes | Shell type: bash, zsh, fish, powershell |
Setup
Add to your shell configuration:
# Bash (~/.bashrc)
eval "$(scoop init bash)"
# Zsh (~/.zshrc)
eval "$(scoop init zsh)"
# Fish (~/.config/fish/config.fish)
eval (scoop init fish)
Features Enabled
- Auto-activation when entering directories with
.scoop-version - Tab completion for commands, environments, and options
- Wrapper function for
activate/deactivate/use
Examples
scoop init bash # Output bash init script
scoop init zsh # Output zsh init script
scoop init fish # Output fish init script
shell
Set shell-specific environment (current shell session only).
Unlike scoop use which writes to a file, scoop shell sets the SCOOP_VERSION environment variable for the current shell session only.
Usage
eval "$(scoop shell <name>)" # Bash/Zsh
scoop shell <name> | source # Fish
Note: If you have shell integration set up (
scoop init), theevalis automatic:scoop shell myenv # Works directly
Arguments
| Argument | Required | Description |
|---|---|---|
name | No | Environment name or system |
Options
| Option | Description |
|---|---|
--unset | Clear shell-specific environment |
--shell <SHELL> | Target shell type (auto-detected if not specified) |
Behavior
- Sets
SCOOP_VERSIONenvironment variable - If
nameis an environment: also outputs activation script - If
nameissystem: also outputs deactivation script --unset: outputsunset SCOOP_VERSION
Priority
SCOOP_VERSION has the highest priority in version resolution:
1. SCOOP_VERSION env var <- scoop shell (highest)
2. .scoop-version file <- scoop use
3. .python-version file <- pyenv compatibility
4. ~/.scoop/version <- scoop use --global
This means scoop shell overrides any file-based settings until:
- You run
scoop shell --unset - You close the terminal
Examples
# Use a specific environment in this terminal
scoop shell myproject
# Use system Python in this terminal
scoop shell system
# Clear the shell setting (return to file-based resolution)
scoop shell --unset
# Explicit shell type
scoop shell --shell fish myenv
Use Cases
Temporary Testing
# Currently using myproject
scoop shell testenv # Switch to testenv temporarily
python test.py # Test something
scoop shell myproject # Switch back
Override Project Settings
cd ~/project # Has .scoop-version = projectenv
scoop shell system # Use system Python anyway
python --version # System Python
scoop shell --unset # Back to projectenv
completions
Generate shell completion script.
Usage
scoop completions <shell>
Arguments
| Argument | Required | Description |
|---|---|---|
shell | Yes | Shell type: bash, zsh, fish, powershell |
Examples
scoop completions bash # Output bash completions
scoop completions zsh # Output zsh completions
scoop completions fish # Output fish completions
Tip: Usually you don’t need this separately -
scoop initincludes completions.
Contributing
Guide for contributing to scoop development.
Prerequisites
Setup
# Clone the repository
git clone https://github.com/ai-screams/scoop-uv.git
cd scoop-uv
# Install prek (Rust-native pre-commit alternative)
uv tool install prek
# or: cargo install prek
# Install git hooks
prek install
# Build
cargo build
# Run tests
cargo test
Project Structure
src/
├── main.rs # Entry point
├── lib.rs # Library root
├── error.rs # Error types (ScoopError)
├── paths.rs # Path utilities
├── validate.rs # Name/version validation
├── uv/ # uv client wrapper
│ ├── mod.rs
│ └── client.rs
├── core/ # Business logic
│ ├── mod.rs
│ ├── virtualenv.rs # VirtualenvService
│ ├── version.rs # VersionService
│ ├── metadata.rs # Metadata structs
│ └── doctor.rs # Health diagnostics
├── cli/ # CLI layer
│ ├── mod.rs # Cli struct, Commands enum
│ └── commands/ # Command handlers
│ ├── mod.rs
│ ├── list.rs
│ ├── create.rs
│ ├── use_env.rs
│ ├── remove.rs
│ ├── install.rs
│ ├── doctor.rs
│ └── ...
├── shell/ # Shell integration
│ ├── mod.rs
│ ├── bash.rs
│ └── zsh.rs
└── output/ # Output formatting
├── mod.rs
└── spinner.rs
docs/ # Public documentation
.docs/ # Internal technical docs
tests/ # Integration tests
Common Commands
Build and Run
cargo build # Debug build
cargo build --release # Release build (optimized)
cargo run -- --help # Show help
cargo run -- list # Run commands
cargo run -- doctor # Check setup health
Quick Quality Check
# All checks at once (recommended before commit)
cargo fmt --check && cargo clippy --all-targets --all-features -- -D warnings && cargo test
For detailed guides, see:
- Testing - Comprehensive testing guide
- Code Quality - Formatting, linting, pre-commit hooks
Architecture
Key Services
VirtualenvService (src/core/virtualenv.rs)
- Manages virtualenvs in
~/.scoop/virtualenvs/ - Wraps uv commands for venv creation
VersionService (src/core/version.rs)
- Manages
.scoop-versionfiles - Resolves current directory to active environment
Doctor (src/core/doctor.rs)
- Health diagnostics for scoop setup
- Checks uv, shell integration, paths, environments
UvClient (src/uv/client.rs)
- Wrapper for
uvCLI commands - Python version management
Shell Integration
Shell scripts are embedded in Rust code:
src/shell/bash.rs- Bash init scriptsrc/shell/zsh.rs- Zsh init script
Key components:
- Wrapper function - Intercepts
use/activate/deactivate - Hook function - Auto-activation on directory change
- Completion function - Tab completion
Adding a New Command
- Define command in
src/cli/mod.rs:
#![allow(unused)] fn main() { #[derive(Subcommand)] pub enum Commands { // ... MyCommand { #[arg(short, long)] option: bool, }, } }
- Create handler in
src/cli/commands/my_command.rs:
#![allow(unused)] fn main() { pub fn execute(output: &Output, option: bool) -> Result<()> { // Implementation Ok(()) } }
-
Export in
src/cli/commands/mod.rs -
Wire up in
src/main.rs -
Add shell completion in
src/shell/{bash,zsh}.rs
Testing
Unit Tests
Located within source files:
#![allow(unused)] fn main() { #[cfg(test)] mod tests { use super::*; #[test] fn test_something() { // ... } } }
Integration Tests
Located in tests/:
#![allow(unused)] fn main() { use assert_cmd::Command; #[test] fn test_cli_command() { Command::cargo_bin("scoop") .unwrap() .args(["list"]) .assert() .success(); } }
Release Process
Releases are automated via release-plz:
- Create PR with changes
- Merge to main
- release-plz creates release PR
- Merge release PR to publish to crates.io
Internal Documentation
See .docs/ for internal technical references:
TECHNICAL_REFERENCE.md- Implementation detailsSHELL_GOTCHAS.md- Shell integration pitfallsIMPLEMENTATION_PLAN.md- Development roadmapbrand/brand.md- Brand guidelines
Code Style
- Follow Rust conventions
- Run
cargo fmtbefore committing - Keep functions small and focused
- Document public APIs with
///comments - Use
thiserrorfor error types - Korean error messages with solutions (per CLAUDE.md)
Translation Guide
This document provides guidelines for contributing translations to scoop.
Current Status
For the latest translation status, see:
- Issue #42: i18n Translation Tracking
- Run
scoop lang --listto see currently supported languages
Contribution Process
Step 1: Fork and Clone
git clone https://github.com/YOUR_USERNAME/scoop-uv.git
cd scoop-uv
Step 2: Add Translations
Edit locales/app.yml and add your language to every key:
create.success:
en: "Created '%{name}' environment"
ko: "'%{name}' 환경 생성됨"
pt-BR: "Ambiente '%{name}' criado"
{ lang }: "Your translation here" # Add your language code and translation
Important:
- Add translations to ALL ~106 keys
- Keep placeholder syntax exactly:
%{name},%{version}, etc. - Preserve special characters:
→, quotes, backticks
Step 3: Register Language
Edit src/i18n.rs and add your language to SUPPORTED_LANGS:
#![allow(unused)] fn main() { pub const SUPPORTED_LANGS: &[(&str, &str)] = &[ ("en", "English"), ("ko", "한국어"), ("pt-BR", "Português (Brasil)"), ("{lang}", "Your Language Name"), // Add your language ]; }
Language Code Format:
- Use BCP 47 format
- Simple languages:
ja,fr,es,de,it - Regional variants:
pt-BR,zh-CN,zh-TW,es-MX
Step 4: Test Locally
# Build and test
cargo build
cargo test
# Test your language (replace {lang} with your language code)
SCOOP_LANG={lang} ./target/debug/scoop --help
SCOOP_LANG={lang} ./target/debug/scoop lang
Step 5: Create Pull Request
Required files in PR:
-
locales/app.yml- All 106 keys translated -
src/i18n.rs- Language registered in SUPPORTED_LANGS
PR Title Format:
docs(i18n): add {Language Name} translation
Style Guidelines
Philosophy: Your Language, Your Style
We trust translators. You know your language and community best.
- Word choice is yours — Pick terms that feel natural to native speakers
- Creativity welcome — Witty expressions are fine if they’re clear and widely understood
- Casual over formal — scoop is a friendly CLI tool, not enterprise software
General Principles
- Concise: CLI messages should be short and clear
- Natural: Use natural phrasing, not word-for-word translation
- Casual: Friendly, approachable tone — like talking to a colleague
- Clear: Wit is great, but clarity comes first
Tone Examples
# Too formal (avoid)
"The environment has been successfully created."
# Too robotic (avoid)
"Environment creation: complete."
# Good - casual and clear
"Created 'myenv' — ready to go!"
"'myenv' is ready"
Message Types
| Type | English Example | Guidance |
|---|---|---|
| Progress | “Installing…” | Use progressive/ongoing form |
| Success | “Created ‘myenv’” | Completion — feel free to add flair |
| Error | “Can’t find ‘myenv’” | Clear and actionable |
| Hint | “→ Create: scoop create…” | Helpful, not lecturing |
Translator’s Discretion
These decisions are up to you:
- Vocabulary: Choose words that resonate with your community
- Idioms: Use local expressions if they fit naturally
- Humor: Light wit is welcome (e.g., ice cream puns if appropriate)
- Formality level: Lean casual, but match your culture’s CLI norms
Only requirement: The meaning must be clear to users.
Technical Terms
For technical vocabulary:
- Check your community — What do Python developers in your language use?
- Consistency — Pick one term and stick with it throughout
- Loanwords OK — If your community uses English terms (e.g., “install”), that’s fine
Tip: Study existing translations in locales/app.yml for reference, but don’t feel bound by them.
Glossary
Do NOT Translate
These terms should remain in English in all languages:
| Term | Reason |
|---|---|
scoop | Brand name |
uv | Tool name |
pyenv | Tool name |
conda | Tool name |
virtualenv | Technical term |
virtualenvwrapper | Tool name |
Python | Language name |
shell | Technical term (bash, zsh, fish) |
JSON | Format name |
PATH | Environment variable |
pip | Tool name |
Commands - Never Translate
All commands and code examples must stay in English:
# WRONG - Command translated
hint: "→ Create: {translated_command} myenv 3.12"
# CORRECT - Only description translated
hint: "→ {translated_word}: scoop create myenv 3.12"
Common Terms to Translate
These are core concepts you’ll need to translate. Reference existing translations for consistency:
| English | What to look for |
|---|---|
| environment | Your language’s term for “environment” |
| create | Common verb for “make/create” |
| remove/delete | Common verb for “delete/remove” |
| install | Standard software installation term |
| uninstall | Standard software removal term |
| activate | Term for “enable/turn on” |
| deactivate | Term for “disable/turn off” |
| migrate | IT term for migration (often kept as loanword) |
| version | Your language’s term for “version” |
| path | Your language’s term for file path |
| error | Your language’s term for “error” |
| success | Your language’s term for “success” |
Tip: Check how these terms are translated in existing translations for reference.
Ice Cream Metaphor (README only)
scoop uses ice cream metaphors in documentation:
| Term | Meaning | Guidance |
|---|---|---|
| scoop | The tool | Always keep as “scoop” |
| flavor | virtualenv | Translate if the metaphor works in your language |
| freezer | ~/.scoop/ directory | Translate if the metaphor works |
Note: The metaphor is mainly in README.md, not in CLI messages (locales/app.yml).
File Structure
locales/app.yml
# Categories in order:
# 1. lang.* - Language command messages
# 2. create.* - Create command messages
# 3. remove.* - Remove command messages
# 4. list.* - List command messages
# 5. use.* - Use command messages
# 6. install.* - Install command messages
# 7. uninstall.* - Uninstall command messages
# 8. migrate.* - Migrate command messages
# 9. error.* - Error messages
# 10. suggestion.* - Suggestion/hint messages
src/i18n.rs
#![allow(unused)] fn main() { // Language detection priority: // 1. SCOOP_LANG environment variable // 2. Config file (~/.config/scoop/config.toml) // 3. System locale // 4. Default: "en" pub const SUPPORTED_LANGS: &[(&str, &str)] = &[ ("en", "English"), // ... existing languages // Add new languages here ]; }
Common Mistakes
1. Missing SUPPORTED_LANGS Registration
Symptom: Translation exists but scoop lang {code} doesn’t work
Fix: Add language to src/i18n.rs SUPPORTED_LANGS
2. Broken Placeholders
# WRONG - Missing placeholder
error: "Cannot find environment"
# CORRECT - Placeholder preserved
error: "Cannot find '%{name}' environment"
3. Translating Commands
# WRONG - Command translated
hint: "→ List: {translated} list"
# CORRECT - Only label translated
hint: "→ {Translated Label}: scoop list"
4. Inconsistent Key Coverage
All languages must have ALL keys. Missing keys fall back to English.
Testing Checklist
Before submitting PR:
- All 106 keys translated
-
All placeholders preserved (
%{name},%{version}, etc.) - Language registered in SUPPORTED_LANGS
-
cargo buildsucceeds -
cargo testpasses -
SCOOP_LANG={code} scoop langshows your language - Messages display correctly in terminal
Questions?
- Open an issue: GitHub Issues
- See existing translations for reference:
locales/app.yml
Architecture
scoop is built in Rust using a modular architecture.
Module Structure
src/
├── cli/ # Command-line interface
│ ├── mod.rs # Cli struct, Commands enum, ShellType
│ └── commands/ # Individual command handlers
├── core/ # Domain logic
│ ├── doctor.rs # Health diagnostics
│ ├── metadata.rs # Virtualenv metadata (JSON)
│ ├── version.rs # Version file resolution
│ └── virtualenv.rs # Virtualenv entity
├── shell/ # Shell integration
│ ├── mod.rs # Shell module exports
│ ├── bash.rs # Bash init script
│ ├── zsh.rs # Zsh init script
│ └── fish.rs # Fish init script
├── output/ # Terminal UI and JSON output
├── uv/ # uv CLI wrapper
├── error.rs # ScoopError enum
├── paths.rs # Path utilities
└── validate.rs # Input validation
Key Components
CLI Layer (cli/)
- Uses clap for argument parsing
Clistruct defines global optionsCommandsenum defines subcommands- Each command has an
executefunction incommands/
Core Layer (core/)
| Module | Purpose |
|---|---|
doctor | Health check system with Check trait |
metadata | JSON metadata for virtualenvs |
version | Version file discovery and parsing |
virtualenv | Virtualenv entity and operations |
Shell Layer (shell/)
Generates shell scripts for integration:
init_script()- Returns shell initialization code- Wrapper function for
scoopcommand - Auto-activation hooks
- Tab completion definitions
Output Layer (output/)
Handles terminal output formatting:
- Colored output using owo-colors
- JSON output for scripting
- Progress indicators with indicatif
UV Layer (uv/)
Wraps the uv CLI for Python/virtualenv operations:
- Python installation
- Virtualenv creation
- Version listing
Design Patterns
Shell Eval Pattern
The CLI outputs shell code to stdout, which the shell evaluates:
# User runs
scoop activate myenv
# CLI outputs
export VIRTUAL_ENV="/Users/x/.scoop/virtualenvs/myenv"
export PATH="/Users/x/.scoop/virtualenvs/myenv/bin:$PATH"
export SCOOP_ACTIVE="myenv"
# Shell wrapper evaluates this output
eval "$(command scoop activate myenv)"
This pattern is used by pyenv, rbenv, and other version managers.
Error Handling
Uses thiserror for error types:
#![allow(unused)] fn main() { #[derive(Debug, Error)] pub enum ScoopError { #[error("가상환경 '{name}'을(를) 찾을 수 없습니다")] VirtualenvNotFound { name: String }, // ... } }
Path Management
Centralizes path logic in paths.rs:
scoop_home()- ReturnsSCOOP_HOMEor~/.scoopvirtualenvs_dir()- Returns virtualenvs directoryversion_file()- Returns global version file path
Data Flow
User Command
│
▼
CLI Parser (clap)
│
▼
Command Handler (cli/commands/)
│
├──► Core Logic (core/)
│ │
│ ▼
│ UV Wrapper (uv/)
│
▼
Output Formatter (output/)
│
▼
stdout/stderr
Dependencies
| Crate | Purpose |
|---|---|
| clap | Argument parsing |
| serde | Serialization |
| thiserror | Error types |
| owo-colors | Terminal colors |
| indicatif | Progress bars |
| dirs | Home directory |
| which | Binary lookup |
Testing
Comprehensive guide for testing scoop.
Quick Reference
cargo test # Run all tests
cargo test json # Run tests containing "json"
cargo test -- --nocapture # Show println! output
cargo clippy -- -D warnings # Lint check
Test Structure
tests/
└── cli.rs # CLI integration tests
src/
├── error.rs # Unit tests for error types
├── validate.rs # Unit tests for validation
├── paths.rs # Unit tests for path utilities
├── output/
│ └── json.rs # Unit tests for JSON output
├── core/
│ ├── virtualenv.rs # Unit tests for virtualenv service
│ ├── version.rs # Unit tests for version service
│ ├── metadata.rs # Unit tests for metadata
│ └── doctor.rs # Unit tests for doctor
├── shell/
│ ├── bash.rs # Shell script tests
│ └── zsh.rs # Shell script tests
└── uv/
└── client.rs # Unit tests for uv client
Running Tests
All Tests
# Run all tests
cargo test
# Run with all features enabled
cargo test --all-features
# Run in release mode (faster execution)
cargo test --release
Filtered Tests
# By name pattern
cargo test json # Tests containing "json"
cargo test error # Tests containing "error"
cargo test virtualenv # Tests containing "virtualenv"
# By module path
cargo test output::json # Tests in output/json.rs
cargo test error::tests # Tests in error.rs
cargo test core::version # Tests in core/version.rs
cargo test cli::commands # Tests in cli/commands/
# Single test
cargo test test_json_response_success_creates_correct_status
Test Output
# Show stdout/stderr (println!, dbg!, etc.)
cargo test -- --nocapture
# Show test names as they run
cargo test -- --nocapture --test-threads=1
# Only show failed tests
cargo test -- --quiet
Debugging
# Run single-threaded (easier to debug)
cargo test -- --test-threads=1
# Run ignored tests
cargo test -- --ignored
# Run specific test with output
cargo test test_name -- --nocapture --test-threads=1
Test Categories
Unit Tests (239 tests)
Located within source files using #[cfg(test)]:
#![allow(unused)] fn main() { #[cfg(test)] mod tests { use super::*; #[test] fn test_something() { assert_eq!(1 + 1, 2); } } }
Key test modules:
| Module | Tests | Coverage |
|---|---|---|
error::tests | 54 | Error types, codes, suggestions |
output::json::tests | 35 | JSON serialization, edge cases |
validate::tests | 30 | Name/version validation |
core::version::tests | 18 | Version file resolution |
core::virtualenv::tests | 12 | Virtualenv service |
paths::tests | 16 | Path utilities |
shell::*::tests | 14 | Shell scripts (shellcheck) |
Integration Tests (41 tests)
Located in tests/cli.rs:
# Run only integration tests
cargo test --test cli
Categories:
- Error cases - Invalid inputs, missing arguments
- Output format - Help, version, JSON output
- Command behavior - list, create, use, remove
Some tests are marked #[ignore] because they require uv installed:
# Run ignored tests (requires uv)
cargo test -- --ignored
Doc Tests (6 tests)
Examples in documentation comments:
#![allow(unused)] fn main() { /// Validates environment name. /// /// # Examples /// /// ``` /// use scoop_uv::validate::is_valid_env_name; /// assert!(is_valid_env_name("myenv")); /// assert!(!is_valid_env_name("123bad")); /// ``` pub fn is_valid_env_name(name: &str) -> bool { ... } }
# Run only doc tests
cargo test --doc
Property Tests
Using proptest for randomized testing:
#![allow(unused)] fn main() { use proptest::prelude::*; proptest! { #[test] fn prop_valid_names_accepted(name in "[a-zA-Z][a-zA-Z0-9_-]{0,49}") { assert!(is_valid_env_name(&name)); } } }
Located in src/validate.rs.
Writing Tests
Unit Test Template
#![allow(unused)] fn main() { #[cfg(test)] mod tests { use super::*; // ======================================== // Test Group Name // ======================================== #[test] fn test_function_name_expected_behavior() { // Arrange let input = "test input"; // Act let result = function_under_test(input); // Assert assert_eq!(result, expected_value); } #[test] fn test_function_name_edge_case() { let result = function_under_test(""); assert!(result.is_err()); } } }
Integration Test Template
#![allow(unused)] fn main() { // tests/cli.rs use assert_cmd::Command; use predicates::prelude::*; #[test] fn test_command_success() { Command::cargo_bin("scoop") .unwrap() .args(["list"]) .assert() .success() .stdout(predicate::str::contains("expected output")); } #[test] fn test_command_failure() { Command::cargo_bin("scoop") .unwrap() .args(["use", "nonexistent"]) .assert() .failure() .stderr(predicate::str::contains("not found")); } }
JSON Output Testing
#![allow(unused)] fn main() { #[test] fn test_json_serialization() { let data = MyData { field: "value".into() }; let json = serde_json::to_string(&data).unwrap(); // Check JSON structure let parsed: serde_json::Value = serde_json::from_str(&json).unwrap(); assert_eq!(parsed["field"], "value"); } #[test] fn test_optional_field_omitted() { let data = MyData { optional: None, .. }; let json = serde_json::to_string(&data).unwrap(); // skip_serializing_if = "Option::is_none" assert!(!json.contains("optional")); } }
Test Utilities
Located in src/test_utils.rs:
#![allow(unused)] fn main() { use scoop_uv::test_utils::*; #[test] fn test_with_temp_environment() { with_temp_scoop_home(|temp_dir| { // SCOOP_HOME is set to temp_dir // Cleanup happens automatically }); } #[test] fn test_with_mock_venv() { with_temp_scoop_home(|temp_dir| { create_mock_venv("myenv", Some("3.12")); // Virtual environment created at temp_dir/virtualenvs/myenv }); } }
Coverage
Using cargo-tarpaulin
# Install
cargo install cargo-tarpaulin
# Run with HTML report
cargo tarpaulin --out Html --output-dir coverage
# Run with specific target
cargo tarpaulin --out Html --output-dir coverage --packages scoop-uv
# View report
open coverage/tarpaulin-report.html
Using cargo-llvm-cov
# Install
cargo install cargo-llvm-cov
# Run with HTML report
cargo llvm-cov --html
# View report
open target/llvm-cov/html/index.html
CI/CD Testing
Tests run automatically on:
- Every push to any branch
- Every pull request
GitHub Actions workflow (.github/workflows/ci.yml):
- name: Run tests
run: cargo test --all-features
- name: Run clippy
run: cargo clippy --all-targets -- -D warnings
Troubleshooting
Test Hangs
# Run single-threaded to identify hanging test
cargo test -- --test-threads=1
Flaky Tests
# Run specific test multiple times
for i in {1..10}; do cargo test test_name || break; done
Environment Issues
# Clear test artifacts
cargo clean
# Rebuild and test
cargo test
Shell Tests Fail
ShellCheck must be installed for shell script tests:
# macOS
brew install shellcheck
# Linux
apt install shellcheck
Best Practices
- Test naming:
test_<function>_<scenario>_<expected> - Arrange-Act-Assert: Clear test structure
- One assertion per test: When practical
- Test edge cases: Empty, unicode, special chars, boundaries
- No test interdependencies: Each test should be isolated
- Fast tests: Mock external dependencies
Code Quality
Comprehensive guide for maintaining code quality in scoop.
Quick Reference
# Format code
cargo fmt
# Lint check
cargo clippy --all-targets --all-features -- -D warnings
# All checks (pre-commit style)
cargo fmt --check && cargo clippy --all-targets --all-features -- -D warnings && cargo test
# Pre-commit hooks
prek run --all-files
Formatting (rustfmt)
Configuration
Located in rustfmt.toml:
edition = "2024"
max_width = 100
use_small_heuristics = "Default"
Commands
# Auto-format all files
cargo fmt
# Check formatting (CI mode, no changes)
cargo fmt --check
# Format specific file
rustfmt src/main.rs
# Show diff instead of applying
cargo fmt -- --check --diff
IDE Integration
VS Code (rust-analyzer):
{
"[rust]": {
"editor.formatOnSave": true
}
}
JetBrains (RustRover/CLion):
- Settings → Languages → Rust → Rustfmt → Run on save
Linting (Clippy)
Basic Usage
# Standard lint check
cargo clippy
# Treat warnings as errors (CI mode)
cargo clippy -- -D warnings
# All targets (including tests, examples)
cargo clippy --all-targets
# All features enabled
cargo clippy --all-features
# Full CI check
cargo clippy --all-targets --all-features -- -D warnings
Lint Categories
# Enable specific lint category
cargo clippy -- -W clippy::pedantic
# Deny specific lint
cargo clippy -- -D clippy::unwrap_used
# Allow specific lint
cargo clippy -- -A clippy::too_many_arguments
Common Lints
| Lint | Severity | Description |
|---|---|---|
clippy::unwrap_used | Warn | Use ? or expect() instead |
clippy::panic | Warn | Avoid panic in library code |
clippy::todo | Warn | Remove before release |
clippy::dbg_macro | Warn | Remove debug macros |
clippy::print_stdout | Warn | Use logging instead |
Fixing Lints
# Auto-fix where possible
cargo clippy --fix
# Allow fixes that change behavior
cargo clippy --fix --allow-dirty --allow-staged
Suppressing Lints
#![allow(unused)] fn main() { // Single line #[allow(clippy::too_many_arguments)] fn complex_function(...) {} // Entire module #![allow(clippy::module_inception)] // With explanation #[allow(clippy::unwrap_used)] // Safe: validated in parse() fn get_value() {} }
Pre-commit Hooks (prek)
Setup
# Install prek
cargo install prek
# or
uv tool install prek
# Install hooks in repository
prek install
Configuration
Located in .pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: cargo-fmt
name: cargo fmt
entry: cargo fmt --all --
language: system
types: [ rust ]
pass_filenames: false
- id: cargo-clippy
name: cargo clippy
entry: cargo clippy --all-targets --all-features -- -D warnings
language: system
types: [ rust ]
pass_filenames: false
- id: cargo-check
name: cargo check
entry: cargo check --all-targets
language: system
types: [ rust ]
pass_filenames: false
Usage
# Run all hooks on staged files
prek run
# Run all hooks on all files
prek run --all-files
# Run specific hook
prek run cargo-fmt
prek run cargo-clippy
# Run multiple specific hooks
prek run cargo-fmt cargo-clippy
# Skip hooks (emergency only!)
git commit --no-verify
Available Hooks
| Hook | Description | When |
|---|---|---|
cargo-fmt | Code formatting | Pre-commit |
cargo-clippy | Linting | Pre-commit |
cargo-check | Type checking | Pre-commit |
trailing-whitespace | Remove trailing spaces | Pre-commit |
end-of-file-fixer | Ensure newline at EOF | Pre-commit |
check-toml | Validate TOML files | Pre-commit |
check-yaml | Validate YAML files | Pre-commit |
CI Pipeline
GitHub Actions
Located in .github/workflows/ci.yml:
name: CI
on: [ push, pull_request ]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-action@stable
with:
components: rustfmt, clippy
- name: Format check
run: cargo fmt --all -- --check
- name: Clippy
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Test
run: cargo test --all-features
Local CI Simulation
# Run exactly what CI runs
cargo fmt --check && \
cargo clippy --all-targets --all-features -- -D warnings && \
cargo test --all-features
Code Style Guidelines
Naming Conventions
| Item | Convention | Example |
|---|---|---|
| Modules | snake_case | version_file |
| Functions | snake_case | get_version() |
| Types | PascalCase | VirtualenvService |
| Constants | SCREAMING_SNAKE | MAX_NAME_LENGTH |
| Lifetimes | short lowercase | 'a, 'src |
Documentation
/// Creates a new virtual environment. /// /// # Arguments /// /// * `name` - Environment name (must be valid) /// * `python` - Python version (e.g., "3.12") /// /// # Returns /// /// Path to the created environment. /// /// # Errors /// /// Returns [`ScoopError::InvalidEnvName`] if name is invalid. /// /// # Examples /// /// ``` /// # fn main() -> Result<(), Box<dyn std::error::Error>> { /// let path = create_env("myenv", "3.12")?; /// # Ok(()) /// # } /// ``` pub fn create_env(name: &str, python: &str) -> Result<PathBuf> { // ... }
Error Handling
#![allow(unused)] fn main() { // Good: Use ? operator fn process() -> Result<()> { let file = File::open(path)?; let data = read_data(&file)?; Ok(()) } // Good: Contextual errors fn process() -> Result<()> { let file = File::open(path) .map_err(|e| ScoopError::Io(e))?; Ok(()) } // Avoid: unwrap() in library code fn bad() { let file = File::open(path).unwrap(); // Bad } // OK: expect() with explanation fn acceptable() { let home = dirs::home_dir() .expect("home directory must exist"); } }
Import Organization
#![allow(unused)] fn main() { // 1. Standard library use std::collections::HashMap; use std::path::PathBuf; // 2. External crates use clap::Parser; use serde::Serialize; use thiserror::Error; // 3. Local modules use crate::error::Result; use crate::paths; }
Security Considerations
Dependency Auditing
# Install cargo-audit
cargo install cargo-audit
# Run audit
cargo audit
# Fix vulnerabilities
cargo audit fix
MSRV (Minimum Supported Rust Version)
- Current MSRV: 1.85
- Defined in
Cargo.toml:[package] rust-version = "1.85"
Unsafe Code
- Avoid
unsafeunless absolutely necessary - Document safety invariants
- Use
#![forbid(unsafe_code)]in library crates
Performance
Profiling
# Build with debug info for release
cargo build --release
# Use flamegraph
cargo install flamegraph
cargo flamegraph --bin scoop -- list
Benchmarks
# Run benchmarks (if defined)
cargo bench
# Using criterion
cargo bench --bench my_benchmark
Continuous Improvement
Regular Checks
# Weekly dependency update check
cargo outdated
# Security audit
cargo audit
# MSRV check
cargo msrv verify
Upgrade Dependencies
# Update Cargo.lock
cargo update
# Upgrade to latest compatible versions
cargo upgrade # requires cargo-edit
Troubleshooting
Clippy False Positives
#![allow(unused)] fn main() { // Silence with explanation #[allow(clippy::needless_return)] fn explicit_return() -> i32 { return 42; // Intentional for readability } }
Format Conflicts
#![allow(unused)] fn main() { // Skip formatting for specific block #[rustfmt::skip] const MATRIX: [[i32; 3]; 3] = [ [1, 0, 0], [0, 1, 0], [0, 0, 1], ]; }
CI vs Local Differences
# Ensure same toolchain as CI
rustup update stable
rustup default stable
# Check Rust version
rustc --version
Summary Checklist
Before committing:
-
cargo fmt- Code formatted -
cargo clippy -- -D warnings- No lint warnings -
cargo test- All tests pass -
cargo doc- Documentation builds -
No
todo!()ordbg!()left in code - Public APIs documented
- Error messages are helpful