A team I worked with had 30 internal Python tools, mostly small CLIs and scripts, all using setup.py and pip. Migrating to pyproject.toml + uv was on the to-do list for over a year. I tackled it in two days using aider.
Tooling modernization is unglamorous but high-leverage. Faster builds, faster CI, less brittle dependency resolution. AI tools make the migration tractable for the cases where it’s mostly mechanical.
The starting state
Each of the 30 tools had:
- A
setup.py(some hadsetup.cfg) - A
requirements.txt - Maybe a
dev-requirements.txt - A
Makefile(often) ortox.ini(sometimes) for tasks
The metadata structure varied. Some tools were carefully maintained; others were drifty.
The target state:
- A
pyproject.tomlwith all metadata uvfor dependency management- Updated CI configs
- Updated local development docs
The aider workflow
For each tool, the pattern:
> /add setup.py
> /add requirements.txt
> /add dev-requirements.txt (if exists)
> /add Makefile (if exists)
>
> Migrate this Python tool to pyproject.toml using PEP 621 metadata.
> Use uv for dependency management. Update the Makefile to use uv
> commands instead of pip. Preserve all existing dependencies and
> dev-dependencies. Keep the package name and version. Add hatchling
> as the build backend.
Aider would produce:
- The new
pyproject.toml - An updated Makefile
- A note about what changed
For most tools, the migration was clean on first attempt. About 5 of the 30 needed iteration:
- Tools with custom build steps (compiled extensions)
- Tools with non-standard metadata
- Tools with version pins that needed updating
Average time per tool: 15-20 minutes including verification.
Verification
After each migration, I’d verify:
uv pip install -e .
pytest
make lint
If all passed, the tool was migrated. If something failed, I’d describe the failure to aider for a fix.
About 80% of migrations worked first try. The remaining 20% needed 1-2 iterations.
What aider got right
Standard package layouts. Tools with clean setup.py files migrated easily. Aider read the metadata, produced the equivalent in pyproject.toml format.
Dependency translation. The dependencies in requirements.txt translated to pyproject.toml cleanly. Aider preserved version constraints.
Build backend selection. Aider correctly chose hatchling for most tools. For one tool with a C extension, it used setuptools-cpp.
Makefile updates. The Makefile patterns are well-known. Aider updated pip install to uv pip install, etc.
What needed iteration
Custom setup.py logic. A few tools had Python code in setup.py that did something special (reading version from a file, etc.). Aider’s first attempts didn’t always preserve this correctly. I’d nudge.
Optional dependencies. Some tools had extras_require with multiple optional dependency groups. Aider’s translation to pyproject.toml’s [project.optional-dependencies] was sometimes incomplete.
Plugin systems. A couple of tools had entry_points that registered plugins. The aider translation worked but the formatting was sometimes inconsistent with pyproject.toml conventions.
These were specific cases. For most of the 30 tools, the migration was straightforward.
CI updates
After the package migrations, I updated the CI configs (mostly GitHub Actions). Aider helped here too:
> /add .github/workflows/ci.yml
>
> Update this CI config to use uv instead of pip. Cache the uv venv.
> Run tests, lint, and type-check as separate steps.
For each repo, this took about 5 minutes. Across 30 repos, ~2.5 hours.
Documentation updates
Each tool had a README with installation instructions. Aider updated them to reference uv:
> /add README.md
>
> Update the installation section to use uv. Mention pip as a fallback
> for users without uv. Update the development section similarly.
Mechanical work; aider handled.
Productivity numbers
- Estimated time (pre-AI): ~3 weeks of focused work
- Actual time: 2 days (~16 hours of focused work)
- Aider API cost: $14
- Tools migrated: 30
The time savings is the headline. A project that had been on the backlog for a year shipped in 2 days.
What this enables
After the migration:
uv pip installis roughly 10x faster than pip- CI runs are noticeably faster (caching uv venvs is reliable)
- New developer setup is faster
- Dependency resolution is more reliable (uv has stricter behavior)
These compound. Across 30 tools, used by maybe 15 engineers daily, the cumulative time savings are real.
What I’d recommend
For teams with similar tooling backlogs:
Bundle similar migrations. Don’t migrate one tool at a time over months. Block 2-3 days; do all the similar tools together. The pattern matching makes batch work efficient.
Use AI tooling for mechanical translation. This is the kind of work AI tools are best at. Don’t write 30 pyproject.toml files by hand.
Verify with the actual workflow. Each tool’s specific quirks need verification. Don’t trust the AI’s first translation; run the build, the tests, the lint.
Update docs and CI in the same effort. Don’t leave half-migrated states. Each tool should have all its references updated together.
Beyond pyproject.toml
The pattern generalizes. Any tooling modernization that’s mostly mechanical fits AI tools well:
- requirements.txt → pyproject.toml
- npm → pnpm or bun
- Webpack → Vite
- Yarn 1 → Yarn 4 or other modern alternatives
- Enzyme → React Testing Library
- Older test frameworks → newer ones
Each of these is “translate from format A to format B” with some judgment about edge cases. AI tools handle the bulk efficiently; human attention handles the edges.
A meta observation
Tooling modernization tends to be “everyone agrees we should but nobody wants to do it” work. The work is real but unrewarding. It accumulates as backlog.
AI tools make this kind of work tractable. The cost of “everyone agrees we should” stops being so prohibitive. Teams can ship the upgrades they’ve been talking about for years.
For teams with tooling backlogs, AI tools change the calculus. Projects that were worth doing but expensive become projects that are worth doing and cheap. The result is healthier tooling across the team.
This is one of the underrated AI tool wins: enabling work that was previously deferred indefinitely.