Entries for July 13, 2025
-
-
Read more here: solmaz.io/log/2025/07/13… -
Workaround for Claude Code running `python` instead of `uv`
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 inbrew.Unfortunately, Claude Code often ignores instructions in
CLAUDE.mdfiles to useuv run pythoninstead of plainpythoncommands. Even with clear documentation stating “always use uv”, Claude Code will attempt to runpythondirectly, 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
pythonandpython3touv.I personally don’t want to map these globally, because a lot of other packages might depend on system installed
pythons, likebrewpackages,gcloudCLI 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 pythonby dynamically creating wrapper scripts in a.envrcfile that direnv automatically loads when entering the project directory.This will override
pythonandpython3to map touv 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/Debian sudo apt install direnv # Add to your shell (bash/zsh) echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc # or ~/.bashrc source ~/.zshrc # or restart terminalStep 2: Setup direnv with dynamic wrapper scripts
# Create .envrc file in project root cat > .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 allowStep 3: Update .gitignore
# Add direnv generated files to .gitignore echo "# direnv generated files" >> .gitignore echo ".direnv/" >> .gitignoreStep 4: Update documentation
Add to your
CLAUDE.mdsomething like this:## Python Package Management with uv **IMPORTANT**: This project uses `uv` as the Python package manager. ALWAYS use `uv` instead of `pip` or `python` directly. DO NOT RUN: ```bash python my_script.py # OR chmod +x my_script.py ./my_script.py ``` INSTEAD, RUN: ```bash uv run my_script.py ``` ### Key uv Commands - **Run Python code**: `uv run <script.py>` (NOT `python <script.py>`) - **Run module**: `uv run -m <module>` (e.g., `uv run -m pytest`) - **Add dependencies**: `uv add <package>` (e.g., `uv add requests`) - **Add dev dependencies**: `uv add --dev <package>` - **Remove dependencies**: `uv remove <package>` - **Install all dependencies**: `uv sync` - **Update lock file**: `uv lock` - **Run with specific package**: `uv run --with <package> <command>`How It Works
- direnv automatically loads
.envrcwhen youcdinto the project directory .envrcdynamically creates executable wrapper scripts in.direnv/bin/- Scripts display a helpful message and redirect to
uv run python .direnv/bin/is prepended to PATH, overriding system python commands- Works for any shell session in the directory (Claude Code, terminal, IDE)
To see if it works:
cd your-project/ python -c "print('Hello World')" # Shows message, uses uv python3 --version # Shows message, uses uvLet me know if this doesn’t work for you, or if you find a better solution.
- direnv automatically loads