One thing that made this more visible recently: agents don’t only use Python when you explicitly ask them to write Python code.
They also spin up small Python snippets in the background — for
example, to scrape a page, preprocess some data, or extract content
before feeding it into a prompt (e.g. parsing a PDF). And those “hidden”
execution paths are just as prone to drifting into pip install and
system Python.
That’s exactly where inconsistency becomes harder to notice — and harder to debug.
I’ve been using coding agents for Python work long enough to notice a recurring pattern: without explicit guidance, they tend to fall back to mixed workflows.
And in Python, that usually means some combination of pip install, raw
python script.py, ad hoc virtual environments, and occasionally
hand-editing dependency declarations. Technically workable, but
inconsistent across runs.
Sometimes it even mixed uv and pip in the same task, which is where
things got confusing.
So I put together a small reference repo with reusable instruction files for both Claude and Codex:
github.com/ipeterfulop/coding-agents-uv-setup
The whole point is simple: if a Python project uses uv, then the agent
should use it consistently — both for explicit tasks and for any
background Python it spins up along the way.
The problem is ambiguity
In practice, most agent mistakes around Python tooling come from ambiguity in project expectations.
If a repository doesn’t make its expectations explicit, the agent has to guess:
- should it use
piporuv? - should it run a script with
pythonoruv run python? - should it update
pyproject.tomlmanually or add dependencies through a command? - should test and lint commands run directly or through the project environment?
- what should it do for small, supporting Python tasks in the background?
If you leave those questions open, you get inconsistent behavior. And inconsistent behavior is exactly what you do not want when you’re using an agent repeatedly across a codebase.
What I put in the repo
This repo is not an example application. It’s a small policy kit for coding agents.
It contains two instruction tracks:
- a Claude-oriented version built around
CLAUDE.md - a Codex-oriented version built around
AGENTS.md
The repo includes:
/.claude/CLAUDE.md/.claude/README.md/.codex/AGENTS.md/.codex/README.md
The policy is the same in both: use uv as the single source of truth
for Python environment management, package changes, and command
execution — regardless of whether the Python code is part of the
project or just a short-lived helper script.
That means the agent should prefer commands like:
| |
And it should avoid the usual drift:
| |
What this changes in practice
Without local instructions, the same task might result in:
pip install polars- running
python script.py - editing
pyproject.tomlmanually - or installing a library ad hoc just to parse a PDF or scrape content
With the policy files in place, the same task consistently results in:
uv add polarsuv run python script.py- no manual dependency edits
- and the same
uvworkflow even for those small, supporting scripts
The difference is not correctness — it’s consistency across runs.
Why I split Claude and Codex instructions
One thing I’ve learned from using different coding agents is that “same policy” does not mean “same file.”
Claude Code and Codex both benefit from local repository instructions, but they don’t consume them in exactly the same way. The structure, phrasing, and emphasis that works well in one tool is not always the best fit for the other.
So instead of forcing one generic document onto both, I wrote two versions that are aligned in intent but adapted to their target environment.
The important part is not textual sameness. The important part is behavioral sameness.
If I ask either tool to add a dependency, run a script, install test
tooling, execute linting, or just use Python as a helper step, I want
the answer to stay inside the uv workflow.
What the instructions actually tell the agent
The bundled files are intentionally strict.
They tell the agent that:
uvis the only supported Python package and environment manager- dependencies should be changed with
uv add,uv remove,uv sync, anduv lock - execution should go through
uv run - one-off tools can go through
uvx - manual virtualenv creation is off-limits
pipanduv pip installare not the expected default for normal project dependency management- dependency lists in
pyproject.tomlshould not be edited by hand
Vague guidance like “prefer uv when possible” is usually not enough. In my experience, agents behave more reliably when the repository policy is explicit.
The simplest use case
The practical workflow is intentionally simple.
If you’re using Claude Code, copy the bundled CLAUDE.md into the
target repository root.
If you’re using Codex, copy the bundled AGENTS.md into the target
repository root.
Then give the agent a task that forces both dependency management and execution. The smoke test I used is intentionally simple:
Add
polarsto the project, create a small script that groups sales by city, and run it. Do not use pip.
If the instructions are doing their job, the agent should reach for:
| |
If it reaches for pip install, raw python, or manual dependency
edits, the instructions are still too weak.
Protecting yourself against compromised packages
One additional guardrail I included in the instructions is uv’s
exclude-newer setting.
The idea is simple: newly published packages carry more risk than those
that have been around long enough for the community to notice problems.
A malicious upload might sit on PyPI for hours or days before anyone
flags it. By telling uv to ignore packages published in the last week,
you give the ecosystem time to catch and yank bad releases before they
land in your project.
The setting goes in pyproject.toml:
| |
This is not a complete supply chain defense, but it’s a low-friction
default that reduces exposure to the most opportunistic attacks. And
because it’s declarative and lives in the project file, it applies
consistently — whether a human or an agent runs uv add.
The instructions tell the agent to add this setting when scaffolding a
new project or updating an existing [tool.uv] table, unless the user
explicitly opts out.
A small repo, but a useful one
This isn’t a big framework or a complicated setup. It’s just a small, reusable repo that answers a narrow question:
How do I tell Claude and Codex to stop diverging from the intended
Python workflow and consistently use uv — even for the small,
background Python tasks they generate along the way?
For me, the answer was to make the rule set explicit, keep it close to the repo, and write the guidance in the format each tool actually understands.
If you’re running coding agents in Python projects and want more predictable behavior, you can grab the instruction files from the repo here:
