Preamble System
The preamble script (preamble.luau) is required for every rule. It runs once per (rule, outputFile) pair — that is, once per unique output file a rule contributes to. The engine deduplicates its result by content per output file at assembly time. It is the right place for:
#includedirectives common to all of the rule’s outputs to this file- License or auto-generated banners specific to this rule (the engine already emits its own banner separately)
- Namespace opening brackets
- Any text that must appear at the top of the file regardless of which entities land there
Signature
Section titled “Signature”return function(input) -- input: JSON-encoded context object, decode if you need it return "text to prepend to the file"endThe input context is:
{ "language": "cpp", "outputFile": "path/to/output.cpp", "ruleName": "<RuleName>", "params": { /* rule.params from RuleName.config.yaml */ }, "entities": [ { "registryId": 42, "qualifiedName": "myns::MyStruct", "structName": "MyStruct", "namespaces": ["myns"], "inputFile": "include/myns/my_struct.hpp", "includes": ["<vector>"] } ]}outputFile is the post-grouping output path for this (rule, file) pair. The entities array contains every entity bound to this output file, with each entity’s handler-emitted includes exposed for conditional preamble logic. This lets you, for example, include <vector> in the preamble only if any entity in the output file needed a vector.
The return value is a raw string — not JSON. Whatever you return is buffered on the rule.
Example: C++ includes
Section titled “Example: C++ includes”return function(input) return "#include <string_view>\n#include <vector>\n\n"endExample: Markdown document header
Section titled “Example: Markdown document header”return function(input) return "# API Reference\n\n" .. "> This file is auto-generated. Do not edit manually.\n\n" .. "---\n\n"endDeduplication at assembly
Section titled “Deduplication at assembly”The engine collects all preamble results from the rules contributing entities to a single output file, deduplicates by content (string equality), and emits each unique result once. Two rules that produce identical preamble strings collapse to a single emission; two rules that produce different strings each contribute one block.
This is what makes fan-in clean: dozens of entities from one rule routed into api-reference.md produce exactly one # API Reference header.
It also means: preambles don’t have visibility into which entities will land in their output file. They run before grouping. If you find yourself wanting to conditionalise preamble content on entity data (“only include this header if the entity has template parameters”), that’s a signal to emit the include from the handler’s includes field instead — the engine will deduplicate those across the file too.
Preamble vs handler
Section titled “Preamble vs handler”| Belongs in the preamble | Belongs in the handler |
|---|---|
| Banner / file-level comment | Per-entity content |
Always-on #include directives, or conditional on the entities list | #include directives specific to a single entity (use includes in the return) |
| Opening namespace bracket | The actual code/declaration text (source, inline) |
Errors
Section titled “Errors”A preamble that calls error() (or hits a runtime error) aborts the whole run with E007 (exit 1). Unlike handler errors (which skip a single entity), there’s no recovery — if a preamble fails for one output file, the entire codegen run is unsafe.
- The preamble is required (
E003if missing); usereturn function() return "" endif there’s nothing to emit. - Runs once per (rule, outputFile) pair; results are deduplicated by content per output file at assembly time.
- The input context is
{language, outputFile, ruleName, params, entities}; entities lists all matches bound to this output file. - Use
entitiesto conditionally emit includes (e.g., include<vector>only if any entity has a vector member). - Use
includesfrom the handler for entity-conditional includes; the engine deduplicates those too. - Preamble errors abort the whole run.