ADR-003: Formatter and Linter
Field |
Value |
|---|---|
Status |
|
Date |
2026-05-18 |
Deciders |
AI Team |
Supersedes |
None |
Superseded by |
– |
Context
The sprintstart-ai service is built in Python 3.12 and uses uv
with pyproject.toml for dependency management.
Before development continues, the team needs to agree on a formatter and linter setup to ensure consistent code quality across local development and CI.
This decision affects:
Code formatting — ensures consistent style and readability across the project
Linting — catches common issues, unused imports, and style violations early
CI quality gates — enforces consistent standards before merging code
Developer onboarding — simplifies local setup and development workflows
This decision blocks the final CI quality pipeline setup.
Decision Drivers
Consistent code style across the project
Fast feedback in local development and CI
Simple configuration in
pyproject.tomlLow maintenance overhead
Compatibility with Python 3.12
Good integration with
uvand GitHub Actions
Considered Options
Formatter / Linter
Option A – Ruff
Option B – Black + isort + Flake8
Option C – Pylint + Black + isort
Decision
Formatter and linter: Ruff
Ruff will be configured in pyproject.toml
and executed in CI using:
uv run ruff check .
uv run ruff format --check .
Selected Ruff configuration:
[tool.ruff]
line-length = 88
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "I"]
Rationale
Ruff is the best option for our project because it combines linting, formatting, and import sorting into a single fast tool.
It integrates well with our existing uv + pyproject.toml
setup and reduces tooling complexity compared to maintaining
multiple separate tools.
Its performance also improves developer experience and CI execution speed.
Pros and Cons of the Options
Formatter / Linter
Option A – Ruff
✅ Extremely fast
✅ Combines linting, formatting, and import sorting
✅ Simple configuration in
pyproject.toml✅ Works well with
uvand GitHub Actions✅ Reduces the number of required tools
❌ Relatively new compared to Black or Flake8
❌ Some team members may be unfamiliar
Option B – Black + isort + Flake8
✅ Mature and widely used
✅ Clear separation of responsibilities
✅ Familiar to many Python developers
❌ Requires multiple tools and configurations
❌ More maintenance overhead
❌ Slower CI execution compared to Ruff
Option C – Pylint + Black + isort
✅ Very detailed static analysis
✅ Mature and feature-rich
✅ Highly configurable
❌ More complex setup and configuration
❌ Can be overly strict for early-stage projects
❌ Slower feedback during development and CI
Consequences
Positive:
Consistent formatting across the entire codebase
Faster CI quality checks
Simpler developer setup
Import ordering handled automatically
Reduced tooling complexity
Negative / Trade-offs:
Team members unfamiliar with Ruff may require a short ramp-up
Ruff behavior may differ slightly from Black or Flake8 defaults
Follow-up actions:
[x] Add Ruff to dev dependencies
[x] Configure Ruff in
pyproject.toml[x] Add Ruff lint check to GitHub Actions
[x] Add Ruff format check to GitHub Actions
[ ] Document local Ruff usage in README