Skip to content

Primitives

Prose is built from a small set of shared primitives, each with one responsibility. A rule reads source through Source, reads the AST through one of the shared walkers, emits Edit lists, and reports diagnostics through the Pipeline. Every rule in the catalog is composed from the pieces named below, so a new rule is a thin walker plus its own per-rule decision rather than an implementation from scratch. The padding math, the comment attachment, and the conflict discipline each live in one place, and the rules read them from there.

The graph below traces how a source flows through the primitives, each node one primitive and each edge one consumer relationship (A → B reads as "A is consumed by B"). The nodes match the registries below, and hovering a node shows the primitive's one-line role.

Hover a tile to see what it draws from and what it feeds into.

The Surface

Public Primitives

Reachable from a downstream Rust consumer today:

PrimitiveRole
PipelineRuns the registered rules in a fixed order, splicing each batch of independent rules in one pass and reparsing between batches, and returns the rewritten source with its diagnostics or the rules that still edit it.
RuleIdThe kebab-case slug that names each rule across the CLI, config, suppressions, and diagnostics.
SourceOwns the original text, the AST, the token stream, the line index, and the derived tables every rule reads.

Crate-Internal Primitives

pub(crate) today and opening toward 1.0, when consumer-implemented rules become reachable:

PrimitiveRole
AlignerComputes the padding each row of an alignment group needs and emits the edits that write it.
BindingAnalysisPer-source table recording every write and read of every name in every lexical scope.
CacheStores each file's diagnostics and rewrite on disk under a key derived from its source, config, rules, and version, so a repeat run over an unchanged file skips the pipeline.
ColonTargetsReads through every : context in a module and builds an alignment member for each.
DocstringVisits every PEP 257 docstring in a module in source order and hands each one to the rule reading it.
EditThe Edit { range, content } value every rule emits and the pipeline applies.
OrdererReorders sibling AST nodes by a classifier closure and keeps each node's attached comments with it.
SuppressionMapPer-source index of every # fmt: off, # fmt: skip, and # prose: ignore[...] directive, read before an edit or a lint is emitted.
WalkerIgnore-aware filesystem walker yielding every .py, .pyi, and .pyw source file and every .ipynb notebook under the given paths.

Reading Order

For a downstream Rust consumer integrating Prose through the public API, the pages to read are Source (input), Pipeline (runner), and RuleId (slug type). The three together cover construction, execution, and the slug type every CLI flag and config table names a rule by.

For a rule author working inside the Prose crate, the reading path starts at Edit (the unit every rule emits) and continues to Pipeline (the runner the rule registers with). From there, which walker primitive to read depends on what the rule does:

Source is the input every walker reads, and SuppressionMap is the filter every emitted edit and diagnostic passes through.

The Rules page lists every rule each primitive appears under, the Configuration reference covers the [tool.prose] table that drives the Pipeline's rule selection, and the Pipeline Order reference covers the fixed order the rules run in.