# Contributor handoff — astral-sh/ruff

> Canonical page: https://codevetter.com/unpack/ruff/agent-handoff

# Contributor handoff — astral-sh/ruff

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

Read the CLI dispatch and the crate you are changing before editing; Ruff and ty share a parser but not a rule registry. Semantic changes need a focused test, snapshot updates via the environment variables rather than hand edits, and `cargo dev generate-all` when options, rules, or CLI help change. ty code must keep `db` in the Salsa parameter position and must not touch another file's AST from an untracked query. Do not drop Python repros inside this checkout, and do not expect file-watcher tests to pass in a sandbox.
- Start with `AGENTS.md` (test commands, mdtest style, Salsa rules, `db` parameter order, prek) and `crates/ruff/src/lib.rs` plus `args.rs` for Ruff CLI work, or `crates/ty/src/lib.rs` for ty CLI work. Rule work starts at `codes.rs` `code_to_rule` and the plugin module; ty lint work starts at `declare_lint!` and `register_lints`. — [AGENTS.md](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/AGENTS.md) [crates/ruff/src/lib.rs#L128-L211](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/lib.rs#L128-L211) [crates/ty/src/lib.rs#L45-L77](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty/src/lib.rs#L45-L77) [crates/ty_python_semantic/src/lib.rs#L89-L97](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty_python_semantic/src/lib.rs#L89-L97)
- Safe Ruff lint edit: add or change a rule under `crates/ruff_linter/src/rules/<plugin>/`, register it in `code_to_rule`, add a fixture and insta snapshot, and leave unrelated plugins alone. The public `ruff_linter` API is documented as unstable, so do not churn signatures to make a single rule compile. — [crates/ruff_linter/src/lib.rs#L1-L6](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/lib.rs#L1-L6) [crates/ruff_linter/src/codes.rs#L237-L249](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/codes.rs#L237-L249) [scripts/add_rule.py#L27-L36](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/scripts/add_rule.py#L27-L36)
- Tests to run for a linter change: `cargo nextest run -p ruff_linter` (or the narrower test binary) with `INSTA_FORCE_PASS=1 INSTA_UPDATE=always MDTEST_UPDATE_SNAPSHOTS=1`, then review snapshot diffs. For ty semantic changes, run `cargo nextest run -p ty_python_semantic --test mdtest`. Full CI uses `cargo insta test --all-features --unreferenced reject --test-runner nextest`. — [AGENTS.md](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/AGENTS.md) [.github/workflows/ci.yaml#L414-L417](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/.github/workflows/ci.yaml#L414-L417) [crates/ty_python_semantic/tests/mdtest.rs#L14-L22](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty_python_semantic/tests/mdtest.rs#L14-L22)
- Never edit `.snap` files or inline snapshot bodies by hand. After option, CLI, rule, or environment-variable definition changes, run `cargo dev generate-all` so `ruff.schema.json`, `ty.schema.json`, and generated docs stay aligned. Finish with `uv run --only-dev --locked prek run --files <each changed path>`. — [AGENTS.md](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/AGENTS.md) [crates/ruff_dev/src/main.rs#L45-L65](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_dev/src/main.rs#L45-L65)
- ty parameter convention: `db` is the first argument of free functions and comes immediately after `self` on methods. Methods that read `.node()` should be `#[salsa::tracked]`. `check_file_impl` is already a tracked query; do not call raw AST helpers from module A while checking module B. — [AGENTS.md](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/AGENTS.md) [crates/ty_project/src/lib.rs#L959-L975](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty_project/src/lib.rs#L959-L975) [crates/ty_python_semantic/src/lib.rs#L168-L172](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty_python_semantic/src/lib.rs#L168-L172)
- Ad-hoc Python repros must be created outside the checkout. The root `pyproject.toml` sets `requires-python = ">=3.7"` and `tool.ruff.target-version = "py38"`, so ty discovered from this tree infers an old Python version. ty preview for 3.15 is still warned unless preview is enabled. — [pyproject.toml#L11-L12](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/pyproject.toml#L11-L12) [pyproject.toml#L160-L161](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/pyproject.toml#L160-L161) [AGENTS.md](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/AGENTS.md) [crates/ruff_linter/src/linter.rs#L458-L464](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_linter/src/linter.rs#L458-L464)
- Do not use `panic!`, `unreachable!`, `unwrap`, or `expect` for conditions the type system can encode. Existing exceptions include the Windows VT assert in `main` and cache timestamp truncation; do not add more. Lint-path failures should become diagnostics the way `catch_unwind` already does. — [AGENTS.md](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/AGENTS.md) [crates/ruff/src/main.rs#L31-L33](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/main.rs#L31-L33) [crates/ruff/src/commands/check.rs#L193-L213](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/commands/check.rs#L193-L213)
- ty PR titles should start with `[ty]`. LSP-only changes use the `server` label when you can set labels. Avoid competing with an open PR; `CONTRIBUTING.md` is the duplicate-work check. — [AGENTS.md](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/AGENTS.md) [CONTRIBUTING.md](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/CONTRIBUTING.md)
- File-watcher tests do not work in the sandbox. Ruff watch mode is `recommended_watcher` in `ruff::check`; ty watch mode is `watch::directory_watcher` plus `ProjectWatcher`. Skip those locally unless the change is specifically about watching. — [AGENTS.md](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/AGENTS.md) [crates/ruff/src/lib.rs#L380-L389](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/lib.rs#L380-L389) [crates/ty/src/lib.rs#L328-L336](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty/src/lib.rs#L328-L336)
- Cache keys include the crate version string, so behavior changes that should invalidate user caches need a version bump or an explicit settings-key change. Do not hand-delete logic that compares `package.package_root` or the atomic rename; both exist because of real corruption bugs. — [crates/ruff/src/cache.rs#L94-L131](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/cache.rs#L94-L131) [crates/ruff/src/cache.rs#L164-L166](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff/src/cache.rs#L164-L166)
- Formatter and parser changes have their own fixture trees and fuzz targets (`ruff_formatter_idempotency`, `ruff_parse_idempotency`). A parser change that still snap-passes can fail idempotency fuzz; run the crate tests, not only a single rule snapshot. — [fuzz/Cargo.toml#L60-L69](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/fuzz/Cargo.toml#L60-L69) [crates/ruff_python_parser/src/lib.rs#L281-L290](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_python_parser/src/lib.rs#L281-L290) [crates/ruff_python_formatter/src/lib.rs#L136-L145](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ruff_python_formatter/src/lib.rs#L136-L145)
- Security-sensitive edits (subprocess, LSP trust, playground KV, cache paths, fix application) should be checked against `agents/references/cli-threat-model.md`, `language-server-threat-model.md`, `playground-threat-model.md`, or `repository-threat-model.md` as appropriate. uv must stay default-off. — [agents/references/threat-models.md#L1-L13](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/agents/references/threat-models.md#L1-L13) [agents/references/cli-threat-model.md#L23-L34](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/agents/references/cli-threat-model.md#L23-L34) [crates/ty_project/src/uv.rs#L33-L36](https://github.com/astral-sh/ruff/blob/c131cbad5a0f858ef2ba207e0260d76bb33069b1/crates/ty_project/src/uv.rs#L33-L36)

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)
