Skip to main content

ferrolint

rust PyPI crates.io License: MIT

Extensible Python linter in Rust that runs custom rules, loaded as WASM plugins, next to Ruff.

Table of contents

About

ferrolint lints Python code with Ruff's own parser crates (ruff_python_parser, ruff_python_ast, ruff_python_semantic) and runs checks that ship as WASM plugins. Instead of a plugin host interpreting Python, each check is a compiled WebAssembly component: the contract feeds it AST visitor events and lets it ask scope and binding questions, and the plugin answers with diagnostics carrying a code, message, range, severity and an optional fix.

Ruff stays in the loop and keeps every built-in rule, including the Pylint PL* checks. ferrolint is the layer for checks Ruff does not have: a team's custom rules, ported Pylint checkers, and Pylint message-ID/symbol mappings, all running in the same pass.

Key features

  • Plugins as WebAssembly components. Each plugin runs in an empty sandbox with per-file fuel and time caps, and loads only with its pinned SHA-256.
  • Pylint compatibility. Rules keep Pylint's message IDs and symbols, so selecting, ignoring and # pylint: disable= comments keep working.
  • Speed on large codebases. On a million lines with the ten benchmark plugins, a cold run takes about 6.5 s on four cores and a warm run 0.25 s; Pylint running the same ten checks takes 167 s. make bench measures it.
  • Incremental runs. A content-keyed cache in .ferrolint-cache/ and --diff-base to lint only what changed.
  • Deterministic output in text, JSON, SARIF or JUnit.
  • One static binary for Linux x86_64 and aarch64 and for macOS aarch64.

Requirements

  • Linux (x86_64 or aarch64) or macOS (aarch64). There is no Windows build.
  • Python 3.9 or later and pip or uv, to install the wheel. The linter itself is a native binary and lints any Python code.
  • To write a plugin: Rust and the wasm32-wasip2 target (rustup target add wasm32-wasip2).

Usage

Lint the current directory:

ferrolint

Lint chosen paths with an explicit configuration file, in SARIF:

ferrolint --config ci.toml --format sarif src tests
Option Default Effect
[PATHS]... . Files or directories to lint.
-c, --config none A ferrolint.toml or pyproject.toml to read.
--threads <N> 0 Worker threads; 0 uses every core.
--format <FORMAT> text text, json, sarif or junit.
--diff-base <REF> none Lint only files changed since the merge base of REF.
--no-cache off Neither read nor write .ferrolint-cache/.
--stats off Print files, cache hits, parses and plugin runs.
Exit code Meaning
0 No findings.
1 At least one finding.
2 Usage, configuration or plugin error.

Configuration lives in ferrolint.toml or in the [tool.ferrolint] table of pyproject.toml (all keys):

select = ["FL002"]
ignore = ["FL003"]
exclude = ["vendor/"]

[[plugins]]
path = "plugins/my_checker.wasm"
sha256 = "…"

[per-file-ignores]
"tests/*.py" = ["FL002"]

Getting started

Install the wheel from PyPI:

pip install ferrolint        # or: uv tool install ferrolint
ferrolint --version

To try an unreleased commit, install from Git. The build needs the pinned Rust toolchain and the wasm32-wasip2 target, and the first build compiles Wasmtime, which takes minutes:

pip install "git+https://github.com/gajaguar/ferrolint"

How a run works

A run discovers the Python files under its targets, honouring .gitignore and the configured excludes, parses them in parallel with Ruff's parser, and runs the host's own rules plus every configured WASM plugin against the plugin.wit contract. The rules and their Pylint counterparts are listed in Native rules. The requirements and the design decisions live in the docs/ bundle: requirements and decisions.

Writing a plugin

A plugin is a Rust cdylib built to wasm32-wasip2 against ferrolint-plugin-sdk:

[dependencies]
ferrolint-plugin-sdk = "1"

The SDK's version is the version of the plugin contract: a plugin built against any 1.x loads in a ferrolint 1.x host. The sample unused-import ports Pylint's W0611 and matches its findings on the fixtures. Writing a plugin builds it step by step, and A plugin outside this repository covers a plugin kept in its own crate.

Type inference with ty

ty is an optional extension that adds ten Pylint rules needing the type of a value. The published wheels are built without it. To use it, build with cargo build --release --features ty and set VIRTUAL_ENV to the project's environment. See Rules answered by ty.

Security

Report a vulnerability by emailing dev@gajaguar.com rather than opening a public issue. SECURITY.md has the supported versions.

Contributing

See CONTRIBUTING.md.

License

ferrolint is released under the MIT License; see LICENSE.

Metadata

Release files for ferrolint 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ferrolint 1.0.0
File Size Uploaded Provenance Actions
ferrolint-1.0.0.tar.gz 599.4 kB With provenance Details for ferrolint-1.0.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for ferrolint 1.0.0
File Interpreter ABI Platform Actions
ferrolint-1.0.0-py3-none-manylinux_2_17_x86_64.musllinux_1_2_x86_64.whl Python 3 none Linux musl 1.2+ x86-64, Linux glibc 2.17+ x86-64 Details for ferrolint-1.0.0-py3-none-manylinux_2_17_x86_64.musllinux_1_2_x86_64.whl
ferrolint-1.0.0-py3-none-manylinux_2_17_aarch64.musllinux_1_2_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64, Linux musl 1.2+ ARM64 Details for ferrolint-1.0.0-py3-none-manylinux_2_17_aarch64.musllinux_1_2_aarch64.whl
ferrolint-1.0.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details for ferrolint-1.0.0-py3-none-macosx_11_0_arm64.whl

Total release size: 27.9 MB

Release files / ferrolint-1.0.0.tar.gz

Download URL ferrolint-1.0.0.tar.gz
Size 599.4 kB
Tags Source
SHA-256 checksum
How to use checksums
d1e03c610778c26392fdf5780a9d589c1a1e7e07da6a815bb136aa0cd889a744
BLAKE2b-256 checksum
How to use checksums
08d7d99a582261e863e0b26b637168d40515c066797ca678d9c4767e3522d13c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Release files / ferrolint-1.0.0-py3-none-manylinux_2_17_x86_64.musllinux_1_2_x86_64.whl

Download URL ferrolint-1.0.0-py3-none-manylinux_2_17_x86_64.musllinux_1_2_x86_64.whl
Size 9.9 MB
Tags Linux glibc 2.17+ x86-64 Linux musl 1.2+ x86-64 Python 3
SHA-256 checksum
How to use checksums
d8631fa468534ba8ecf63c65115c2573b54ae7d5a2c134ddb742dd9f0ddefc5d
BLAKE2b-256 checksum
How to use checksums
71aa9aea83654bf52c20216c0ecec521d840787324c8f0ce2265f26f10e7f3da
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Release files / ferrolint-1.0.0-py3-none-manylinux_2_17_aarch64.musllinux_1_2_aarch64.whl

Download URL ferrolint-1.0.0-py3-none-manylinux_2_17_aarch64.musllinux_1_2_aarch64.whl
Size 8.5 MB
Tags Linux glibc 2.17+ ARM64 Linux musl 1.2+ ARM64 Python 3
SHA-256 checksum
How to use checksums
bf16afa535616129404c9c3f10fce00fddf5ca3f15e4a88246b2cc29ec02ad2b
BLAKE2b-256 checksum
How to use checksums
b266d77955602f1b9a9e9e5dff19192b255db08b7fd9c8925f9c28314ce9e9c3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Release files / ferrolint-1.0.0-py3-none-macosx_11_0_arm64.whl

Download URL ferrolint-1.0.0-py3-none-macosx_11_0_arm64.whl
Size 8.9 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
67451c5dbccd04320722708fefef206cfe61b3b45700287be64af9dcd9d836c9
BLAKE2b-256 checksum
How to use checksums
54c05268e1fc0ab186551f27cd884b71f76bb6355137bf0df701853e3c8883e9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Security for ferrolint 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 4 files in this release have been uploaded with provenance metadata.

Select from 4 files

Attestation for ferrolint-1.0.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.0 This release

4 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page