# Extension points — astral-sh/ruff

> Canonical page: https://codevetter.com/unpack/ruff/extension-points

# Extension points — astral-sh/ruff

Scanned commit c131cbad5a0f858ef2ba207e0260d76bb33069b1 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

New Ruff rules plug into a plugin module, the `Linter` enum, and the `code_to_rule` table, usually scaffolded by `scripts/add_rule.py`. New ty lints plug into `declare_lint!` plus `LintRegistryBuilder::register_lint`. User-facing commands, LSP methods, TOML options, and WASM settings are each a closed table that must be updated and then regenerated into docs and JSON schema. Checker phases and `FormatNodeRule` are the extension points inside an existing rule or syntax node.
- `scripts/add_rule.py` scaffolds a rule (`--name`, `--prefix`, `--code`, `--linter`, `--category`). The implementation then lives under `crates/ruff_linter/src/rules/<plugin>/` and must be referenced from `code_to_rule` in `codes.rs`. Plugin modules are declared in `rules/mod.rs`. — [scripts/add_rule.py#L27-L36](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/scripts/add_rule.py#L27-L36) [crates/ruff_linter/src/rules/mod.rs#L1-L59](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/rules/mod.rs#L1-L59) [crates/ruff_linter/src/codes.rs#L237-L249](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/codes.rs#L237-L249)
- `Linter` is a `RuleNamespace` enum. `#[derive(RuleNamespace)]` in `ruff_macros` generates the prefix and rule-iteration impls. `Rule::from_code` parses a code into that namespace and matches the noqa suffix. — [crates/ruff_linter/src/registry.rs#L34-L45](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/registry.rs#L34-L45) [crates/ruff_linter/src/registry.rs#L16-L25](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/registry.rs#L16-L25) [crates/ruff_macros/src/lib.rs#L94-L101](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_macros/src/lib.rs#L94-L101)
- Rule structs use `#[derive(ViolationMetadata)]` (`ruff_macros::derive_violation_metadata`). `Violation` and `AlwaysFixableViolation` are the public traits re-exported from `ruff_linter`. Test-only rules are compiled in under `feature = "test-rules"` inside `check_path`. — [crates/ruff_macros/src/lib.rs#L85-L91](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_macros/src/lib.rs#L85-L91) [crates/ruff_linter/src/lib.rs#L17-L18](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/lib.rs#L17-L18) [crates/ruff_linter/src/linter.rs#L259-L270](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/linter.rs#L259-L270)
- ty lints are not in the Ruff `Rule` enum. `declare_lint!` builds a `LintMetadata` static; `register_lints` in `ty_python_semantic` calls `types::register_lints` and then registers ignore-comment lints. `LintRegistryBuilder::register_lint` panics on a duplicate name. Aliases go through `register_alias`. — [crates/ty_python_semantic/src/lib.rs#L79-L97](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty_python_semantic/src/lib.rs#L79-L97) [crates/ty_python_semantic/src/lint.rs#L256-L281](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty_python_semantic/src/lint.rs#L256-L281) [crates/ty_python_semantic/src/lint.rs#L370-L398](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty_python_semantic/src/lint.rs#L370-L398)
- CLI extension is the clap `Command` enum in `crates/ruff/src/args.rs` and the match in `ruff::run`. ty's parallel table is `crates/ty/src/args.rs` `Command` and the match in `ty::run`. Hidden shell-completion variants call `clap_complete_command`. — [crates/ruff/src/args.rs#L131-L186](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/args.rs#L131-L186) [crates/ruff/src/lib.rs#L170-L210](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/lib.rs#L170-L210) [crates/ty/src/args.rs#L33-L60](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty/src/args.rs#L33-L60) [crates/ty/src/lib.rs#L54-L63](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty/src/lib.rs#L54-L63)
- Ruff LSP methods are one module per request under `server/api/requests/` and one per notification under `server/api/notifications/`, re-exported from `requests.rs` and `notifications.rs`. Adding a method means a new handler type plus registration in those modules, not a dynamic plugin loader. — [crates/ruff_server/src/server/api/requests.rs#L1-L24](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_server/src/server/api/requests.rs#L1-L24) [crates/ruff_server/src/server/api/notifications.rs#L1-L23](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_server/src/server/api/notifications.rs#L1-L23)
- Configuration options use `#[derive(OptionsMetadata)]` and `CombineOptions` from `ruff_macros`. `ruff config` prints that metadata. `cargo dev generate-all` / `generate-json-schema` / `generate-options` / `generate-ty-schema` regenerate `ruff.schema.json`, `ty.schema.json`, and docs. CLI overrides arrive as `ConfigurationTransformer` implementations passed into `resolve_root_settings`. — [crates/ruff_macros/src/lib.rs#L23-L48](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_macros/src/lib.rs#L23-L48) [crates/ruff_dev/src/main.rs#L45-L65](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_dev/src/main.rs#L45-L65) [crates/ruff_workspace/src/resolver.rs#L442-L450](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_workspace/src/resolver.rs#L442-L450)
- Lint passes are selected by `rule.lint_source()` inside `check_path`: tokens, filesystem, logical lines, AST, imports, physical lines, and TOML. A rule that needs a new pass has to extend that match of sources, not only the rule body. AST work enters through `check_ast`. — [crates/ruff_linter/src/linter.rs#L154-L256](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/linter.rs#L154-L256) [crates/ruff_linter/src/checkers/mod.rs#L1-L7](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/checkers/mod.rs#L1-L7)
- Formatter node coverage is the `FormatNodeRule<N>` trait (`fmt` handles comments and source-map positions; `fmt_fields` is implemented per node). `format_module_ast` is the stable entry for callers that already have a `Parsed<Mod>`. — [crates/ruff_python_formatter/src/lib.rs#L52-L96](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_python_formatter/src/lib.rs#L52-L96) [crates/ruff_python_formatter/src/lib.rs#L148-L155](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_python_formatter/src/lib.rs#L148-L155)
- WASM settings are whatever `Options` / `Configuration::from_options` accepts. `Workspace::new` is the JS constructor; `defaultSettings` re-serializes defaults including `DEFAULT_SELECTORS`. There is no runtime plugin registry in the WASM crate. — [crates/ruff_wasm/src/lib.rs#L268-L318](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_wasm/src/lib.rs#L268-L318)
- File discovery can be customized per invocation by implementing `ConfigurationTransformer` and passing it to `project_files_in_path` / `resolve_scoped_settings`. The CLI's `ConfigArguments` is that transformer for `--config` key/value overrides and `--isolated`. — [crates/ruff_workspace/src/resolver.rs#L477-L507](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_workspace/src/resolver.rs#L477-L507) [crates/ruff/src/args.rs#L38-L71](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/args.rs#L38-L71)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
