mdsmith
Esc
    v0.52.0 GitHub
    MDS021 directive ready directive

    MDS021: include

    Include section content must match the referenced file.

    # Marker Syntax

    <?include
    file: path/to/file.md
    strip-frontmatter: "true"
    wrap: markdown
    heading-level: "absolute"
    ?>
    ...included content...
    <?/include?>

    Do not use YAML folded scalars (>, >-) in the YAML body. Markdown parsers interpret > at the start of a line as a blockquote marker, which breaks the processing instruction content. Use literal block scalars (|, |-, |+) or quoted strings instead. See the generated-section concept for details.

    # Parameters

    ParameterRequiredDefaultDescription
    fileyesRelative path to include
    extractnoDotted path through the extract projection of a kind-typed file:. Splices one leaf value
    strip-frontmatterno"true"Remove YAML frontmatter (incompatible with extract:)
    wrapnoWrap in code fence (value = language)
    heading-levelno"absolute" or 1-6: nest under parent, or pin shallowest heading to that level
    heading-offsetnoSigned integer -6 to 6: shift every heading by N (incompatible with heading-level, extract:)

    Relative link and image targets in included content are automatically rewritten so they resolve from the including file’s directory. Absolute URLs, anchor-only links (#foo), and protocol links (http://, https://, mailto:) are not modified.

    For example, DEVELOPMENT.md contains [rules](internal/rules/). When included from docs/guide.md, the link becomes [rules](../internal/rules/).

    # Heading-Level Adjustment

    heading-level takes "absolute" or an integer 1-6.

    "absolute" is parent-relative: included headings shift so the shallowest one becomes a child of the enclosing section. The marker sits under ## Project (level 2). The included file has ## Build (2) and ### Sub (3). The shift is 2 - 2 + 1 = 1: ### Build (3) and #### Sub (4). At the document root no shift is applied.

    An integer pins the shallowest included heading to that level, whatever the source starts at, so it also works at the document root. heading-level: "2" renders a source # Title / ## Sub as ## Title / ### Sub. A deeper source is promoted; levels are capped at 1-6.

    heading-level cannot combine with heading-offset or extract:.

    # Heading-Offset Adjustment

    When heading-offset: "N" is set, every heading in the included content shifts by N levels. N is a signed integer from -6 to 6. A positive value demotes a heading (adds a #); a negative value promotes it. Levels are capped at the 1-6 range.

    Unlike heading-level: "absolute", the shift is fixed. It does not read a preceding heading, so it also applies at the document root. heading-offset cannot combine with heading-level or extract:.

    # Cycle Detection

    Include chains are tracked during check and fix. A diagnostic is emitted when:

    • A file includes itself (direct cycle).
    • A file includes B which includes A (indirect cycle, detected by scanning nested includes).
    • The include chain exceeds 10 levels deep.

    The cycle message shows the full chain:

    cyclic include: a.md -> b.md -> a.md

    # Config

    rules:
      include: true

    Disable:

    rules:
      include: false

    # Examples

    # Basic Include

    <?include
    file: data.md
    ?>
    Hello world
    <?/include?>

    # With Code Fence Wrapping

    <?include
    file: config.yml
    wrap: yaml
    ?>
    ```yaml
    key: value
    ```
    <?/include?>

    # With Frontmatter Kept

    <?include
    file: data.md
    strip-frontmatter: "false"
    ?>
    ---
    title: My Doc
    ---
    Content here.
    <?/include?>

    # With Heading-Level Shift

    Given DEVELOPMENT.md contains ## Build and ### Sub, including under ## Project shifts headings one level down:

    ## Project
    
    <?include
    file: DEVELOPMENT.md
    heading-level: "absolute"
    ?>
    ### Build
    
    Steps here.
    
    #### Sub
    
    Details.
    <?/include?>

    # With Heading Offset

    Demote every heading in the included file by one level, even when no heading precedes the marker:

    <?include
    file: features.md
    heading-offset: "1"
    ?>
    ## Was An H1 In The Source
    <?/include?>

    Given DEVELOPMENT.md in the repo root contains [rules](internal/rules/), including it from docs/guide.md rewrites the link:

    <?include
    file: DEVELOPMENT.md
    ?>
    See [rules](../internal/rules/) for details.
    <?/include?>

    # Extract a Typed Value

    extract: walks the JSON projection mdsmith extract would produce for a kind-typed file: target. The value is a dotted path. The directive splices the leaf:

    <?include
    file: docs/brand/messaging.md
    extract: tagline.text
    ?>
    Markdown, fast.
    <?/include?>

    A wrapper object with one content key (text, code, items, or rows) resolves to the inner value. So extract: tagline is the same as extract: tagline.text. Multi-key wrappers are ambiguous: the directive surfaces a lint error listing the keys. Frontmatter scalars sit under the frontmatter key: extract: frontmatter.title.

    extract: is incompatible with strip-frontmatter:, heading-level:, and heading-offset:. The projection returns one scalar, so those parameters do not apply.

    # Bad — Outdated Content

    <?include
    file: data.md
    ?>
    Outdated content
    <?/include?>

    # Diagnostics

    ConditionMessage
    content mismatchgenerated section is out of date
    missing fileinclude file “x.md” not found
    no file paraminclude directive missing required “file” parameter
    absolute pathinclude directive has absolute file path
    escapes rootinclude file path escapes project root
    no root for dotdotinclude file path contains “..” but project root is not configured
    invalid heading-levelinclude directive “heading-level” must be “absolute” or an integer between 1 and 6
    invalid heading-offsetinclude directive “heading-offset” must be an integer between -6 and 6
    offset + levelinclude directive “heading-offset” cannot be combined with “heading-level”
    empty extractinclude directive “extract” value is empty
    extract + sfminclude directive “extract” cannot be combined with “strip-frontmatter”
    extract + hlinclude directive “extract” cannot be combined with “heading-level”
    extract + offsetinclude directive “extract” cannot be combined with “heading-offset”
    extract missextract: missing key “x” in extract projection
    extract no kindextract: “x.md” has no resolved kind; cannot project a typed value
    extract not conformantextract: target file does not conform to its schema: …
    cyclic includecyclic include: a.md -> b.md -> a.md
    depth exceededinclude depth exceeds maximum (10)

    # Pattern

    The bad pattern is a section duplicated across two files. The good pattern is one canonical source plus <?include?> references. 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

    README.md:

    # Project
    
    ## Build
    
    Run `make build` to compile the project. The
    binary lands in `dist/`.

    INSTALL.md:

    # Install
    
    ## Build
    
    Run `make build` to compile the project. The
    binary lands in `dist/`.

    # With the directive

    snippets/build.md:

    Run `make build` to compile the project. The
    binary lands in `dist/`.

    README.md:

    # Project
    
    ## Build
    
    <?include
    file: snippets/build.md
    ?>
    Run `make build` to compile the project. The
    binary lands in `dist/`.
    <?/include?>

    INSTALL.md follows the same shape.

    # Meta-Information