CodeVetter · Repo Unpack · System map
astral-sh/ruff
The Cargo workspace (edition 2024, rust-version 1.96, toolchain channel 1.98.0) builds two binaries, `ruff` and `ty`, plus libraries they share: the Python parser and AST, diagnostics, and workspace settings. Ruff's check and format paths are parallel file walks over hierarchical TOML config with an on-disk `.ruff_cache`. ty is a separate CLI and language server on a Salsa 0.28 `ProjectDatabase`, with typeshed vendored under `crates/ty_vendored`. Release artifacts are a scratch Docker image, cargo-dist installers, PyPI (maturin bin binding), WASM playgrounds, and crate publishes, all driven from GitHub Actions.
- The workspace members are `crates/*`, package version 0.16.8, Rust edition 2024, minimum rust-version 1.96, license MIT, and the shared dependency set includes both `ruff_*` crates and `ty_*` crates plus salsa 0.28.2.
- The developer toolchain pin is Rust 1.98.0 in rust-toolchain.toml, which the Dockerfile copies before `rustup target add` and `cargo zigbuild --bin ruff --release`.
- `ruff` starts at `crates/ruff/src/main.rs`: it expands `@file` args with `argfile`, parses `Args` with clap, and calls `ruff::run`. Windows uses mimalloc; other supported arches use jemalloc. Broken-pipe errors exit 0; other failures print `ruff failed` and return `ExitStatus::Error` (code 2).
- `ty` starts at `crates/ty/src/main.rs` and calls `ty::run`. `ty::run` sets up Rayon, expands `@file` arguments, and dispatches `Cli` to check, server, version, shell completion, or explain. Exit statuses are Success 0, Failure 1, Error 2, InternalError 101, and Interrupted 130.
- PyPI packaging uses maturin with `bindings = "bin"`, `manifest-path = "crates/ruff/Cargo.toml"`, and `python-source = "python"`. `python/ruff/__main__.py` execs (or on Windows `subprocess.run`s) the native binary located by `find_ruff_bin`, which searches sysconfig script directories rather than embedding the linter in Python.
- Shared front-end: `ruff_python_parser::parse` builds a `Parsed<Mod>` via `Parser::new`, and both the linter (`lint_only`) and the formatter (`format_module_source`) consume that parse. The linter crate documents its public API as completely unstable.
- Ruff settings come from `ruff_workspace`. `project_files_in_path` normalizes paths, walks ancestors for `pyproject.toml` when hierarchical discovery is on, and walks the tree with the `ignore` crate's `WalkBuilder` (gitignore on, hidden files included, at most 12 threads).
- Lint/format caches live in `.ruff_cache` (`ruff_cache::CACHE_DIR_NAME`). `Cache::open` stores one rkyv file per package at `cache_dir/VERSION/<settings key>` and drops entries if the package root does not match.
- ty's persistent state is a Salsa `ProjectDatabase` created by `ProjectDatabase::fallible`. `check` and `check_with_reporter` delegate to `Project::check`. One-shot CLI checks call `disable_lru` and may `freeze` inputs; `run_check` then `mem::forget`s the database after optional `TY_MEMORY_REPORT` dumps.
- Language servers are separate crates speaking stdio LSP: `ruff server` calls `ruff_server::run` (worker threads capped at 4); `ty server` calls `ty_server::run_server` with an `OsSystem` fallback and the same thread cap.
- Release shape is cargo-dist 0.31.0 (`dist = false` on the workspace, local artifact jobs `./build-binaries`, `./build-docker`, `./build-wasm`; publish jobs PyPI, wasm, and crates). Installers are shell and PowerShell for a long target list, hosted at `https://releases.astral.sh/github/ruff/releases/download/{tag}`. The Docker image is `FROM scratch` with `ENTRYPOINT ["/ruff"]` and `WORKDIR /io`.
- In-browser entry points are `ruff_wasm` (`Workspace::new` deserializes `Options` into `Settings`) and the npm workspaces `ruff`, `ty`, and `shared` under `playground/`, built with Vite, React, Tailwind, and wasm-pack. Sharing uses a Cloudflare Worker in `playground/api`.