Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Processors

RSConstruct uses processors to discover and build products. Each processor scans for source files matching its conventions and produces output files.

Processor Types

There are four processor types: checker, generator, explicit, and mass generator. They differ in how inputs are discovered, how outputs are declared, and how results are cached.

See Processor Types for full descriptions, examples, and a comparison table.

Configuration

Declare processors by adding [processor.TYPE.NAME] sections to rsconstruct.toml:

[processor.checker.ruff]

[processor.checker.pylint]
args = ["--disable=C0114"]

[processor.generator.cc_single_file]

Only declared processors run — no processors are enabled by default. Use rsconstruct smart auto to auto-detect and add relevant processors.

Use rsconstruct processor list to see declared processors and descriptions. Use rsconstruct processor list --all to show all built-in processors, not just those enabled in the project. Use rsconstruct processor files to see which files each processor discovers.

Available Processors

  • Tera — renders Tera templates into output files
  • Ruff — lints Python files with ruff
  • Pylint — lints Python files with pylint
  • Mypy — type-checks Python files with mypy
  • Pyrefly — type-checks Python files with pyrefly
  • CC — builds full C/C++ projects from cc.yaml manifests
  • CC Single File — compiles C/C++ source files into executables (single-file)
  • Linux Module — builds Linux kernel modules from linux-module.yaml manifests
  • Cppcheck — runs static analysis on C/C++ source files
  • Clang-Tidy — runs clang-tidy static analysis on C/C++ source files
  • Shellcheck — lints shell scripts using shellcheck
  • Zspell — checks documentation files for spelling errors
  • Rumdl — lints Markdown files with rumdl
  • Oxlint — lints JavaScript/TypeScript files with oxlint
  • Selene — lints Lua files with selene
  • Iluacheck — lints Lua files with luacheck’s analysis (native)
  • Biome — lints CSS/JavaScript/TypeScript/JSON files with biome
  • Make — runs make in directories containing Makefiles
  • Cargo — builds Rust projects using Cargo
  • Yamllint — lints YAML files with yamllint
  • Jq — validates JSON files with jq
  • Jsonlint — lints JSON files with jsonlint
  • Taplo — checks TOML files with taplo
  • Terms — checks that technical terms are backtick-quoted in Markdown files
  • Json Schema — validates JSON schema propertyOrdering
  • Iyamlschema — validates YAML files against JSON schemas (native)
  • Yaml2json — converts YAML files to JSON (native)
  • Markdown2html — converts Markdown to HTML using markdown CLI
  • Imarkdown2html — converts Markdown to HTML (native)
  • Mass Generator — runs a tool that enumerates its outputs in advance, one cached product per predicted file
  • Zola — builds a zola site, one cached product per file zola writes, planned natively

Clean behavior

rsconstruct clean outputs calls each product’s processor-defined clean(). What gets removed depends on the processor type:

Processor typeWhat clean() removesRecursive?
CheckerNothing — checkers produce no outputs—
GeneratorEach declared output file (product.outputs)No
ExplicitDeclared output_files + declared output_dirsYes (for output_dirs only)
Mass generatorEach predicted output file (product.outputs)No

Recursive directory removal is reserved for the user-declared output_dirs of Explicit. All other processor types remove individually-declared files and nothing else. A mass generator’s output_dirs only bound where its predicted files may live; the directory itself is never removed directly, though the empty-directory sweep removes directories that become empty.

After every product’s clean() completes, the orchestrator runs an empty-directory sweep: every parent of every removed output (and every parent of every removed output_dir) is tried with fs::remove_dir (non-recursive — succeeds only on already-empty directories), walking upward until a non-empty directory or the project root. The sweep does not special-case out/ — any ancestor of a cleaned output is eligible.

See rsconstruct clean for the full command reference, the --no-empty-dirs flag, the -p filter, and the other clean variants (all, git, unknown).

Worked example

Consider this project:

# rsconstruct.toml

[processor.checker.ruff]                     # Checker — no outputs
src_dirs = ["src"]

[processor.generator.tera]                   # Generator — declared file outputs
src_dirs = ["templates"]
src_extensions = [".tera"]

[processor.mass_generator.mdbook]            # Mass generator — planned file outputs
src_dirs = ["docs"]

Layout:

project/
├── rsconstruct.toml
├── src/main.py                      # ruff lints this
├── templates/index.html.tera        # tera renders to → out/processor.generator.tera/index.html
├── docs/
│   ├── book.toml
│   └── src/SUMMARY.md
└── book/                            # mdbook output_dir; each file is a planned product
    ├── index.html
    ├── css/general.css
    └── ...

After rsconstruct build, both out/processor.generator.tera/index.html and the planned files under book/ exist.

Now run rsconstruct clean outputs:

  1. ruff — Checker. clean() is a no-op. Nothing removed.
  2. tera — Generator. clean() calls fs::remove_file("out/processor.generator.tera/index.html"). The file goes; out/processor.generator.tera/ and out/ are not yet touched.
  3. mdbook — Mass generator. clean() removes each planned output file under book/.
  4. Empty-directory sweep. The orchestrator collects parents of every removed path (out/processor.generator.tera, out, book/css, book) and removes those that are now empty, deepest-first.

Final state: src/main.py, templates/index.html.tera, docs/..., and rsconstruct.toml remain untouched. The cache (.rsconstruct/) is untouched. out/ and book/ are gone.

If you instead ran rsconstruct clean outputs --no-empty-dirs, the only difference is step 4 is skipped — out/processor.generator.tera/ and out/ would remain as empty directories.

If you ran rsconstruct clean outputs -p processor.generator.tera, only step 2 + the sweep of its parents runs. book/ is left intact because mdbook is filtered out.

Custom Processors

A command of your own runs through a config-driven processor: [processor.checker.script] for a check, [processor.generator.generic] for one output per input, [processor.explicit.generic] for declared inputs and outputs, and [processor.mass_generator.generic] for a tool that can predict its outputs. A new tool with its own discovery or output rules is a new processor file under src/processor/.