Enforcing Document Structure with Schemas
How to use schemas, require, and allow-empty-section to validate headings, front matter, and filenames.
mdsmith can validate that documents follow a required
structure — specific headings, front matter fields,
and filename patterns. This is configured through
schema files and the required-structure rule
(MDS020
).
# When to use schemas
Use a schema when a set of files must follow the same structure. Common examples:
- Rule READMEs that must all have the same sections
- Plan files that must include Goal, Tasks, and Acceptance Criteria
- API docs that must have Parameters and Examples
# Creating a schema
A schema file is a Markdown file whose headings define the required structure. Front matter keys define CUE constraints on document front matter.
---
id: '=~"^MDS[0-9]{3}$"'
name: 'string & != ""'
status: '"ready" | "not-ready"'
---
# ?
## Goal
## Tasks
## Acceptance CriteriaThe # ? heading matches any top-level heading. Each
## ... heading is required in documents validated
against this schema.
# Applying a schema to files
Configure the schema in .mdsmith.yml using
overrides:
overrides:
- glob: ["internal/rules/*/README.md"]
rules:
required-structure:
schema: internal/rules/proto.mdmdsmith check reports missing or extra sections,
wrong heading levels, front matter that violates CUE
constraints, and heading/body text that does not match
front matter values.
# Requiring filename patterns
Use <?require?> in a schema file to constrain
document filenames:
<?require
filename: "[0-9]*_*.md"
?>Documents validated against this schema must have a
basename matching the glob. If they don’t, check
reports: filename "foo.md" does not match required pattern "[0-9]*_*.md".
Schema-only: <?require?> is only recognized in
schema files. Using it in a normal file emits:
<?require?> is only recognized in schema files; this directive has no effect.
For full reference, see MDS020 required-structure .
# Allowing intentional empty sections
Some sections are intentionally left empty (for
example, a Compatibility section that exists for
future use). Use <?allow-empty-section?> to suppress
the empty-section diagnostic:
## Compatibility
<?allow-empty-section?>
## Notes
This section has real content.Without this marker,
MDS030
reports: section "## Compatibility" has no meaningful body content.
Does not propagate: Adding
<?allow-empty-section?> to a schema file does not
suppress the diagnostic in documents using that
schema. Each file must add its own marker.
# Schema composition
Schema files can use <?include?> to share structure
across schemas. Included fragment headings are spliced
into the heading list at the include position.
Fragment front matter is ignored. <?require?>
constraints from fragments are merged.
# ?
## Goal
<?include
file: common/acceptance-criteria.md
?>Cycle detection prevents circular includes. Max include depth is 10.
# What schemas do not enforce
Schemas validate headings and front matter only. They do not enforce:
- Directive presence (a
<?catalog?>in a schema does not require documents to also contain one) - Body content beyond heading structure
- Formatting rules (handled by other rules)
| Behavior | Schema file | Normal file |
|---|---|---|
<?require?> recognized | yes | no (warning emitted) |
<?allow-empty-section?> effect | local to that file | local to that file |
<?include?> behavior | splices headings | embeds content |
# Optional front matter fields
Append ? to a schema front matter key to make it
optional. The field may be absent, but if present it
must satisfy the type constraint:
name: 'string & != ""'
"description?": string# Allowing extra sections
By default, extra sections are rejected. Add a
heading with text ... to allow extra headings in
that position:
## ...
## Required Section