# moonprompt syntax

## Lexical form

```ebnf
template  = { text | output | statement | comment } ;
output    = "{{", pipeline, "}}" ;
comment   = "{#", { character }, "#}" ;
statement = "{%", (for | if | elif | else | end), "%}" ;
pipeline  = expression, { "|", identifier, ["(", arguments, ")"] } ;
expression = literal | path | expression, compare-op, expression ;
path      = identifier, { ".", identifier | "[", integer, "]" } ;
```

Whitespace outside tags is preserved. Errors report one-based line and column.

## Blocks

`for item in items` binds `item`, `loop.index` (one-based), and `loop.last`.
Conditions use value truthiness or `== != < > <= >=`. Blocks may nest.

## Filters

`upper`, `lower`, `trim`, `capitalize`, `default(value)`, `join(separator)`,
`length`, `replace(old,new)`, `truncate(n)`, and `e`/`escape` are built in.
Escaping covers `& < > " '` and is opt-in so prompts are not unexpectedly changed.

## Frontmatter values

Frontmatter keys use letters, digits, `_` and `-`. Duplicate keys are rejected.
Values support strings, integers, booleans, null, and JSON-compatible inline arrays
or objects. Inline comments begin with whitespace followed by `#`; quoted hashes
remain data. Nested indentation-based YAML collections are intentionally outside
the documented subset.

## Role convention

`split_roles` recognizes line-oriented `[system]`, `[user]`, and `[assistant]`
headers after rendering. This simple convention avoids coupling moonprompt to one SDK.
