Why rules_lint
- No changes needed to rulesets. Works with the Bazel rules you already use.
- No changes needed to BUILD files. No lint wrapper macros, and lint doesn’t appear in
bazel queryoutput. Users simply lint their existing*_librarytargets. - Incremental. Lint checks (including producing fixes) run as normal Bazel actions, so they support Remote Execution and their outputs land in the Remote Cache.
- Lint changes only. It’s fine if your repository has a lot of existing issues; you don’t need to fix or suppress them all to start linting new changes. We call this the “Water Leak Principle”: always fix the leak before mopping the spill.
- Formats files Bazel doesn’t know about. Formatting runs directly on the file tree, so there’s no need to create targets for your shell scripts just to format them.
- Honors your existing configuration files. The same config the tools use outside Bazel (for example, in your editor) applies under Bazel.
Supported tools
Formatters and linters ship for dozens of languages, including:| Language | Formatter | Linter(s) |
|---|---|---|
| JavaScript / TypeScript | Prettier | ESLint |
| Python | ruff | ruff, flake8, pylint, bandit, ty |
| C / C++ | clang-format | clang-tidy, cppcheck |
| Go | gofmt / gofumpt | |
| Java | google-java-format | PMD, Checkstyle, Spotbugs |
| Kotlin | ktfmt | ktlint |
| Rust | rustfmt | clippy |
| Shell | shfmt | shellcheck |
| Starlark | Buildifier | Buildifier |
| Protocol Buffers | buf | buf lint |
| Markdown, YAML, JSON, HTML, CSS | Prettier and friends | Vale, yamllint, Stylelint |
Running under the Aspect CLI
Theaspect lint and aspect format tasks are the easiest way to run rules_lint: hold-the-line linting that only fails on violations you introduced, and formatting for just the files changed in your PR. Results can be surfaced by Marvin as status checks, review comments, and suggested fixes on GitHub and GitLab, or as failing tests.

