DEV Community

Rafael Pierre
Rafael Pierre

Posted on • Originally published at lighthousenewsletter.com

A Python Toolchain Built for the Agentic Engineering Era

I have to admit: I have never been a huge fan of pre-commit hooks. I always felt they were slow and broke up my development pace. That opinion — and my broader laziness about automated quality gates in general — has been changed by two shifts happening at the same time:

  • Rust ate the toolchain. Thanks to the wide adoption of Rust, we now have developer tooling that is orders of magnitude faster than what came before. Checks that used to cost you a coffee break now cost milliseconds.
  • Agentic Engineering (or Vibe Coding, if you will) raised the stakes. When an AI agent is writing a meaningful share of your code, automated quality controls stop being nice-to-haves, especially in dynamically typed languages like Python. Add to this equation many people in a team contributing to the same product, and the requirement to have these quality checks done automatically and at scale is even more imperative. Fast tools mean you can afford to run checks everywhere — in your editor, on every commit, in CI, and inside the agent's own feedback loop. And agents generating code at superhuman speed mean you need checks everywhere. This post is a tour of the stack I've landed on.

Rust adoption is giving birth to incredible tooling

You probably already know what these tools have in common: uv, ruff, ty, complexipy. The common thread: they're all written in Rust, and they all deliver lightspeed performance for the unglamorous housekeeping side of development.

For my Python projects, the following tools have become part of an essential quartet.

uv

A drop-in replacement for pip, pip-tools, pipx, poetry, pyenv, twine, virtualenv, and more. uv manages Python projects and their dependencies, installs and manages Python versions, and runs and installs tools published as Python packages. It's 10–100x faster than pip, which by itself is already a good reason to adopt it. Beyond raw speed, it makes environments reproducible and disposable — the same lockfile drives your laptop, your CI runner, and your agent's sandbox.

Installation

curl -LsSf https://astral.sh/uv/install.sh | sh
Enter fullscreen mode Exit fullscreen mode

Getting started

Once uv is installed, you can use it to import your requirements.txt file (if you had been using solely pip), or your pyproject.toml (if you use poetry, for instance):

From pip + requirements.txt:

# Initialize a uv project
uv init

# Import existing requirements
uv add -r requirements.txt

# If you have requirements-dev.txt for dev dependencies
uv add --dev -r requirements.txt

# One caveat: uv add -r keeps specifiers as written,
# so if your file is a pip freeze dump of == pins,
# you'll end up with everything hard-pinned in pyproject.toml.
Enter fullscreen mode Exit fullscreen mode

From pyproject.toml:

# Migrate project definitions
uvx migrate-to-uv

# Update lockfile
uv lock

# Install/update/reinstall dependencies
uv sync
Enter fullscreen mode Exit fullscreen mode

ruff

Code linter and formatter with drop-in parity with Flake8, isort, and Black, plus great extras like built-in caching and monorepo support.

If you're not familiar: a linter reads your code without running it and flags likely bugs, dead code, and style inconsistencies — think of it as a spell-checker for code. A formatter then rewrites the code into one consistent style so nobody argues about whitespace in code review.

Installation

# Install Ruff globally.
uv tool install ruff@latest

# Or add Ruff to your project.
uv add --dev ruff

# With pip.
pip install ruff

# With pipx.
pipx install ruff
Enter fullscreen mode Exit fullscreen mode

Usage

# Lint the code at <path>
uv run ruff check <path>

# Lint and auto-fix violations where possible
uv run ruff check --fix <path>

# Format the code
uv run ruff format <path>
Enter fullscreen mode Exit fullscreen mode

ty

Type checker and language server, 10–100x faster than mypy and Pyright. It's still young compared to those two, but it's already usable for most projects.

A type checker verifies that your code uses values consistently — that you're not passing a string where a function expects a number, or calling a method that doesn't exist. Python won't catch these mistakes until the code actually runs (often in production); a type checker catches them before that.

Installation

# Project scoped
uv add --dev ty

# Global installation
uv tool install ty@latest
Enter fullscreen mode Exit fullscreen mode

Usage

# Runs type-check tests over <path>
uv run ty check <path>
Enter fullscreen mode Exit fullscreen mode

Read the full article in my Substack: https://lighthousenewsletter.com/subscribe

I used to skip pre-commit hooks because they were slow, keep CI checks minimal because they were annoying, and trust my own fingers for the rest. All three assumptions have expired: the tooling is now near-instant, the checks are cheap enough to run everywhere, and my fingers aren't always the ones typing. If you built your quality-control habits in the pip-and-Flake8 era, it's definitely worth revisiting them.

I'm considering a follow-up on the Next.js / TypeScript side of this stack (oxlint, oxfmt) and on wiring these checks into agent workflows more deeply. Reply and tell me which one you'd rather read first — I read all comments and emails.

Top comments (0)