# RenderUserTemplate

Renders a template from `templates/` by substituting `{{var}}` placeholders with caller-supplied params.

## Overview

Companion to `ReadUserTemplate`. Instead of returning the raw body, this tool:

1. Parses the template's frontmatter `params` spec (same shape as scripts / browser-macros).
2. Validates caller-supplied `params` against the spec (type-check + defaults applied).
3. Replaces every `{{name}}` placeholder in the body with the resolved value.
4. Returns the rendered body (no `# Template:` header, no frontmatter — just the substituted text).

Placeholders **not declared** in `frontmatter.params` are left literal — so prose like
`use {{column}} as the key` survives unchanged when no `column` param exists.

---

## Usage

Template file `templates/weekly-report.md`:

```markdown
---
description: Weekly status report
params:
  - name: date
    type: string
  - name: summary
    type: string
    default: "(no summary)"
---
# Status — {{date}}

{{summary}}
```

Call:

```json
{ "name": "weekly-report", "params": { "date": "2026-05-11", "summary": "shipped 3 PRs" } }
```

Response:

```
# Status — 2026-05-11

shipped 3 PRs
```

---

## Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | string | Yes | Template filename, with or without `.md` extension (max 128 chars) |
| `params` | object | No | Key-value params matching the template's `frontmatter.params` spec |

---

## Frontmatter `params` schema

Identical to scripts / browser-macros:

```yaml
params:
  - name: identifier  # must match /^[a-zA-Z_$][a-zA-Z0-9_$]*$/
    type: string | number | boolean
    description: optional
    default: optional  # if omitted, the param is required
```

Param values are coerced to string via `String(value)` when substituted.

---

## Error cases

- `name` missing or invalid characters → error.
- Template file does not exist in `templates/` → error.
- Frontmatter is malformed (bad YAML, bad `params` shape) → error.
- A required param (no default) is missing from the call → error: `param X: required but not provided`.
- A param has the wrong type → error: `param X: expected number, got string`.

Templates without any frontmatter render as pure pass-through — any `{{var}}` stays literal.

---

## Use cases

- Weekly / monthly reports: `RenderUserTemplate({ name: "weekly-report", params: { date, summary } })`.
- Email canned responses with variable substitution.
- Code boilerplate with a few configurable parts (component name, props).

For more dynamic logic (conditionals, loops), open `ReadUserTemplate` and do the substitution
inline in your output — there is no Handlebars / Liquid / etc. engine, by design.

---

## Related tools

- `ReadUserTemplate` — returns the raw body + frontmatter. Use this when you want to inspect
  the template structure or do substitution yourself.
- `ListUserAssets({ kind: "templates" })` — list available templates.
- `RunUserScript` — for executable scripts (not just text substitution).
- This tool is a META_TOOL — no need to add it to `allowed_tools` in piece YAML.
