> ## Documentation Index
> Fetch the complete documentation index at: https://puzzlet-9ba7bb98.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Syntax overview

> Complete syntax reference for TemplateDX

TemplateDX combines Markdown and JSX for LLM prompt templates. Type safety comes from the [AgentMark codegen layer](/configure/type-safety), 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:

```jsx theme={null}
---
title: My Prompt Template
description: A brief description
---

# Your prompt content here

You are a helpful assistant specializing in {props.domain}.

<If condition={props.showInstructions}>
## Instructions
{props.instructions}
</If>
```

## Frontmatter

Frontmatter is optional metadata at the top of your file:

```yaml theme={null}
---
title: Customer Support Prompt
description: Template for customer support interactions
version: 1.0
---
```

## Variables

Access dynamic data using curly braces:

```jsx theme={null}
{props.userName}           // Simple variable
{props.user.email}         // Nested property
{props.items[0]}           // Array access
```

A missing nested property renders as an empty string (there's no error to guard against, so `?.` and `.` behave identically).

[Learn more about variables →](/templatedx/variables)

## Expressions

Evaluate expressions inline: arithmetic, comparison, and logical operators, property access, and **registered filter calls**:

```jsx theme={null}
{props.score * 2}
{props.score >= 90}
{props.items.length}
{upper(props.name)}
{join(props.tags, ", ")}
```

JavaScript method calls (`props.name.toUpperCase()`) and the ternary operator (`a ? b : c`) aren't supported. Use a [filter](/templatedx/filters) or an [`<If>`](#control-flow) tag instead.

[Learn more about expressions →](/templatedx/expressions)

## Control flow

### Conditionals

Use `<If>`, `<ElseIf>`, and `<Else>` tags:

```jsx theme={null}
<If condition={props.userType == "premium"}>
  You have access to premium features.
</If>
<ElseIf condition={props.userType == "standard"}>
  You have access to standard features.
</ElseIf>
<Else>
  You have access to basic features.
</Else>
```

Use loose equality (`==` / `!=`); strict equality (`===` / `!==`) isn't in the evaluator's operator table and throws at render time. See [Expressions](/templatedx/expressions) for the full operator list.

<Warning>
  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.
</Warning>

### Loops

Use `<ForEach>` to iterate over arrays:

```jsx theme={null}
<ForEach arr={props.items}>
  {(item, index) => (
    <>
      {index + 1}. {item.name} - {item.description}
    </>
  )}
</ForEach>
```

[Learn more about control flow →](/templatedx/tags)

## Filters

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

```jsx theme={null}
{upper(props.status)}              {/* ACTIVE */}
{lower(props.email)}               {/* user@example.com */}
{capitalize(props.name)}           {/* Note: only capitalizes first char; doesn't lowercase the rest */}
{truncate(props.content, 100)}     {/* First 100 chars + "..." */}
{join(props.tags, ", ")}           {/* tag1, tag2, tag3 */}
```

[Learn more about filters →](/templatedx/filters)

## Components

Create reusable template components:

```jsx theme={null}
import SystemRole from './system-role.mdx';
import Examples from './examples.mdx';

<SystemRole role="expert" domain={props.domain} />

## Task

{props.taskDescription}

<Examples data={props.examples} />
```

[Learn more about components →](/templatedx/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.

```jsx theme={null}
<Raw>
  {props.variableName}
</Raw>
```

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.

```jsx theme={null}
<examples>
<example>What is 2+2? The answer is 4.</example>
<example>What is 3+3? The answer is 6.</example>
</examples>

Now answer: What is {props.a}+{props.b}?
```

Output:

```text theme={null}
<examples>
  <example>What is 2+2? The answer is 4.</example>
  <example>What is 3+3? The answer is 6.</example>
</examples>

Now answer: What is 5+5?
```

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:

```jsx theme={null}
<context type="system">You are an expert assistant.</context>
<instructions>
<rule>Be concise</rule>
<rule>Cite sources</rule>
</instructions>
```

<Note>
  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.
</Note>

## Comments

Use JSX-style comments:

```jsx theme={null}
{/* This is a comment */}

{/**
  * Multi-line comment
  * for documentation
  */}
```

## Fragments

Use fragments to group elements without adding markup:

```jsx theme={null}
<>
  First line
  Second line
</>
```

## Markdown support

TemplateDX supports all standard Markdown:

```markdown theme={null}
# Heading 1
## Heading 2

**Bold text**
*Italic text*

- Bullet list
- Item 2

1. Numbered list
2. Item 2

[Link text](https://example.com)

`inline code`

\`\`\`javascript
// Code block
const x = 10;
\`\`\`
```

## Whitespace

TemplateDX preserves whitespace in your templates:

```jsx theme={null}
Line 1
Line 2

Paragraph with blank line above
```

## Escaping literal braces

To keep `{` or `}` out of expression evaluation, wrap the content in `<Raw>`:

```jsx theme={null}
<Raw>{literal-braces}</Raw>
```

Output:

```text theme={null}
\{literal-braces}
```

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](/configure/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:

```jsx theme={null}
---
title: Product Review Analysis
---

{/**
  * @typedef Props
  * @property {string} productName
  * @property {Array<{author: string, rating: number, comment: string}>} reviews
  * @property {string} analysisType
  */}

# Product Review Analysis for {props.productName}

You are an expert product analyst. Analyze the following customer reviews and provide insights.

## Reviews ({props.reviews.length} total)

<ForEach arr={props.reviews}>
  {(review, index) => (
    <>
      ### Review {index + 1}
      **Rating**: {review.rating}/5
      **Author**: {capitalize(review.author)}

      "{truncate(review.comment, 200)}"

      ---
    </>
  )}
</ForEach>

## Analysis Instructions

<If condition={props.analysisType == "sentiment"}>
  Focus on overall sentiment and emotional tone in the reviews.
</If>
<ElseIf condition={props.analysisType == "features"}>
  Identify the most mentioned product features and customer opinions about them.
</ElseIf>
<Else>
  Provide a comprehensive analysis covering sentiment, features, and improvement suggestions.
</Else>

Please provide your analysis in a structured format.
```

## Next steps

* [Variables](/templatedx/variables) - Learn about variable access
* [Expressions](/templatedx/expressions) - JavaScript expressions
* [Tags](/templatedx/tags) - Control flow and special operations
* [Filters](/templatedx/filters) - Data transformation
* [Components](/templatedx/components) - Reusable templates
