uv is now the de facto default Python package manager. I have already deleted all pythons from my system except for the one that has to be installed for other packages in brew.
Unfortunately, Claude Code often ignores instructions in CLAUDE.md files to use uv run python instead of plain python commands. Even with clear documentation stating “always use uv”, Claude Code will attempt to run python directly, leading to “command not found” errors in projects that rely on uv for Python environment management.
The built-in Claude Code hooks and environment variable settings also don’t reliably solve this issue due to shell context limitations.
The reason is that Claude (and most other AI models) take time to catch up to such changes, because their learning horizon is longer, up to months to years. Somebody will need to include this information explicitly in the training data.
Until then, we can prevent wasting tokens by mapping python and python3 to uv.
I personally don’t want to map these globally, because a lot of other packages might depend on system installed pythons, like brew packages, gcloud CLI and so on.
Because of that, I map them at the project level, using direnv:
An OK-ish solution: direnv + dynamic wrapper scripts
We can force Claude Code (and any developer) to use uv run python by dynamically creating wrapper scripts in a .envrc file that direnv automatically loads when entering the project directory.
This will override python and python3 to map to uv run python, and also print a nice message to the model:
Use "uv run python ..." instead of "python ..." idiot.
This is probably not the best solution, but it is a solution. Feel free to suggest a better one.
Step 1: Install direnv
# macOS
brew install direnv
# Ubuntu/Debiansudo apt install direnv
# Add to your shell (bash/zsh)echo'eval "$(direnv hook zsh)"'>> ~/.zshrc # or ~/.bashrcsource ~/.zshrc # or restart terminal
Step 2: Setup direnv with dynamic wrapper scripts
# Create .envrc file in project rootcat> .envrc <<'EOF'
#!/bin/bash
# Create temporary bin directory for python overrides
TEMP_BIN_DIR="$PWD/.direnv/bin"
mkdir -p "$TEMP_BIN_DIR"
# Create python wrapper scripts
cat > "$TEMP_BIN_DIR/python" << 'INNER_EOF'
#!/bin/bash
echo "Use \"uv run python ...\" instead of \"python ...\" idiot"
exec uv run python "$@"
INNER_EOF
cat > "$TEMP_BIN_DIR/python3" << 'INNER_EOF'
#!/bin/bash
echo "Use \"uv run python ...\" instead of \"python3 ...\" idiot"
exec uv run python "$@"
INNER_EOF
# Make them executable
chmod +x "$TEMP_BIN_DIR/python" "$TEMP_BIN_DIR/python3"
# Add to PATH
export PATH="$TEMP_BIN_DIR:$PATH"
EOF
# Allow direnv to load this configuration
direnv allow