Short version: Ruff 0.16.0 (July 23, 2026) now enables 413 rules by default, up from 59. If your CI runs ruff check and you don't pin a version or set an explicit select, the next upgrade will surface hundreds of pre-existing diagnostics and fail a previously green build. Pin now, then adopt the new rules on your terms.
This is not a bug and not a rumor — it's the headline line of the 0.16.0 changelog, verbatim: "Ruff now enables a much larger set of rules by default (413, up from 59)." The version landed July 23, 2026, and is live on PyPI as the current stable release — we flagged it in this week's founder toolchain roundup, and this is the dedicated migration. For a solo founder or a small team, the risk is narrow and specific: if you rely on Ruff's default rule set, a routine pip install -U ruff or a floating version in CI turns a passing pipeline into a wall of new findings you never agreed to fix today. Everything below is the fix, in the order you should do it.
Step 0: figure out if this even affects you#
It only affects you if Ruff runs against its default rules. Check your config for an explicit select under [tool.ruff.lint]:
# What version am I on, and do I pin a rule set?
ruff version
grep -A3 "\[tool.ruff.lint\]" pyproject.toml || echo "no explicit lint config"
If you see an explicit select = [...], you're largely insulated — Ruff treats your select as the basis for the entire rule set, so a change to the built-in default can't reach you. If you see no select (or only extend-select), you're running the default, and the jump from 59 to 413 will hit you on the next upgrade.
Step 1: pin the version before you touch anything#
The fastest way to make the problem stop moving is to pin Ruff below 0.16. The last 0.15 release was 0.15.22 on July 16, 2026, per the PyPI history.
# uv
uv add --dev "ruff==0.15.22"
# or pip / requirements
pip install "ruff==0.15.22"
Pinning freezes the tool: no new rules, no new fixes, no surprises in CI. It's the right move when you're mid-release and cannot absorb a linter migration this week. It is not a permanent answer — you'll want the speed and bug fixes in newer Ruff — so treat it as buying a week, not a policy.
Step 2: the durable fix — declare an explicit rule set#
Pinning freezes the tool; an explicit select freezes your rules while letting you keep upgrading Ruff. This is the reproducible-linting setup Ruff has always recommended, and it's the version-proof answer to this whole class of surprise. Start from the classic pair and add what you want:
# pyproject.toml
[tool.ruff.lint]
# You now own the rule set. Default changes can't touch you.
select = ["E", "F"] # pycodestyle errors + Pyflakes: the safe baseline
extend-select = ["I", "B"] # add isort import-sorting and flake8-bugbear
ignore = ["E501"] # e.g. let the formatter own line length
With an explicit select, extend-select adds families on top and ignore removes specific codes (docs). Now you can bump Ruff to 0.16 and beyond and your diagnostics only change when you edit this list.
Step 3: if you want the 413, adopt them by triage#
Smaller or newer repos may just want the coverage. Take the upgrade, then measure the blast radius before you fix anything:
uv add --dev "ruff==0.16.0"
# Count findings per rule instead of scrolling 2,000 lines
ruff check --statistics
Work down that list. For findings you accept but don't want to fix now, 0.16 adds a per-line escape hatch analogous to # noqa — a # ruff: ignore[CODE] comment you can place at a line's end or on the line above a diagnostic (from the changelog):
result = eval(user_input) # ruff: ignore[S307]
Reach for a blanket ignore in config only for rules you're deferring across the whole repo; use the per-line comment for genuine one-off exceptions.
Step 4: make CI failures readable, not a wall of text#
Once you're on 0.16, wire the annotation output so failures land inline on the pull request instead of buried in log scroll. The changelog notes format --check now supports the same output formats as the linter, including github and gitlab:
# In CI (GitHub Actions)
ruff check --output-format=github .
ruff format --check --output-format=github .
One more surprise: Ruff now formats your Markdown#
Separate from the rule count, ruff format in 0.16 formats Python code blocks inside Markdown files by default. If you keep hand-tuned code samples in your README.md or docs and run ruff format across the repo, expect diffs there too. If that's unwanted, exclude Markdown from the formatter:
[tool.ruff.format]
exclude = ["**/*.md"]
The one-line takeaway#
If you have five minutes today, pin Ruff (ruff==0.15.22) so nothing breaks while you're heads-down. If you have thirty, do it properly: set an explicit [tool.ruff.lint] select, upgrade to 0.16.0, and adopt the new rules with ruff check --statistics as your worklist. The 413 default is a genuine upgrade — dramatically stronger linting out of the box — but the whole point of a fast tool is that it shouldn't decide your Tuesday for you. For the full list of what's now on by default and the official migration notes, read Astral's Ruff v0.16.0 post and the Default Rules page.



