astral-sh/ruff

ruff has 900+ rules for Python, but zero rules for its own per-crate manifest discipline. alint is the missing piece.

Narrative
Catches conventions your pipeline assumes but doesn't verify
Rules
75
Last revalidated
Engineering reference
README on GitHub · .alint.yml

Why this case study matters

ruff is a linter that can’t lint its own structure. It maintains its structural validation in two places: .pre-commit-config.yaml (16 hooks, run via prek — Astral’s own pre-commit runner) and .github/workflows/ci.yaml (~22 jobs).

Unlike rust-lang/rust’s src/tools/tidy/ (which IS structural validation), ruff’s crates/ruff_dev/ is exclusively a codegen + introspection binary. The conventions exist (every internal crate is version = "0.0.0", publish = false; only ruff and ruff_linter and ruff_wasm get versioned), but their enforcement is entirely social.

This case study has two distinct narrative angles worth featuring, both of which position alint orthogonally to Astral’s ecosystem rather than competitively.

Headline catch

ruff has 900+ rules for Python, but zero rules for its own per-crate manifest discipline.

The rule ruff-internal-crates-unpublished in this config is something ruff literally does not check today and would benefit from on day one. Same shape applies to most “linter for language X” projects across the inventory.

Where alint earns its keep here

Two distinct angles worth featuring:

1. The “prek replacement” angle

“alint replaces 15 of ruff’s 16 pre-commit hooks with one declarative config.” The prek framework is itself an Astral product (the modern pre-commit replacement); pitching alint as the next layer up — the rule-config side, not the hook-runner side — positions alint orthogonally rather than competitively. There’s no overlap: prek runs hooks, alint declares rules.

2. The “ruff is a linter that can’t lint its own structure” angle

Ruff has 900+ rules for Python, but zero rules for its own per-crate manifest discipline. Its structural gates live entirely in prek hooks calling third-party tools (typos, zizmor, actionlint, mdformat, shellcheck, prettier, ruff itself). This is a legitimately different shape from rust-lang/rust’s tidy: ruff has chosen the “compose existing tools via prek” path rather than building its own structural linter. Alint is exactly the missing piece — one declarative file replaces the prek wrapper, plus the per-prek-hook YAML, plus the priority-order metadata, plus the per-hook exclusion patterns.

Future story angles

The factual engineering writeup (tooling inventory, mapping table, gap catalogue, validation status footer) lives in the public alint repo at github.com/asamarts/alint/tree/main/examples/astral-sh-ruff/README.md.