p.enthalabs

GitHub - domenukk/md-tmpl: Fast and powerful templates. Valid markdown. Strongly typed and great for agents. Supports Rust, Python, Go, TypeScript

Fast and powerful templates. Valid markdown. Strongly typed and great for agents.

The Template

[](https://github.com/domenukk/md-tmpl#the-template)

--- consts:

- MODEL = str := "gemini-3.5-flash"

- MAX_FINDINGS = int := 20

types:

- Severity = enum(Critical, High, Medium, Low)

- Verdict = enum(Approved, NeedsChanges(reason = str), Rejected(reason = str))

params:

- reviewer = str

- file_path = str

- severity = Severity

- findings = list(line = int, message = str, severity = Severity)

- verdict = Verdict

---

Code Review: {{ file_path }}

Reviewer: {{ reviewer }} · Model: {{ MODEL }} Severity: {{ kind(severity) }} · Findings: {{ len(findings) }}/{{ MAX_FINDINGS }}

> {% for finding in findings %}

- **L{{ finding.line }}** ({{ kind(finding.severity) }}): {{ finding.message }}

> {% /for %}

> {% match verdict %} > {% case Approved %}

✅ **Approved** — ship it.

> {% case NeedsChanges %}

🔄 **Needs changes:** {{ verdict.reason }}

> {% case Rejected %}

❌ **Rejected:** {{ verdict.reason }}

> {% /match %}

Types and fields are validated at build time — rendering happens at runtime:

use md_tmpl_macros::include_template;

include_template!("prompts/code_review.tmpl.md");

let output = code_review::Params::builder() .reviewer("Alice") .file_path("src/main.rs") .severity(code_review::Severity::High) .findings([ code_review::FindingsItem::builder() .line(42) .message("unused import") .severity(code_review::Severity::Low) .build(), ]) .verdict(code_review::Verdict::NeedsChanges { reason: "remove dead imports".into(), }) .build().render().unwrap();

Wrong types, missing fields, non-exhaustive matches — all caught at **build time**. Templates can also be loaded and validated at runtime for dynamic or hot-reload use cases.

Why?

[](https://github.com/domenukk/md-tmpl#why) | Problem | Solution | | --- | --- | | Prompts buried in code | **Markdown-native** — `.tmpl.md` files render in any editor or on GitHub | | Errors found in production | **Strict typing** — caught at build time (Rust) or render time | | LLMs drift templates silently | **Agent-safe** — the engine catches drift immediately | | Syntax breaks in previews | **Markdown-safe** — renders cleanly in any viewer, even unrendered |

Features

[](https://github.com/domenukk/md-tmpl#features) | Feature | Description | | --- | --- | | **Typed parameters** | `str`, `int`, `float`, `bool`, `list(…)`, `struct(…)`, `enum(…)`, `option(…)`, `tmpl(…)` | | **Type aliases** | `types:` defines reusable named types | | **Cross-template imports** | `imports:` pulls types via dotted paths (`stem.TypeName`) | | **Typed lists** | `list(title = str, score = int)` — iterate with `{% for %}`, fields validated | | **Enum dispatch** | `match`/`case` with exhaustiveness checking and field narrowing | | **Includes as links** | `{% include name with … %}` — clickable, type-checked | | **Inline templates** | `{% tmpl name %}` — reusable fragments without separate files | | **Constants** | `consts:` for file-scoped immutable values | | **Built-in functions** | `idx(b)`, `len(x)`, `kind(x)`, `has(x)` + filters (`upper`, `lower`, `trim`, `join`, …) | | **Readable as markdown** | `> {% %}` blockquote prefix keeps control flow visually separated from prose | | **Markdown-safe syntax** | Valid YAML frontmatter, clean `()` type syntax — looks good even unrendered |

> **Note:** The `>` prefix is required only on `{% %}` tag lines — it is stripped before compilation. Content lines between tags are normal text and should not use `>`. A content line starting with `>` is kept verbatim as a literal markdown blockquote in the output.

Quick Start

[](https://github.com/domenukk/md-tmpl#quick-start)

use md_tmpl_macros::include_template;

// Parsed + validated at build time — generates typed structs from frontmatter include_template!("prompts/task_report.tmpl.md");

let output = task_report::Params::builder() .title("Sprint 42") .priority(task_report::Priority::Critical) .tasks([ task_report::TasksItem::builder() .name("Fix auth bypass") .urgency(task_report::Priority::Critical) .build(), task_report::TasksItem::builder() .name("Update dependencies") .urgency(task_report::Priority::Low) .build(), ]) .build().render().unwrap();

Performance

[](https://github.com/domenukk/md-tmpl#performance) Built for speed — zero-allocation rendering in Rust, native FFI in all bindings.

Rust (render-only, pre-parsed)

[](https://github.com/domenukk/md-tmpl#rust-render-only-pre-parsed) | Scenario | md-tmpl | Tera | `MiniJinja` | Handlebars | | --- | --- | --- | --- | --- | | **simple** | **122 ns** 🏆 | 221 ns | 552 ns | 717 ns | | **loop** | **555 ns** 🏆 | 651 ns | 1.89 µs | 3.31 µs | | **conditional** | **168 ns** 🏆 | 390 ns | 612 ns | 1.38 µs | | **hero** | **2.09 µs** 🏆 | 2.17 µs | 7.43 µs | 25.18 µs | | **mega** | **10.60 µs** 🏆 | 11.21 µs | 28.39 µs | 91.99 µs |

Cross-Language (render-only)

[](https://github.com/domenukk/md-tmpl#cross-language-render-only) | Language | simple | loop | conditional | large | | --- | --- | --- | --- | --- | | **Rust** | 196 ns 🏆 | 1.11 µs 🏆 | N/A | 22.1 µs 🏆 | | **Go** | 525 ns | 1,716 ns | N/A | 24,808 ns | | Go `text/tmpl` | 569 ns | 6,251 ns | N/A | 140,495 ns | | **TypeScript** | 610 ns | 4,135 ns | 2,011 ns | N/A | | **Python** | 0.84 µs | 1.74 µs | 0.87 µs | 6.62 µs |

See the language-specific READMEs or the benchmarks suite for full details and methodology.

Language Bindings

[](https://github.com/domenukk/md-tmpl#language-bindings)

Rust (README)

[](https://github.com/domenukk/md-tmpl#rust-readme) Build-time validation via proc macros, plus a full runtime API for dynamic loading. Pre-parsed templates with zero-overhead rendering. Includes `ctx!` macro, `TypedBuilder`, `serde`, hot-reload, caching, and benchmarks.

Python (README)

[](https://github.com/domenukk/md-tmpl#python-readme) Includes generated types, import hooks, pattern matching, enum construction, caching, and benchmarks.

Go (README)

[](https://github.com/domenukk/md-tmpl#go-readme) Includes `RenderStruct`, `TaggedVariant`, codegen, caching, and benchmarks.

TypeScript (README)

[](https://github.com/domenukk/md-tmpl#typescript-readme) Includes `TypedTemplate(P)`, `defineVariants`, codegen, WASM backend, and benchmarks.

WASM (README)

[](https://github.com/domenukk/md-tmpl#wasm-readme) WebAssembly bindings wrapping the full Rust engine via `wasm-bindgen`. Same `ITemplate` interface as the pure-TypeScript package.

Full Reference

[](https://github.com/domenukk/md-tmpl#full-reference) See **SPEC.md** for the complete syntax — all control-flow tags, filters, built-in functions, whitespace control, and error diagnostics.

Packages

[](https://github.com/domenukk/md-tmpl#packages)

- **Rust**: https://crates.io/crates/md-tmpl (and https://crates.io/crates/md-tmpl-macros)

- **Python**: https://pypi.org/project/md-tmpl/

- **Go**: https://github.com/domenukk/md-tmpl

- **TypeScript**: https://www.npmjs.com/package/md-tmpl

License

[](https://github.com/domenukk/md-tmpl#license) Apache-2.0 OR MIT