The Problem
When Claude Code needs Python for ad-hoc tasks (e.g., parsing Excel files, reading PDFs, quick data analysis) it uses whatever Python is available. This can cause issues:
- No isolation: packages installed to user site-packages
- Version uncertainty: using whatever Python happened to be installed
- Dependency conflicts: risk of polluting project-specific environments
- Ambiguity: no clear boundary between ad-hoc work and project venvs
I wanted a dedicated, managed environment for Claude Code’s throwaway tasks that wouldn’t interfere with anything else.
The Solution
A uv-managed Python environment specifically for Claude Code’s ad-hoc work, invoked via a distinct shell command.
Why uv?
brew install uv- Fast: installs packages in seconds, not minutes
- Modern: handles both package management and environment isolation
- Simple: one tool instead of virtualenv + pip + pyenv
- Flex: all the cool kids use it 😎
Project Setup
Create a dedicated project directory:
mkdir -p /casa/dev/claude-code
cd /casa/dev/claude-code
uv initThe pyproject.toml declares whatever dependencies your agent might need:
[project]
name = "claude-adhoc"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
# Data/Files
"pandas",
"numpy",
"openpyxl",
"xlrd",
"python-pptx",
"python-docx",
"pypdf",
"pdfplumber",
"pillow",
"pyyaml",
# Web
"requests",
"httpx",
"beautifulsoup4",
"lxml",
# Utilities
"rich",
"chardet",
"matplotlib",
"seaborn",
# Dev tools
"ruff",
"mypy",
"pytest",
]Add these with uv add <package> or just ask your robot to do it. 🤖
Shell Script
Create an executable script (not a shell function) and add it to your PATH:
#!/bin/zsh
echo "⚠️ This Python instance is for ad-hoc usage only."
echo " If working in a project with its own venv, use that instead."
echo ""
exec uv run --project /casa/dev/claude-code python "$@"Save this as ~/.config/scripts/claude-adhoc-python (or wherever you keep scripts), make it executable, and symlink it to a directory in your PATH:
chmod +x ~/.config/scripts/claude-adhoc-python
ln -sf ~/.config/scripts/claude-adhoc-python ~/.local/bin/claude-adhoc-pythonWhy a script instead of a shell function? Claude Code’s Bash tool runs in a non-interactive shell, which only sources .zshenv - not .zshrc or any files it sources. Shell functions defined in .zshrc won’t be available. A standalone script in your PATH works everywhere.
Key design choices:
| Choice | Rationale |
|---|---|
| Standalone script | Works in non-interactive shells (like Claude Code’s Bash) |
| Distinct command name | Avoids confusion with project-local Python |
| Warning message | Reminds both Claude and user this is for ad-hoc use |
Claude Code Instructions
Add to your global ~/.config/claude/CLAUDE.md (see Claude Code’s Instruction Mechanisms for how CLAUDE.md and other config mechanisms work):
## Ad-hoc Python
For quick Python tasks outside of project contexts, use:
claude-adhoc-python -c "import pandas as pd; ..."
DO NOT use this inside projects that have their own venv or pyproject.toml.
Use the project's environment instead.This tells Claude when to use the ad-hoc environment and - critically - when not to.
Usage
One-liners:
claude-adhoc-python -c "import pandas as pd; print(pd.read_excel('data.xlsx').head())"Scripts:
claude-adhoc-python script.pyOr invoke uv directly:
uv run --project /casa/dev/claude-code python -c "import pdfplumber; ..."If you use Claude Code’s sandbox, the uv cache is outside the working directory and needs explicit permission. Add your cache path to ~/.claude/settings.json:
"allow": [
"Read(//path/to/.uv-cache/**)",
"Edit(//path/to/.uv-cache/**)"
]Use // for absolute paths - a single / is relative to the settings file. Adjust the path to match your $UV_CACHE_DIR.
Also: early versions of uv (before v0.9.29) panicked inside the sandbox due to a blocked macOS system API. If you hit “Attempted to create a NULL object”, update uv: uv self update.
What I Didn’t Do
No ipykernel: Claude Code’s Bash tool is stateless; each command runs in a fresh shell. A persistent REPL adds no value here.
No activation script: the uv run --project pattern handles isolation without needing to “activate” anything. Simpler mental model.
Maintenance
Add packages as needed:
cd /casa/dev/claude-code
uv add some-new-packageUpdate everything:
uv sync --upgrade