MDS039: build
Validate <?build?> directive parameters and keep the section body
in sync with the recipe’s rendered body-template.
# What it detects
MDS039 validates each <?build?> directive in a Markdown file:
reciperesolves — the recipe name must be declared inbuild.recipesin.mdsmith.yml.outputsis present and safe —outputsis a required, non-empty list. Each entry must be a relative path with forward-slash separators, no..components afterpath.Clean, no Windows drive letter or UNC prefix, no reserved device name, and no glob characters. Entries under.mdsmith/are rejected.inputsis well-formed —inputsis an optional list of paths or doublestar globs. Each entry passes the same path-shape rules asoutputs, except glob characters are allowed.- Required params present — params listed as required by the recipe schema must all be supplied.
- No unknown params (warning) — params not in the recipe’s
requiredoroptionallists produce a warning. The old singularoutput:is no longer known and draws this warning. - Body in sync — the section body must equal the rendered
body-template; MDS039 reportsgenerated section is out of datewhen it diverges.
mdsmith fix rewrites the body using the rendered body-template.
No external tool is executed.
# Directive syntax
<?build
recipe: RECIPE-NAME
inputs:
- path/to/source.md
outputs:
- path/to/artifact.ext
[recipe-specific params]
?>
RENDERED BODY
<?/build?># Common parameters
| Name | Required | Description |
|---|---|---|
recipe | yes | Recipe name declared in build.recipes |
outputs | yes | Non-empty list of relative artifact paths; no globs |
inputs | no | List of relative source paths or doublestar globs |
outputs entries accept any file extension; MDS039 applies no
extension filter.
# Generated body
Each recipe has a body-template. mdsmith fix renders it once per
outputs entry, in declared order, and joins the lines with newlines.
Two placeholders are available per render iteration:
| Placeholder | Value |
|---|---|
{output} | The current outputs entry |
{alt} | "{recipe} output: {output}" for that entry |
When body-template is omitted from the recipe declaration, the
default [{output}]({output}) is used.
# Config
build:
recipes:
render:
body-template: ""
params:
required: [source]
optional: [title]To disable MDS039:
rules:
build: false# Examples
# Good
<?build
recipe: render
source: diagram.svg
outputs:
- docs/diagram.png
?>

<?/build?># Bad — stale body
<?build
recipe: render
source: diagram.svg
outputs:
- docs/diagram.png
?>
outdated content
<?/build?>MDS039 reports: generated section is out of date
# Bad — unknown recipe
<?build
recipe: nonexistent
outputs:
- out.png
?>
content
<?/build?>MDS039 reports: build directive references unknown recipe "nonexistent"
# Bad — missing required param
<?build
recipe: render
outputs:
- out.png
?>
content
<?/build?>MDS039 reports:
build directive recipe "render": missing required parameter "source"
# Pattern
The bad pattern is a hand-maintained snippet
describing where a generated artifact lives. The
good pattern is the same content produced by a
<?build?> directive. The canonical source
files live in pattern/bad/
and
pattern/good/
; the snippets
below mirror those files for quick reference.
The markdown-audit skill reads the folders
directly.
# Without the directive
# Demo
The recorded demo lives at `demo.gif`. Re-record
the GIF with:
```sh
vhs demo.tape
```
Embedded inline:
# With the directive
# Demo
<?build
recipe: vhs
source: demo.tape
outputs:
- demo.gif
?>

<?/build?># Meta-Information
- ID: MDS039
- Name:
build - Status: ready
- Default: enabled
- Fixable: yes (body only)
- Implementation: source
- Category: directive