Skip to main content
TemplateDX combines Markdown and JSX for LLM prompt templates. Type safety comes from the AgentMark codegen layer, not the engine itself. This page covers the full syntax.

Basic structure

Every TemplateDX template is a .mdx file with optional frontmatter and a mix of Markdown and JSX:

Frontmatter

Frontmatter is optional metadata at the top of your file:

Variables

Access dynamic data using curly braces:
A missing nested property renders as an empty string (there’s no error to guard against, so ?. and . behave identically). Learn more about variables →

Expressions

Evaluate expressions inline: arithmetic, comparison, and logical operators, property access, and registered filter calls:
JavaScript method calls (props.name.toUpperCase()) and the ternary operator (a ? b : c) aren’t supported. Use a filter or an <If> tag instead. Learn more about expressions →

Control flow

Conditionals

Use <If>, <ElseIf>, and <Else> tags:
Use loose equality (== / !=); strict equality (=== / !==) isn’t in the evaluator’s operator table and throws at render time. See Expressions for the full operator list.
A scope supports one condition chain. After any <If>, <ElseIf>, or <Else> in a scope has rendered, every later conditional tag in that same scope renders nothing, even a new <If> with a true condition. Conditionals nested inside another tag’s children (for example a <ForEach> or <If> body) get a fresh scope, so this limit doesn’t affect them.

Loops

Use <ForEach> to iterate over arrays:
Learn more about control flow →

Filters

Transform data with built-in filters. TemplateDX ships 10 filters: abs, capitalize, dump, join, lower, replace, round, truncate, upper, urlencode.
Learn more about filters →

Components

Create reusable template components:
Learn more about components →

Raw output

Use <Raw> to emit the enclosed content as literal source text; expressions inside <Raw> aren’t evaluated. The plugin re-serializes its children through Markdown, so you get exactly what you wrote.
Output: \{props.variableName} (literal text, not the value of props.variableName). TemplateDX re-serializes the Raw content through remark-stringify, which backslash-escapes { and <, so braces and angle brackets appear escaped in the output.

XML tags

TemplateDX preserves lowercase XML tags as-is in the output, making them ideal for prompt engineering patterns like <examples>, <context>, and <instructions>. A fixed allow-list of HTML tags (per supported-tags.ts) also passes through unchanged. TemplateDX evaluates expressions inside these tags normally.
Output:
The final stringify step indents nested elements by two spaces, so passthrough output isn’t byte-identical to your source. Keep that in mind for whitespace-sensitive prompts. XML tags support attributes and nesting:
TemplateDX treats lowercase tags as XML passthrough, along with a fixed allow-list of HTML tags. The allow-list check is case-insensitive, so PascalCase forms of allow-listed HTML elements (<Table>, <Code>) also pass through. The only PascalCase tags TemplateDX registers as built-ins are If, ElseIf, Else, ForEach, and Raw. Tags like <User>, <System>, and <Assistant> are AgentMark message tags layered on top of TemplateDX, not engine built-ins. A PascalCase tag that’s not on the HTML allow-list must be a registered TagPlugin or an imported component, or bundling throws Unsupported tag '<TagName>'. TemplateDX still evaluates variables and expressions inside passthrough tags normally.

Comments

Use JSX-style comments:

Fragments

Use fragments to group elements without adding markup:

Markdown support

TemplateDX supports all standard Markdown:

Whitespace

TemplateDX preserves whitespace in your templates:

Escaping literal braces

To keep { or } out of expression evaluation, wrap the content in <Raw>:
Output:
The leading backslash is inherent to the final stringify step, which always escapes { at the start of text content. There is no way to emit an unescaped literal { through stringify.

Type safety

See Type safety for the canonical flow: agentmark generate-types emits AgentmarkTypes from your prompt schemas. That’s the codegen pipeline AgentMark actually uses at runtime. TemplateDX itself doesn’t evaluate JSDoc or TypeScript types; the bundler strips comments at bundle time (removeComments, bundler.ts:163-170).

Best practices

  1. Use descriptive variable names. Prefer props.customerName over props.n.
  2. Keep templates modular. Break large templates into components.
  3. Generate types. Run agentmark generate-types and pass the result to createAgentMark<AgentmarkTypes>() for compile-time prop validation.
  4. Use conditionals wisely. Make prompts adapt to context.
  5. Use filters. Transform data at the template level instead of reshaping it in your application code.

Complete example

Here’s a full example combining multiple features:

Next steps