This guide is for engineers, architects, and contributors who need to understand how the
Ruff repository is built, how its two shipped tools work internally, and how to operate,
extend, and reason about the codebase. For day-to-day usage of the ruff and ty
commands, see the companion User Guide.
Table of Contents
- Executive Summary
- Repository Architecture
- How Ruff lints: the
check_pathpipeline - How Ruff formats
- How ty type-checks: the Salsa engine
- Configuration system
- Concurrency and performance
- Caching
- Language servers
- Build, requirements, and toolchain
- Operations
- Security analysis
- Testing strategy
- Code quality & conventions
- Extending the codebase
- Potential improvements
- Quick Reference
Executive Summary
The astral-sh/ruff repository is a single Cargo workspace of roughly three dozen
crates that compiles into two independent command-line binaries:
ruff— an extremely fast Python linter and code formatter.ty— an extremely fast Python type checker and language server.
Both are written entirely in Rust and ship as self-contained native binaries (a thin
Python wheel wraps the compiled binary for pip install). The two tools share a large
substrate of common crates — a Python parser, an AST, source-text utilities, a
diagnostics renderer, and a Salsa-based incremental database — but they are separately
published and separately consumed.
| Property | Value |
|---|---|
| Primary language | Rust (Cargo workspace) |
| Shipped binaries | ruff, ty |
| Workspace crates | ~37 crates/* plus playground/* (web) and python/* (tooling) |
| Source size | ~13.6M characters across ~4,800 code files |
| CLI framework | clap (derive style) |
| Incremental engine | salsa (used by ruff_db / ty) |
| Parallelism | rayon |
| Source commit | fd16b26 |
Note
Because the linter alone implements 800+ rules (reimplementing Pyflakes, pycodestyle, isort, pyupgrade, pydocstyle, and many flake8 plugins), this guide documents the architecture and operation of the engine rather than enumerating individual rules. The rule set is exposed at runtime through
ruff linterandruff rule.
Repository Architecture
Two products, one workspace
The repository is best understood as a multi-product monorepo rather than a single application:
astral-sh/ruff (Cargo workspace)
│
├── ruff (binary) ──► linting + formatting of Python source
│
├── ty (binary) ──► type checking + language server for Python
│
├── shared foundation crates (parser, AST, source text, diagnostics, Salsa db)
│
├── playground/ (TypeScript/React web playgrounds for ruff and ty)
└── python/ (Python-side tooling: ecosystem checks, fuzzer, wheel wrapper)
The top-level directory layout:
| Path | Contents |
|---|---|
crates/ |
All Rust crates — the engines, both binaries, and every supporting library. |
playground/ |
Browser playgrounds (playground/ruff, playground/ty, plus shared and api) built on the WASM crates. |
python/ |
Python-side packages: ruff (wheel wrapper), ruff-ecosystem (real-world regression checks), py-fuzzer. |
scripts/ |
Maintenance and benchmarking scripts. |
docs/ |
Project documentation site sources (MkDocs Material). |
fuzz/ |
Cargo-fuzz targets. |
Architectural layers
Rather than thinking about ~37 crates individually, group them into layers. Data flows upward: low-level text and parsing crates feed the AST, which feeds the semantic/type layers, which feed the linter, formatter, and type checker, which are wrapped by the two binaries.
┌──────────────────────────────────────────────────────────────┐
│ Binaries (user-facing) │
│ ruff (crates/ruff) ty (crates/ty) │
├──────────────────────────────────────────────────────────────┤
│ Tool engines │
│ ruff_linter ruff_python_formatter ty_python_semantic │
│ ruff_formatter (generic IR/printer) ty_project / ty_ide │
├──────────────────────────────────────────────────────────────┤
│ Language understanding │
│ ruff_python_parser → ruff_python_ast → ruff_python_semantic │
│ ruff_python_index ruff_python_trivia ty_module_resolver │
├──────────────────────────────────────────────────────────────┤
│ Shared foundation │
│ ruff_db (Salsa database, file system, diagnostics render) │
│ ruff_source_file ruff_text_size ruff_diagnostics │
│ ruff_cache ruff_index ruff_macros ruff_notebook │
└──────────────────────────────────────────────────────────────┘
Crate map
The most important crates, grouped by role. (Char counts are approximate, from the analyzed snapshot, and indicate relative weight.)
User-facing binaries
| Crate | Role |
|---|---|
ruff |
The ruff binary: CLI parsing (args.rs), command dispatch (commands/), file caching (cache.rs). |
ty |
The ty binary: CLI (args.rs), main loop & watch mode (lib.rs), logging, printer. |
ruff_dev |
Internal developer CLI: schema/docs/CLI-reference generation, AST/CST/token dumps, format-dev harness. |
Linter engine
| Crate | Role |
|---|---|
ruff_linter |
The linter: rule registry (codes.rs/registry.rs), checkers (checkers/), all rules/ plugins, the check_path/lint_only/lint_fix pipeline, # noqa handling (noqa.rs, directives.rs), fixes (fix/). |
ruff_python_semantic |
Semantic model used by lint rules (bindings, scopes, references, control-flow graph). |
ruff_python_stdlib |
Knowledge of the Python standard library (builtins, module membership). |
ruff_diagnostics |
Diagnostic and fix data types shared across the linter. |
Formatter engine
| Crate | Role |
|---|---|
ruff_python_formatter |
Python-specific formatter: turns the AST into formatter IR (statements, expressions, comments, strings). |
ruff_formatter |
Generic, language-agnostic formatter IR and printer (the "format element" + printer that ruff_python_formatter targets). |
ruff_python_codegen |
Source generation / stylist (detects existing quote and indentation style). |
Parser / AST / source primitives
| Crate | Role |
|---|---|
ruff_python_parser |
Hand-written lexer + parser producing the Python AST and tokens. |
ruff_python_ast |
The Python AST node definitions (largely code-generated, see generated.rs) and visitors. |
ruff_python_index |
Indexes tokens/comments for fast lookups during linting. |
ruff_python_trivia |
Whitespace/comment ("trivia") analysis. |
ruff_python_literal |
Literal evaluation helpers (numbers, strings, f-strings). |
ruff_source_file |
Source file abstraction: line index, positions, encodings. |
ruff_text_size |
Byte-offset text range primitives used everywhere. |
ty type system
| Crate | Role |
|---|---|
ty_python_semantic |
The type inference and type-checking core (the largest semantic crate). |
ty_python_core |
Core type-system building blocks and use-def analysis. |
ty_project |
Project model, project database, configuration metadata, file watching, glob handling. |
ty_module_resolver |
Resolves imports to modules using the Python environment and search paths. |
ty_vendored |
Vendored typeshed stubs (stdlib type stubs bundled into the binary at build time). |
ty_ide |
IDE features (completions, hover, call hierarchy, docstrings) shared by the server. |
ty_combine |
Configuration "combine"/merge trait for layering options. |
ty_static |
Static data including the EnvVars registry. |
Shared foundation
| Crate | Role |
|---|---|
ruff_db |
The Salsa-based incremental database: file inputs, tracked parse/source queries, file-system abstraction (OsSystem), diagnostics rendering, cancellation. |
ruff_cache |
On-disk cache key machinery for the linter. |
ruff_index |
Typed index/arena collections. |
ruff_macros |
Procedural macros (e.g. CacheKey, option metadata derives). |
ruff_notebook |
Jupyter notebook parsing and cell handling. |
ruff_annotate_snippets |
Renders annotated source snippets in diagnostics. |
ruff_options_metadata |
Reflection over configuration options (powers ruff config). |
ruff_workspace |
Configuration resolution for ruff: the Options/Configuration schema and settings layering. |
ruff_graph |
Import dependency-graph construction (powers ruff analyze graph). |
Servers, WASM, and tooling
| Crate | Role |
|---|---|
ruff_server |
The ruff server language server (LSP). |
ty_server |
The ty server language server (LSP). |
ruff_wasm / ty_wasm |
WebAssembly bindings powering the browser playgrounds. |
ruff_benchmark / ty_completion_bench |
Benchmark harnesses. |
ruff_mdtest / mdtest / ty_test |
Markdown-driven test harnesses (notably for ty's inference tests). |
ruff_memory_usage |
Heap-size accounting used by Salsa memory reports. |
How Ruff lints: the check_path pipeline
The heart of the linter is ruff_linter::check_path (in crates/ruff_linter/src/linter.rs).
For a single file, the source is first tokenized and parsed (producing Parsed<ModModule>
and a token stream), then directives (# noqa, # isort: skip, # TODO) are extracted.
check_path then runs the enabled rules grouped by their lint source — the kind of
input a rule needs — so each pass only runs if at least one enabled rule requires it:
source text
│
▼ ruff_python_parser
tokens + AST (Parsed<ModModule>) + Indexer (comment ranges, etc.)
│
▼ directives: extract # noqa / # isort: skip / # TODO
│
├─► token-based rules (check_tokens) — always available
├─► filesystem-based rules (check_file_path) — path/package rules
├─► logical-line rules (check_logical_lines) — pycodestyle-style
│
▼ if syntax is valid:
├─► AST-based rules (check_ast) — builds the semantic model
└─► import rules (check_imports) — isort
│
▼
aggregate Diagnostics → apply # noqa suppression → (optionally) apply fixes
Key properties:
- Rules declare their input. Each rule advertises a "lint source" (tokens, filesystem, logical lines, AST, or imports). A pass is skipped entirely if no enabled rule needs it, which is a major reason Ruff is fast.
- AST rules require valid syntax. AST- and import-based rules run only when the file
parses cleanly (
parsed.has_valid_syntax()); token- and filesystem-based rules still run on files with syntax errors. - The semantic model is built during the AST pass.
check_ast(incrates/ruff_linter/src/checkers/ast/) walks the tree, building bindings, scopes, and references viaruff_python_semantic, and dispatches semantic rules as it goes. - Two public entry points wrap
check_path:lint_only(report only) andlint_fix(report and apply fixes, re-linting iteratively until the code stabilizes). - Suppression is a post-filter.
# noqacomments are matched against produced diagnostics after the fact (noqa.rs), which is also how--add-noqaand theRUF100unused-noqa rule are implemented.
Preview behavior is gated through crates/ruff_linter/src/preview.rs, which exposes named
predicate functions instead of raw preview flag checks, so that promoting a preview
feature to stable is a matter of deleting its predicate.
How Ruff formats
The formatter is independent of the linter. ruff_python_formatter lowers the parsed AST
into a generic, language-agnostic intermediate representation defined by ruff_formatter
(the "format element" tree), and a printer then renders that IR back to text under the
active [tool.ruff.format] settings (line length, quote style, indentation, trailing
commas, line endings, docstring code formatting). Because the formatter consumes the same
parser and AST as the linter, formatting and linting always agree on the structure of the
code. The result is a Black-compatible style with Ruff-specific options layered on top.
Range formatting (ruff format --range) maps a 1-based line/column range to a byte range
(FormatRange::to_text_range) and formats only the enclosing logical lines; it is
restricted to a single, non-notebook file.
How ty type-checks: the Salsa engine
ty is built on Salsa, an incremental computation framework. The shared crate
ruff_db defines a Salsa database trait (#[salsa::db] pub trait Db: salsa::Database)
whose inputs are files (#[salsa::input]) and whose derived values — parsed ASTs, source
text, and so on — are #[salsa::tracked] queries with memoization and LRU eviction (for
example the parsed-AST query is capped at an LRU of 200 entries). When a file changes, Salsa
invalidates only the queries that transitively depend on it and recomputes the minimum
necessary, which is what makes watch mode cheap.
ty check (in crates/ty/src/lib.rs) is structured as a message-driven main loop:
ty check
│
▼ discover project metadata (ProjectMetadata::discover or ::from_config_file)
▼ apply configuration files + CLI overrides
▼ build a ProjectDatabase (Salsa)
│
▼ MainLoop (crossbeam channel of messages)
│ ├─ CheckWorkspace → rayon::spawn a background check; report progress
│ ├─ CheckCompleted → render diagnostics, compute exit status
│ ├─ ApplyChanges → (watch mode) invalidate & re-check on file events
│ └─ Exit → cancel pending queries and stop
▼
diagnostics → printer → exit code
Notable design points:
- Module resolution uses your environment.
ty_module_resolverresolves third-party imports through the Python environment selected by--python/--venv(or inferred), and stdlib types come fromty_vendoredtypeshed stubs baked into the binary. - Cancellation is first-class.
Ctrl+Ctriggers a cancellation token; in-flight Salsa queries are cancelled cooperatively (salsa::Cancelled::catch), and watch mode cancels and reschedules on every change. - Fix and suppression modes share the loop.
--fix(fix_all_diagnostics) and--add-ignore(suppress_all_diagnostics) are alternateMainLoopMode::Fixbranches that reuse the same check results. - Severity drives the exit code. ty maps the maximum diagnostic severity to an exit
status (see Exit codes); warnings only fail the build under
--error-on-warning, and I/O diagnostics produce exit code2. - Memory introspection is built in. Setting
TY_MEMORY_REPORTtoshort,full, orjsondumps Salsa's memory usage after a check.
Configuration system
The two tools have parallel but separate configuration stacks.
Ruff configuration lives in ruff_workspace. The schema is the serde Options struct
(options.rs) projected into a resolved Configuration (configuration.rs), split into:
- top-level settings (
line-length,indent-width,target-version,src,include,exclude,respect-gitignore,fix,output-format,preview,required-version,extend,cache-dir, …), LintConfiguration→[tool.ruff.lint](rule selection, per-file ignores, plus a sub-table per upstream plugin:isort,pycodestyle,pydocstyle,mccabe,pylint,pyupgrade, theflake8-*family,ruff, …),FormatConfiguration→[tool.ruff.format](quote-style,indent-style,line-ending,skip-magic-trailing-comma,docstring-code-format,docstring-code-line-length, …),AnalyzeConfiguration→[tool.ruff.analyze](import-graph options).
Resolution walks up the directory tree from each file, so nested projects can override
settings. Precedence, lowest to highest: configuration files → --config "KEY = VALUE"
inline overrides → dedicated CLI flags (--line-length, --select, …). The
--config flag is overloaded: it accepts either a config-file path or an inline TOML
override (parsed by ConfigArgumentParser in crates/ruff/src/args.rs). --isolated
discards all config files; ruff_options_metadata powers the self-describing ruff config
command.
ty configuration lives in ty_project::metadata::options. It reads ty.toml or the
[tool.ty] table of pyproject.toml, organized into environment, src, terminal, and
rules sub-tables. CLI flags are converted into the same Options type
(CheckCommand::into_options) and merged with --config overrides via the ty_combine
Combine trait, so the CLI and config file share one schema.
Concurrency and performance
- Data parallelism via rayon. Both tools build a global rayon thread pool and process
files in parallel. ty bounds the pool to
max_parallelism()and a fixed stack size; the pool size can be capped withTY_MAX_PARALLELISM. - Message passing via crossbeam. ty's main loop communicates with background check tasks
over a bounded crossbeam channel, keeping the orchestrating thread responsive (and able to
handle
Ctrl+Cand watch events) while checks run on rayon. - Incrementality via Salsa. Memoized, dependency-tracked queries mean unchanged files are not re-parsed or re-analyzed across a watch session.
- Custom allocator. On supported 64-bit, non-macOS/Windows targets, ty uses
jemalloc(tikv-jemallocator) as the global allocator for throughput. - Skip-work-by-default. The linter only runs a rule pass if an enabled rule needs that input kind (see the pipeline above), avoiding tokenization/semantic work that no active rule would consume.
Caching
Ruff persists a per-package on-disk cache (crates/ruff/src/cache.rs, built on
ruff_cache). The cache directory defaults under the configured cache-dir and is keyed
by the Ruff VERSION and the resolved settings, so changing the version or configuration
invalidates it automatically. Per-file cache keys combine the file's last-modified time and
permission bits (FileCacheKey). Disable reads with --no-cache/RUFF_NO_CACHE; wipe the
cache with ruff clean.
ty caches in memory through Salsa for the duration of a process (especially valuable in watch and server modes); it does not rely on the on-disk lint cache.
Important
The Ruff cache is keyed on the binary version. After upgrading Ruff, the old cache is simply ignored rather than producing stale results — there is no manual migration step.
Language servers
Each tool ships an LSP server reusing the same engine as its CLI:
ruff server(ruff_server) provides diagnostics, quick-fixes, import organization, and formatting. It shares Ruff's configuration resolution, so editor results match CLI results.--previewenables unstable server features and turns on preview for the linter and formatter.ty server(ty_server, with IDE features fromty_ide) provides type diagnostics, hover, completions, and related language features over the same Salsa project database used byty check.
Editors normally spawn these servers via an extension rather than the user invoking them
directly. A migration note for users coming from ruff-lsp lives in crates/ruff_server/docs.
Build, requirements, and toolchain
- Build system: Cargo workspace. Build the binaries with
cargo build --release -p ruffandcargo build --release -p ty. A Rust toolchain is required (see the repository'srust-toolchain.toml). - Runtime requirements: None beyond the native binary. Ruff and ty do not require a
Python interpreter to run; ty does need access to your project's Python environment to
resolve third-party imports (via
--python), but that is data input, not a runtime dependency of the tool itself. - Code generation at build time: Parts of the AST (
ruff_python_ast/src/generated.rs) and schema/reference docs are generated.ruff_devexposes generators guarded by environment switches such asRUFF_UPDATE_SCHEMA,TY_UPDATE_SCHEMA(regenerate JSON schemas), and the variousgenerate_ty_*commands (CLI/options/rules/env-var references).ty_vendored/build.rscopies typeshed stubs into the binary usingOUT_DIR. - Docs site: The documentation site is MkDocs Material. The pinned toolchain in
docs/requirements.txtincludesmkdocs==1.6.1,mkdocs-material==9.7.6,ruff==0.15.15,mdformat==1.0.0, and related plugins. - Python-side tooling:
python/ruff-ecosystemruns Ruff against real-world projects to detect behavioral regressions;python/py-fuzzerfuzzes the parser/formatter;scripts/holds benchmarking and maintenance utilities (with their ownpyproject.tomlthat itself uses[tool.ruff]and[tool.ty]).
Operations
This repository produces developer tools rather than a long-running service, so "operations" means running the binaries in CI and developer workflows.
Run in CI (no writes, fail on issues):
ruff check --output-format github # lint with GitHub Actions annotations
ruff format --check # fail if any file is unformatted
ty check --error-on-warning # fail on type errors and warnings
Pin the expected version so a project fails fast on drift:
[tool.ruff]
required-version = ">=0.15"
Diagnose configuration problems:
ruff check --show-settings path/to/file.py # resolved settings for a file
ruff check --show-files # which files would be analyzed
ty check -v # verbose; -vv / -vvv for more
Profiling ty:
TY_LOG=ty=debug ty check # detailed tracing
TY_LOG_PROFILE=1 ty check # write a flamegraph profile (tracing.folded)
TY_MEMORY_REPORT=full ty check # dump Salsa memory usage
Tip
The
ruff_devcrate is the maintainers' Swiss-army knife —cargo run -p ruff_dev -- …can print the AST/CST/tokens of a file, regenerate schemas and docs, and run the formatter-development harness. It is not shipped to end users.
Security analysis
Ruff and ty are static analysis tools: they read source files and (optionally) write formatted/fixed source back. They are not network services and expose no remote attack surface in normal use.
| Area | Assessment |
|---|---|
| Network | The core binaries do not make network calls during check/format. (Python-side ecosystem tooling clones repositories for testing; that is developer tooling, not the shipped binary.) |
| Code execution | Ruff and ty parse and analyze Python; they do not execute the target code. This is a fundamental safety property versus runtime tools. |
| File writes | --fix (ruff/ty) and ruff format modify files in place. Treat them like any code-mutating tool: run on a clean VCS tree and review diffs. --diff/--check provide non-destructive previews. |
| Untrusted input | The parser and formatter are continuously fuzzed (fuzz/, python/py-fuzzer) precisely because they ingest arbitrary, possibly malicious source text. Internal panics map to exit code 101 (ty) and are reported as bugs rather than silently ignored. |
| Configuration | Config is TOML parsed into typed structs; unknown keys and malformed values are rejected with actionable errors rather than executed. |
| Path handling | File discovery respects .gitignore by default and supports force-exclude; --isolated removes ambient config influence for reproducible runs. |
Caution
The most common operational hazard is
--fix/formatrewriting files. Always run these against version-controlled code so changes are reviewable and reversible.
Testing strategy
The repository combines several layers of testing:
- Snapshot tests (
insta-stylesnapshots/directories across the linter and formatter) pin rule output and formatted output so regressions are caught as diffs. - Markdown-driven tests (
mdtest,ruff_mdtest,ty_test) — particularly for ty's type inference — encode expected diagnostics inline in Markdown fixtures underresources/mdtest/, which double as living documentation of type-system behavior. - CLI integration tests (
crates/ruff/tests/cli,crates/ty/tests/cli) exercise the binaries end to end. (Issue #19016 tracks ongoing cleanup of Ruff's CLI tests.) - End-to-end LSP tests (
crates/ruff_server/tests/e2e,crates/ty_server/tests/e2e). - Fuzzing (
fuzz/fuzz_targets,python/py-fuzzer) for the parser and formatter. - Ecosystem checks (
python/ruff-ecosystem) run Ruff against real-world projects to surface behavioral changes before release. - Benchmarks (
ruff_benchmark,ty_completion_bench,scripts/benchmarks) guard performance, using vendored real-world files (numpy, pydantic, CPython's tomllib, etc.).
Code quality & conventions
- Crate granularity. Functionality is split into many small, single-responsibility crates, which keeps compile units focused and makes the dependency graph (and therefore the data-flow layering) explicit.
- Code generation. The AST and several reference documents are generated rather than
hand-maintained (
generated.rs,ruff_devgenerators), reducing drift between the implementation and its schemas/docs. - Preview-feature discipline. New rules and behaviors land behind named preview
predicates (
preview.rs) so they can be tested in the field and promoted by deleting a single function. - Self-describing surfaces. Both CLIs use
clapderive structs as the single source of truth for arguments and help;ruff_options_metadatamakes the configuration schema introspectable (ruff config). - Centralized environment variables. ty centralizes its environment variables in
ty_static'sEnvVarsregistry, keeping the documented set and the consumed set in sync.
Extending the codebase
Adding a lint rule (high level):
- Implement the rule under
crates/ruff_linter/src/rules/<plugin>/rules/, declaring its lint source (tokens / AST / logical lines / filesystem / imports) so it joins the right pass incheck_path. - Register its code in the registry (
codes.rs);registry.rsre-exports from there. - Add fixtures and snapshots under the plugin's
resources//snapshots/directories. - Gate unstable behavior behind a
preview.rspredicate until it stabilizes.
Adding/adjusting a configuration option:
- Add the field to the relevant
Optionsstruct inruff_workspace(or the ty options inty_project::metadata::options). - Thread it into the resolved
Configuration/settings. - Regenerate schemas/docs via the
ruff_devgenerators (RUFF_UPDATE_SCHEMA/TY_UPDATE_SCHEMA).
Working on the type checker: add Markdown inference tests under
crates/ty_python_semantic/resources/mdtest/ — they are the canonical way to specify and
verify ty's behavior, and they render as documentation.
Potential improvements
These are observations from the codebase and its tracked issues, not defects:
- CLI test cleanup is explicitly tracked (issue #19016: "Cleanup Ruff's CLI tests"), indicating the CLI test suite is an area of active consolidation.
- A known panic exists in ty's IDE layer (issue #25639: a panic when hovering over an inlay hint in VS Code). Panics in the language server degrade the editor experience and surface as internal errors — hardening hover/inlay paths against unexpected states would improve robustness.
- Preview surface management. The named-predicate approach in
preview.rsis sound; periodic audits to delete predicates for already-promoted features keep the surface clean. - Rule-message consistency. Tracked issues such as #14743 (a violation message showing the wrong type) show that diagnostic wording occasionally lags behavior; snapshot tests help, but message accuracy benefits from continued review.
Quick Reference
Build:
cargo build --release -p ruff
cargo build --release -p ty
ruff subcommands: check, format, rule, linter, config, clean,
analyze graph, server, version, help.
ty subcommands: check, server, explain rule, version.
Ruff environment variables: RUFF_OUTPUT_FORMAT, RUFF_OUTPUT_FILE, RUFF_NO_CACHE,
RUFF_CACHE_DIR.
ty environment variables: TY_CONFIG_FILE, TY_OUTPUT_FORMAT, TY_LOG,
TY_LOG_PROFILE, TY_MEMORY_REPORT, TY_MAX_PARALLELISM.
Build/dev environment switches: RUFF_UPDATE_SCHEMA, TY_UPDATE_SCHEMA,
MDTEST_UPGRADE_LOCKFILES, CARGO_MANIFEST_DIR/OUT_DIR/TARGET (standard Cargo).
ty exit codes: 0 success · 1 errors (or warnings with --error-on-warning) ·
2 invocation/I-O error · 101 internal error (panic).
Ruff exit codes: 0 no violations · 1 violations found (modifiable with
--exit-zero / --exit-non-zero-on-fix).
Config files: ruff.toml / .ruff.toml / [tool.ruff] in pyproject.toml
(linter+formatter); ty.toml / [tool.ty] in pyproject.toml (type checker).
Key source locations:
| Concern | Location |
|---|---|
| Ruff CLI definition | crates/ruff/src/args.rs |
| Ruff command dispatch | crates/ruff/src/commands/ |
| Lint pipeline | crates/ruff_linter/src/linter.rs (check_path) |
| Rule registry | crates/ruff_linter/src/codes.rs, registry.rs |
| Ruff config schema | crates/ruff_workspace/src/{options,configuration}.rs |
| Formatter | crates/ruff_python_formatter/, crates/ruff_formatter/ |
| ty CLI + main loop | crates/ty/src/{args.rs,lib.rs} |
| Type system | crates/ty_python_semantic/, crates/ty_python_core/ |
| Project/Salsa db | crates/ty_project/, crates/ruff_db/ |
| Parser / AST | crates/ruff_python_parser/, crates/ruff_python_ast/ |