CodeVetter · Repo Unpack · Data flow
astral-sh/ruff
Ruff and ty both start from OS arguments and project files, never from a network service in the CLI. Ruff turns paths into per-file source text, a parse, noqa/suppression directives, and diagnostics, then either prints them, writes fixes, or stores a negative cache entry. ty loads project metadata into a Salsa database, type-checks files in parallel, and optionally rewrites source. The only intentional subprocess is uv, and only when `TY_UV` enables it. The playground is the network boundary: the browser runs WASM locally and optionally POSTs source to Workers KV.
- Input boundary for both CLIs is `wild::args_os` expanded by `argfile::expand_args_from` (prefix `@`) before clap parsing. Ruff also honors `FORCE_COLOR` via `colored_override` and `RUFF_OUTPUT_FORMAT` / `RUFF_OUTPUT_FILE`.
- `ruff check` calls `resolve::resolve` for the root config, then `project_files_in_path`. Enabled rules decide whether `.py` and pyproject/ruff TOML files stay in the set. Package roots come from `resolver.package_roots`, and per-file `LinterSettings` come from `resolver.resolve(path)`.
- Per-file lint transform in `diagnostics::lint_path`: cache lookup by relative path plus `FileCacheKey` (mtime and permission mode); on miss, `SourceKind::from_path`; then `lint_fix` (apply or diff) or `lint_only`. `lint_only` parses, builds `Locator`, `Stylist`, and `Indexer`, extracts noqa directives and `Suppressions`, and calls `check_path`.
- `check_path` is phased: token rules, filesystem rules, logical-line rules, then (only if the parse is valid) `check_ast` plus import sorting and docstring line collection, then physical-line rules. AST checking is `checkers::ast::check_ast`. Diagnostics are sorted with `Diagnostic::ruff_start_ordering` before return.
- Output boundary for a check: `Printer` writes violations to stdout, or to `RUFF_OUTPUT_FILE` (parent directories created, color forced off) unless `--watch`. `--fix` writes transformed source with `File::create`; `--diff` writes a unified diff to stdout. Watch mode uses `notify::recommended_watcher` and re-resolves config when a `.toml` changes.
- Cache write path: after the parallel fold, `caches.persist()` runs `Cache::persist`, which rkyv-serializes `PackageCache` to a temp file in the cache directory and renames it into place. Windows `PermissionDenied` on that rename is warned, not failed. A cache hit with noqa enabled returns empty diagnostics and skips re-lint.
- ty input flow: cwd from `current_directory`, optional `--project` directory, absolute check paths, `OsSystem`, and `UseUv::from_system`. Metadata is `ProjectMetadata::from_config_file` or `discover_with_uv`, then `apply_configuration_files` and `set_override_options`. A single PEP 723 script file forces `UseUv::Scripts` even when uv is otherwise on.
- ty check execution: `MainLoop::main_loop` synchronizes script environments, then on `CheckWorkspace` clones the database and Rayon-spawns `db.check_with_reporter`. `Project::check` reports settings and file-set diagnostics, then `into_par_iter` calls salsa `check_file_impl`, which calls `ty_python_semantic::check_file` unless script settings are invalid. Results are discarded if the revision moved.
- ty fix output: `FixMode::ApplyFixes` calls `fix_all_diagnostics` with `Applicability::Safe` only; `FixMode::AddIgnore` calls `suppress_all_diagnostics`. `--exit-zero` forces `ExitStatus::Success` after a non-internal result. `TY_MEMORY_REPORT=short|full|json` dumps Salsa memory on the summary stream.
- When uv is enabled, `Uv::execute` runs `Command::new(executable)` with args `workspace metadata --quiet`. Workspace targets add `--active`; script targets add `--sync --script <path>` and optional `--python`. The executable is `UV` if set, otherwise `system.which("uv")`.
- Playground data flow: the SPA keeps editor state in localStorage and runs Ruff or ty as WASM. Share URLs hit the Worker: GET `/{id}` reads Workers KV namespace `PLAYGROUND`; POST reads the raw body, stores it under `crypto.randomUUID()`, and returns the id. Production CORS allows `https://play.ruff.rs` plus `playknot.ruff.rs`, `types.ruff.rs`, and `play.ty.dev`.