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

Processor Types

Every processor in RSConstruct has a type that determines how it discovers inputs, produces outputs, and interacts with the cache. There are four types.

Run rsconstruct processors types to list them.

Checker

A checker validates input files without producing any output. If the check passes, the result is cached — if the inputs haven’t changed on the next build, the check is skipped entirely.

How it works

  1. Scans for files matching src_extensions in src_dirs
  2. Creates one product per input file
  3. Runs the tool on each file (or batch of files)
  4. If the tool exits successfully, records a marker in the cache
  5. On the next build, if inputs are unchanged, the check is skipped

What gets cached

A marker entry — no files, no blobs. The marker’s presence means “this check passed with these inputs.”

Examples

Lint Python files with ruff:

[processor.ruff]

Scans for .py files, runs ruff check on each. No output files produced.

src/main.py → (checker)
src/utils.py → (checker)

Lint shell scripts:

[processor.shellcheck]

Scans for .sh and .bash files, runs shellcheck on each.

Validate YAML files:

[processor.yamllint]

Scans for .yml and .yaml files, runs yamllint on each.

Validate JSON files with jq:

[processor.jq]

Scans for .json files, validates each with jq.

Spell check Markdown files:

[processor.zspell]

Scans for .md files, checks spelling with the built-in zspell engine.

Built-in checkers

ruff, pylint, mypy, pyrefly, black, pytest, doctest, shellcheck, luacheck, yamllint, jq, jsonlint, taplo, cppcheck, clang_tidy, cpplint, checkpatch, mdl, markdownlint, rumdl, aspell, zspell, ascii, encoding, duplicate_files, terms, eslint, jshint, standard, htmlhint, htmllint, tidy, stylelint, jslint, svglint, svgo, perlcritic, xmllint, checkstyle, php_lint, yq, hadolint, slidev, json_schema, iyamlschema, ijq, ijsonlint, iyamllint, itaplo, marp_images, license_header

Generator

A generator transforms each input file into one or more output files. It creates one product per input file (or one per input x format pair for multi-format generators like pandoc).

How it works

  1. Scans for files matching src_extensions in src_dirs
  2. For each input file, computes the output path from the input path, output directory, and format
  3. Creates one product per input x format pair
  4. Runs the tool to produce the output file
  5. Stores the output as a content-addressed blob in the cache

What gets cached

One blob per output file. The blob is the raw file content, stored by its SHA-256 hash. On restore, the blob is hardlinked (or copied) to the output path.

Examples

Render Tera templates:

[processor.tera]

Scans tera.templates/ for .tera files, renders each template. The output path is the template path with the .tera extension stripped:

tera.templates/config.py.tera → config.py
tera.templates/README.md.tera → README.md

Convert Marp slides to PDF:

[processor.marp]

Scans marp/ for .md files, converts each to PDF (and optionally other formats):

marp/slides.md → out/marp/slides.pdf
marp/intro.md → out/marp/intro.pdf

Convert documents with pandoc (multi-format):

[processor.pandoc]

Scans pandoc/ for .md files, converts each to PDF, HTML, and DOCX. Each format is a separate product with its own cache entry:

pandoc/syllabus.md → out/pandoc/syllabus.pdf
pandoc/syllabus.md → out/pandoc/syllabus.html
pandoc/syllabus.md → out/pandoc/syllabus.docx

Compile single-file C programs:

[processor.cc_single_file]

Scans src/ for .c and .cc files, compiles each into an executable:

src/main.c → out/cc_single_file/src/main.elf
src/test.c → out/cc_single_file/src/test.elf

Convert Mermaid diagrams:

[processor.mermaid]

Scans for .mmd files, converts each to PNG (configurable formats):

diagrams/flow.mmd → out/mermaid/diagrams/flow.png

Compile SCSS to CSS:

[processor.sass]

Scans sass/ for .scss and .sass files, compiles each to CSS:

sass/styles.scss → out/sass/styles.css

Built-in generators

tera, mako, jinja2, cc_single_file, pandoc, marp, mermaid, drawio, chromium, libreoffice, protobuf, sass, markdown2html, pdflatex, a2x, objdump, rust_single_file, tags, pdfunite, ipdfunite, imarkdown2html, isass, yaml2json, generator, script

Creator

A creator runs a command and caches declared output files and directories. It scans for anchor files — files whose presence means “run this tool here.” One product is created per anchor file found, and the command runs in the anchor file’s directory.

Unlike generators (where outputs are derived from input paths), creator outputs are declared explicitly in the config via output_dirs and output_files.

How it works

  1. Scans for anchor files matching src_extensions in src_dirs
  2. Creates one product per anchor file
  3. Runs the command in the anchor file’s directory
  4. Walks all declared output_dirs and collects output_files
  5. Stores each file as a content-addressed blob
  6. Records a tree in the cache — a manifest listing every output file with its path, blob checksum, and Unix permissions

What gets cached

A tree entry listing all output files. On restore, the directory tree is recreated from cached blobs with permissions preserved. Individual files within the tree that already exist with the correct checksum are skipped.

Examples

Install Python dependencies with pip:

[processor.creator.venv]
command = "pip"
args = ["install", "-r", "requirements.txt"]
src_extensions = ["requirements.txt"]
output_dirs = [".venv"]

Scans for requirements.txt files. For each one, runs pip install and caches the entire .venv/ directory. After rsconstruct clean, the venv is restored from cache instead of reinstalling.

Build a Node.js project:

[processor.creator.npm_build]
command = "npm"
args = ["run", "build"]
src_extensions = ["package.json"]
output_dirs = ["dist"]

Scans for package.json files, runs npm run build, caches the dist/ directory.

Build documentation with Sphinx:

[processor.sphinx]

Scans for conf.py files, runs sphinx-build, caches the output directory.

docs/conf.py → (creator)

Build a Rust project with Cargo:

[processor.cargo]

Scans for Cargo.toml files, runs cargo build, optionally caches the target/ directory.

Cargo.toml → (creator)

Run a custom build script:

[processor.creator.assets]
command = "./build_assets.sh"
src_extensions = [".manifest"]
src_dirs = ["."]
output_dirs = ["assets/compiled", "assets/sprites"]
output_files = ["assets/manifest.json"]

Scans for .manifest files, runs the build script, caches two output directories and one output file.

Built-in creators

cargo, pip, npm, gem, sphinx, mdbook, jekyll, cc (full C/C++ projects)

User-defined creators use the creator processor type directly via [processor.creator.NAME].

Explicit

An explicit processor aggregates many inputs into (possibly) many output files and/or directories. Unlike other types which create one product per discovered file, explicit creates a single product with all declared inputs and outputs.

How it works

  1. Inputs are listed explicitly via inputs and input_globs in the config
  2. Creates a single product with all inputs and all outputs
  3. Runs the command, passing --inputs and --outputs on the command line
  4. Stores each output file as a content-addressed blob

What gets cached

One blob per output file (like generator).

Examples

Build a static site from generated HTML:

[processor.explicit.site]
command = "python3"
args = ["build_site.py"]
input_globs = ["out/pandoc/*.html", "templates/*.html"]
inputs = ["site.yaml"]
outputs = ["out/site/index.html", "out/site/style.css"]

Waits for pandoc to produce HTML files, then combines them with templates into a site. All inputs are aggregated into one product:

out/pandoc/page1.html, out/pandoc/page2.html, templates/base.html, site.yaml → out/site/index.html, out/site/style.css

Merge PDFs into a course bundle:

[processor.explicit.course]
command = "pdfunite"
input_globs = ["out/pdflatex/*.pdf"]
outputs = ["out/course/full-course.pdf"]

Aggregates all PDF outputs from pdflatex into a single merged PDF.

Built-in explicit processors

explicit, pdfunite, ipdfunite

Comparison

CheckerGeneratorCreatorExplicit
PurposeValidateTransformBuild/installAggregate
InputsScannedScannedScanned (anchor files)Declared in config
ProductsOne per inputOne per input (x format)One per anchorOne total
OutputsNoneDerived from input pathDeclared dirs + filesDeclared files
Cache typeMarkerBlobTreeBlob
Runs inProject rootProject rootAnchor file’s directoryProject root
Command argsInput filesInput + outputUser-defined args--inputs + --outputs