Skip to content
Dev Tools Article

Ruff's 413 Default Rules End the Flake8 Era

Astral's first defaults change since v0.1.0 breaks unpinned CI — and it's still the right call.

Lenn Voss
Lenn Voss
Cloud & Infrastructure Writer · Jul 26, 2026 · 4 min read
Ruff's 413 Default Rules End the Flake8 Era

For three years, running ruff check with no config meant something very specific and very modest: pyflakes plus a sliver of pycodestyle, 59 rules in all. That era ended this week. Ruff v0.16.0 flips on 413 rules by default — a 7x expansion, and the first change to the default set since v0.1.0 back in 2023.

This isn't a changelog entry. It's Astral deciding what Python code should look like, at the exact moment the company has maximum leverage to make that decision stick.

Defaults are the real standard

Ruff's rule catalog grew from 708 rules at v0.1.0 to 968 today, but the defaults never moved. That was a deliberately conservative stance: match flake8's out-of-the-box behavior, don't scare anyone, win on speed. It worked — Ruff displaced flake8, isort, and pyupgrade across a huge slice of the ecosystem, and its pyproject.toml stanza became boilerplate in every cookiecutter template.

But conservative defaults have a cost. As Astral notes in the release post, many of the dormant rules catch outright syntax errors and immediate runtime errors — bugs, not style nits — and the majority of projects never turned them on. The zero-config experience quietly lagged years behind what the tool could actually do.

The new default set pulls in curated subsets from 34 rule categories: 29 flake8-bugbear rules (mutable default arguments, the classics), 42 pyupgrade rules, 21 from flake8-simplify, 67 pylint rules, plus timezone-aware datetime checks (DTZ), async pitfalls, and Ruff's own RUF set. The operative word is subsets. The defaults enable 42 of the UP rules, not all of them — so if you currently have extend-select = ["UP"] and delete it thinking the new defaults cover you, you'll silently drop rules. Audit before you prune your config.

The breakage is real, and mostly fine

If your CI installs Ruff unpinned, it broke this week. Simon Willison reported exactly that, then ran v0.16.0 against his three biggest projects: on sqlite-utils alone, the new defaults surfaced 1,618 violations — and --fix cleared 1,538 of them automatically. What remained was the interesting residue: naive datetimes, bare except clauses, dead attribute accesses. Real findings, not noise.

That ratio — roughly 95% auto-fixable — is what makes this defensible. Pylint tried maximalist defaults twenty years ago and trained a generation of developers to ignore linters. ESLint spent the last few releases moving the other direction, slimming eslint:recommended and pushing opinions into shareable configs. Ruff is betting it can go maximalist because it ships the fixer in the same binary. When the tool that finds 1,600 problems also fixes 1,500 of them in half a second, an aggressive default set stops being a wall of shame and becomes a one-time migration commit.

The escape hatches are clean, too. Freezing the old behavior is one stanza:

[tool.ruff.lint]
select = ["E4", "E7", "E9", "F"]

And v0.16 ships a nicer suppression story for whatever survives autofix: # ruff: ignore[F401] comments (with optional reasons) alongside the old noqa syntax, plus file-level ignores. Also in the box: Ruff now formats Python code fenced inside Markdown files by default, and check output shows fix diffs inline — small things, but they matter for docs-heavy repos and CI logs respectively.

The part nobody's saying out loud

The timing deserves scrutiny. OpenAI announced its acquisition of Astral in March, folding the uv and Ruff team into Codex. Four months later, Ruff makes its defaults dramatically stricter — and stricter machine-checkable defaults are worth far more in a world where LLM agents write a growing share of Python.

An agent doesn't read your team's style guide. It reads tool output. Every rule promoted into the default set becomes a guardrail that fires automatically in any agent loop that runs ruff check, with no prompt engineering required. Willison made the same observation, and the HN thread surfaced the counterpoint: agents can also burn tokens "fixing" benign warnings or, worse, route around failing checks entirely. Both things are true. But if you're building agent workflows, opinionated-and-autofixable defaults are close to free alignment, and Ruff just became the strongest off-the-shelf option for it.

What to actually do

For maintainers, the playbook is short. Pin Ruff — in pre-commit you already do; in CI, stop installing latest. Then upgrade deliberately: run ruff check --fix on a clean branch, eyeball the diff (with decent test coverage this is, as Willison put it, "pretty safe"), and handle stragglers with --add-noqa or targeted per-file-ignores rather than reverting wholesale. Triage one category at a time if the diff is intimidating — --select UP first, since pyupgrade fixes are the most mechanical. Greenfield projects should just take the new defaults and delete their select config entirely; hand-curated rule lists are now mostly legacy.

The one breaking change to watch beyond the rules: JSON output fields like filename and location can now be null where they previously defaulted to placeholder values. If you've written tooling that parses ruff check --output-format json, add null checks before you upgrade.

Verdict

This is the right call, executed about as well as a defaults change can be. Ruff earned the standing to be opinionated by being fast and fixable first, and a linter that hides its best rules behind config flags is leaving value on the table. The grumbling about broken CI is really grumbling about unpinned dependencies, which was always a self-inflicted wound. What's genuinely changed is Ruff's posture: it's no longer a faster flake8. It's the house style of Python now — and increasingly, the house style of whatever's writing Python for you.

Sources & further reading

  1. Ruff v0.16.0 — astral.sh
  2. Release 0.16.0 - astral-sh/ruff — github.com
  3. Ruff v0.16.0 — simonwillison.net
  4. Ruff v0.16.0 - Significant new updates - 413 default rules up from 59 — news.ycombinator.com
  5. OpenAI to acquire Astral — openai.com
  6. Ruff 0.16.0 Enables 7x More Rules by Default — pydevtools.com
Lenn Voss
Written by
Lenn Voss · Cloud & Infrastructure Writer

Lenn writes about cloud platforms, Kubernetes internals, and the infrastructure decisions that quietly make or break engineering organizations. Based in Berlin's vibrant tech scene, they have a talent for turning dense platform-engineering topics into prose that people actually finish reading.

Discussion 0

Join the discussion

Sign in or create an account to comment and vote.

No comments yet

Be the first to weigh in.

Related Reading