# Architecture

```mermaid
flowchart LR
  A[Template text] --> B[Tag lexer]
  B --> C[Recursive descent parser]
  C --> D[Immutable AST]
  D --> E[Scoped renderer]
  V[Value variables] --> E
  E --> F[Rendered prompt]
  F --> G[Role splitter]
  G --> H[LLM SDK messages]
```

The lexer retains exact text and source locations. The parser validates nesting and
produces `Text`, `Output`, `For`, and `If` nodes. Rendering uses lexical scopes:
each loop iteration adds bindings without mutating caller data. Filter arguments
are expressions evaluated in the same scope. No global state or backend-specific
primitive is used, so the core package is portable across wasm-gc, JavaScript and
native targets.

The frontmatter reader is deliberately a documented YAML subset (flat scalar
keys with JSON-compatible inline arrays/objects), keeping the parser deterministic.
The project includes a strict JSON-to-`Value` adapter used by the native CLI.

Static analysis walks the same immutable AST to report node counts, nesting,
external variables and invalid filter calls without rendering. Role validation,
diagnostic excerpts, render limits and conservative security findings are separate
layers, so hosts can opt into policy without changing core template semantics.
