mdsmith
Esc
    v0.52.0 GitHub

    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 Criteria

    The # ? 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.md

    mdsmith 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)
    BehaviorSchema fileNormal file
    <?require?> recognizedyesno (warning emitted)
    <?allow-empty-section?> effectlocal to that filelocal to that file
    <?include?> behaviorsplices headingsembeds 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