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
- Scans for files matching
src_extensionsinsrc_dirs - Creates one product per input file
- Runs the tool on each file (or batch of files)
- If the tool exits successfully, records a marker in the cache
- 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
- Scans for files matching
src_extensionsinsrc_dirs - For each input file, computes the output path from the input path, output directory, and format
- Creates one product per input x format pair
- Runs the tool to produce the output file
- 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
- Scans for anchor files matching
src_extensionsinsrc_dirs - Creates one product per anchor file
- Runs the command in the anchor file’s directory
- Walks all declared
output_dirsand collectsoutput_files - Stores each file as a content-addressed blob
- 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
- Inputs are listed explicitly via
inputsandinput_globsin the config - Creates a single product with all inputs and all outputs
- Runs the command, passing
--inputsand--outputson the command line - 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
| Checker | Generator | Creator | Explicit | |
|---|---|---|---|---|
| Purpose | Validate | Transform | Build/install | Aggregate |
| Inputs | Scanned | Scanned | Scanned (anchor files) | Declared in config |
| Products | One per input | One per input (x format) | One per anchor | One total |
| Outputs | None | Derived from input path | Declared dirs + files | Declared files |
| Cache type | Marker | Blob | Tree | Blob |
| Runs in | Project root | Project root | Anchor file’s directory | Project root |
| Command args | Input files | Input + output | User-defined args | --inputs + --outputs |