Documentation / Moth template files

Moth template files

A .mtf file puts Markdown directly inside Moth's compile-time template system. It needs no frontmatter, embedded script block or separate template engine.

The compiler exports the folded result as content. Use plain .md for portable Markdown and normal .moth when the file needs declarations, dependencies or runtime work.

Choose the explanation level: Moth template files

Moth template files

A .mtf file is Markdown that lives inside Moth's template world.

Write prose directly

# Getting started

This is **bold** text.

[p: This paragraph is styled by the @html builder helper.]

No dependency clauses, no declarations, no frontmatter. Content only.

Bind the result

@docs/intro content as intro

[: [intro] ]

The content constant is the only thing a .mtf file exports.

A .mtf file is a Moth template file. The compiler prepares it as an implicit compile-time Markdown template body and exposes one generated content constant.

Implicit template structure

The compiler builds each .mtf file as if its whole body were the body of an implicit compile-time Markdown template:

content #String = [$md:
    ...entire .mtf file body...
]

The compiler constructs this structure directly from the token stream. It does not prepend wrapper source text to the file.

Exported declaration

A .mtf file exposes exactly one generated constant: content #String. The content is compile-time folded HTML text. No other declaration is exported.

File is content-oriented

A .mtf file is not a normal declaration file. It does not contain authored dependency clauses, declarations, frontmatter or metadata. It is a template body that produces a folded string.

Comments and punctuation

Because the file body is a template body, -- is content text, not a Moth comment. Backslashes follow template-body formatter behaviour. Backticks are Markdown inline-code delimiters, not raw string syntax.

Source file path and module ownership

A .mtf file belongs to the module that contains its directory. Same-module files can bind its generated content constant, and the module root can re-export that constant through its export: block.

Target and builder availability

Moth template files are available in HTML project builds. The .mtf body sees a restricted flat compile-time scope provided by the builder. See Template scope.

Related concepts

Choose the explanation level: Implicit Markdown

Implicit Markdown

Moth template files use a small Markdown subset, not full CommonMark.

What works

  • Headings with #
  • Paragraphs separated by blank lines
  • *italic* and **bold**
  • Links
  • Unordered and ordered lists
  • Inline code with single backticks

What does not work

  • Fenced code blocks (triple backticks). Use codeblock helpers instead.
  • Pipe tables. Use structured lists instead.
  • Raw HTML is escaped. Use $raw or $html directives for raw output.

Moth template files use Moth's $md Markdown flavour. This is intentionally smaller than full CommonMark.

Supported Markdown

  • Headings: #, ##, ### and deeper
  • Paragraphs: separated by blank lines
  • Emphasis: *italic* and **bold**
  • Moth-aware links: @path (label)
  • Unordered lists: - item
  • Ordered lists: 1. item
  • Inline code: paired isolated single backticks on the same line

HTML escaping

Moth template files escape HTML characters in Markdown text. Raw HTML tags such as <div> are escaped as &lt;div&gt; in the output. Use $raw or $html directives when raw HTML output is needed.

Not supported

  • Fenced code blocks (triple backtick blocks) are not rendered as <pre><code>. They appear as literal text. Use a codeblock helper with a $code(...) directive instead.
  • Markdown pipe tables are not rendered as <table>. They appear as literal text. Use a structured list or a page-owned table component instead.
  • Full CommonMark is not claimed. Moth's $md is a small, deliberate subset.

Backticks are inline-code delimiters

In $md, backticks delimit inline code, not raw strings. Empty spans, repeated backtick runs, unmatched backticks, multiline spans, variable-length delimiters and fenced code blocks are not part of the $md flavour.

Links use Moth-aware syntax

Use @/docs/packages (Packages) for internal routes or @https://example.com (Example) for external links. Ordinary [label](path) Markdown links belong to Plain Markdown and aren't parsed as links by a moth template's $md formatter.

A target beginning with a single / is a site route and renders through the site root, so the configured origin is applied for you. Relative, fragment, protocol-relative and absolute targets render literally. See Markdown formatting.

-- is content

Because the file body is a template body, -- is body text, not a Moth comment. It renders as literal -- in the output.

Backslashes follow body behaviour

Backslashes in the template body follow formatter behaviour. They are not escape characters in the same sense as normal Moth source.

Code examples

Use codeblock and $code(...) where the helper is available through the content environment. See Template scope for what is visible inside a .mtf file.

Related concepts

Choose the explanation level: Content dependencies

Content dependencies

Bind Moth template content with normal extensionless dependency clauses.

Bind and use

@docs/intro content as intro

[: [intro] ]

The content constant is a compile-time string. Insert it wherever you want.

Do not include the extension

@docs/intro.mtf content is rejected. Use @docs/intro content.

Moth template content is bound with normal extensionless source dependency clause syntax. The bound content constant is a compile-time string.

Dependency syntax

@docs/intro

[: [intro.content] ]

A bare namespace clause exposes content as a field. A direct selection binds it directly:

@docs/intro content as intro_content

[: [intro_content] ]

Aliasing content

Use as to give the bound content a local name. This is the standard form when multiple content files are depended on by the same page.

Compile-time string semantics

The bound content is a #String compile-time constant. It has already folded by the time the declaring file uses it. It is not a runtime value.

Use in a page or template

Insert the bound content into a template body:

@docs/intro content as intro

[: [intro] ]

The caller decides where to insert it. Bound content does not become a page fragment automatically.

Explicit extensions are rejected for source content

@docs/intro.mtf content

This is rejected with MOTH-IMPORT-0024. Use @docs/intro without the .mtf extension.

The same content as a file value

The explicit-extension spelling that a clause rejects is valid in expression position, where it evaluates to the same content string:

intro #= @docs/intro.mtf

Both forms name one compiled file and one content value. Use the clause when the bound name matters or the file is used repeatedly, and the direct file value when a template needs the content once. See File values.

Relative path resolution

Content dependency clauses follow the same path resolution rules as normal source dependency clauses. Both @intro and @docs/intro resolve from the declaring file's owning module root; the latter selects docs/intro below that root. @./... has no supported meaning.

Dependencies from root or helper files

A .mtf file can be depended on from a module root, a normal source file, or both. The dependency path resolves the same way regardless of the declaring file's role.

Bound content does not become a page fragment

Binding a .mtf file and inserting its content into a template does not create a page fragment. The caller controls where the content appears. Only direct top-level templates in the entry-selected module root become page fragments.

Visibility and module boundary

A .mtf file's content is subject to the same module visibility rules as other declarations. Cross-module dependency clauses can only access content if the module root's export: block re-exports it.

export:
    @intro content as intro
;

Related concepts

Choose the explanation level: Template scope

Template scope

A .mtf file sees exported compile-time constants from its same-directory module root and compile-time helpers supplied by @html.

A constant capture

-- docs/@docs.moth
export:
    site_name #= "Moth"
;
-- docs/intro.mtf
# Welcome to [site_name]

The compile-time constant is inserted into the Markdown at that position.

A nested $raw override

[$raw: <div>Raw HTML here</div>]

Nested templates default to $md, but an explicit directive overrides that.

A .mtf file sees a small compile-time scope. The implicit template body can access constants from its module root and builder-provided helpers.

Same-directory module root constants

Exported compile-time constants and const records from the same-directory module root are visible inside a .mtf file. This is the primary way to parameterise moth template content.

-- docs/@docs.moth
export:
    site_name #= "Moth"
;
-- docs/intro.mtf
# Welcome to [site_name]

Builder-provided compile-time helpers

Exported compile-time constants and const records from @html are visible flat inside a .mtf file. This includes helpers such as p, codeblock and other HTML builder constants.

-- docs/intro.mtf
[p: This paragraph uses the @html p helper.]

[codeblock, $code("moth"): value = 42]

Collision semantics

@html constants and same-directory module root constants don't shadow each other. If both surfaces expose the same visible name, compilation fails with a visible-name collision diagnostic. The collision identifies both sources where location data is available.

Authors resolve collisions by renaming the module-root export.

-- docs/@docs.moth
export:
    -- INVALID when this root is paired with a .mtf file because @html also exposes p.
    p #= [: Custom paragraph]
;
-- docs/@docs.moth
export:
    my_p #= [: Custom paragraph]
;

The collision occurs when the same-directory root and implicit @html surface are combined for a .mtf body.

This follows the same no-shadowing model as ordinary source visibility.

Nested templates

Nested templates inside a .mtf body are valid. A nested template with no explicit directive defaults to $md. Any explicit directive (such as $raw, $fresh, $html, $code, $css or $escape_html) overrides the moth template Markdown default for that nested template.

[$raw: <div>Raw HTML output</div>]

Constants versus runtime values

Only compile-time constants are visible inside a .mtf file. Runtime bindings, runtime functions, types, traits, methods, external runtime APIs and the generated self content constant are not visible.

A reference to a runtime value is rejected with MOTH-RULE-0034 or MOTH-RULE-0053.

No runtime capture

Moth template bodies are const-required. There is no runtime capture. The entire body must fold at compile time.

Allowed template directives

All template directives available in the compile-time template environment are valid inside .mtf. This includes $md, $raw, $fresh, $html, $code, $css and $escape_html.

Child-template formatting boundary

Child templates are opaque barriers to the parent formatter. A child template's output is not inspected by the parent $md formatter. Template delimiters cannot pair across child boundaries.

Literal delimiter output

To output literal template delimiters, use string insertion:

["["]
["]"]
["[literal]"]

Content helpers

Content helpers such as codeblock work only where the builder environment provides them. Do not assume arbitrary normal source dependencies are available inside .mtf.

Related concepts

Choose the explanation level: Moth template file limits

Moth template file limits

Moth template files are the wrong tool when the job stops being content-shaped.

Use .moth instead when

  • You need runtime values or control flow.
  • You need dependency clauses or declarations.
  • You need page fragments or slot composition.

Use .md instead when

  • You need plain Markdown with no Moth syntax.
  • You need fenced code blocks or pipe tables.
  • You need raw HTML preserved.

Moth template files are intentionally small. These are the confirmed restrictions and deferred surfaces.

Confirmed restrictions

  • Implicit const-required evaluation: the entire .mtf body must fold at compile time. There is no runtime path.
  • No normal top-level declarations: a .mtf file does not contain authored dependency clauses, functions, structs, choices, type aliases or trait declarations. Text that looks like a declaration is template body content, not a compiled declaration.
  • No runtime bindings or calls: runtime values are not visible. A reference to a runtime name is rejected with MOTH-RULE-0034 or MOTH-RULE-0053.
  • No fenced code blocks: triple-backtick blocks are literal text in $md, not <pre><code>. Use codeblock helpers instead.
  • No pipe tables: Markdown pipe table syntax is literal text in $md, not <table>. Use structured lists or page-owned table components.
  • No raw backtick strings: backticks are Markdown inline-code delimiters, not raw string syntax.
  • Template and Markdown child boundaries: child templates are opaque barriers to the parent formatter. Delimiters cannot pair across child boundaries.
  • Unsupported runtime control flow: template if and loop are available as template directives, but ordinary runtime control flow is not part of the const-required moth template body.

Differences from normal .moth

  • A .moth file can contain dependency clauses, declarations, runtime code and page fragments. A .mtf file cannot.
  • A .moth file has normal Moth source scope. A .mtf file has a restricted flat compile-time scope.
  • A .moth file can produce page fragments. A .mtf file produces one content #String constant.

Differences from plain .md

  • A .mtf file is parsed as Moth template syntax. A .md file is not.
  • A .mtf file can access compile-time constants and use nested templates. A .md file cannot.
  • A .mtf file uses the $md renderer. A .md file uses the plain Markdown renderer (CommonMark-compatible with GFM extensions).
  • A .mtf file escapes raw HTML. A .md file preserves raw HTML.

When to choose normal Templates instead

Use a .moth template when:

  • runtime values or control flow are needed
  • full slot and wrapper composition is needed
  • the content is part of broader program logic
  • dependency clauses or declarations are needed in the same file

Related concepts