A request to add Black to Tabeer.ai's Django backend came in after Ruff was already installed, configured, and had already reformatted 91 files. Worth being direct about what actually happened: Black wasn't added as a separate dependency. Here's the reasoning, laid out plainly rather than silently skipped.
Ruff's Formatter Is Black, Functionally
ruff format isn't "similar to Black" or "Black-inspired" — it's an explicit,
from-scratch reimplementation targeting Black's exact output style, built by the Ruff team
specifically so teams already using Black could switch without a diff. The project's own
documentation states the intent directly: match Black's formatting decisions, just implemented
in Rust instead of Python, for a large speed difference on real codebases.
backend/pyproject.toml already had this configured before Black ever came up:
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
What Installing Black Alongside Ruff Would Actually Mean
Two formatters, configured to produce (as close to) identical output, both running — on every commit if wired into pre-commit, in CI if wired there too. Concretely, that's:
- Redundant CI time — two passes over the same files for the same result.
- A second config to keep in sync — Black's own settings would need to mirror Ruff's quote-style and line-length exactly, forever, or the two tools start producing genuinely different output and fighting each other on every file either one touches.
- Zero net benefit — no code path exists where Ruff's formatter produces different output than Black would, by design. Running both doesn't catch anything the other missed; it just runs the same idea twice.
When Adding Black Separately Would Actually Make Sense
To be fair to the original ask — there are real reasons a team might want Black specifically instead of Ruff's formatter:
- Already deep in Black-specific tooling (editor integrations, CI badges, docs referencing Black by name) where switching the name of the tool has organizational cost independent of the actual output.
- Need Black's exact release cadence and stability guarantees for a codebase with a compliance requirement around tool provenance — unusual, but it happens.
Neither applies to this project: Ruff was already the formatter of record, already configured, already run against the whole codebase with the full test suite verified green afterward. There was no existing Black-specific dependency to preserve.
The Actual Decision Rule
When a request asks for a tool that would exactly duplicate a job an already-configured tool is doing, the responsible move isn't silently ignoring the request or installing the redundant tool anyway to check a box — it's surfacing the overlap plainly and explaining the actual tradeoff, the same way the Trivy-vs-Dependabot decision got made on this project: match tooling to what's actually needed, not to a checklist of names.
If you're auditing a Python project's tooling for exactly this kind of redundancy — two linters, two formatters, two of anything doing the same job — get in touch.
By Shahid Malik