Agent Skill
This site publishes an agent skill: a package of instructions that teaches a coding agent how lttr actually works. Point your agent's installer at this domain and it picks up the shape of a Comark template, the Go wiring around it, and the handful of behaviours that are easy to get wrong.
Install it
pnpx skills add https://lttr.sulv.org
npx skills add https://lttr.sulv.org does the same thing if you are not using pnpm.
The installer reads the discovery index at /.well-known/skills/index.json, which lists every skill this site publishes along with its files. There is one, named lttr.
Know what it contains
The skill leads with a short SKILL.md your agent always reads, and six reference files it loads only when the task calls for one. That split keeps the common case cheap: an agent adding a module to a template pulls in the module catalogue, not the SMTP details.
| File | Covers |
|---|---|
SKILL.md | Mental model, a complete runnable program, the traps, and a map to everything below |
references/authoring.md | Frontmatter, Comark syntax, merge tags, bindings, URLs, actions, spans, compile errors |
references/modules.md | Every module with its attributes, bindings, allowed content, limits and errors |
references/rendering-and-families.md | Families, footer copy, placeholders, streams, Theme, Config, render-time rules, output |
references/sending.md | Message, MIME, Router, SMTP, custom senders, Mapbox maps |
references/tooling-and-testing.md | The lttr CLI, make targets, testing your own templates |
references/api-reference.md | The exported surface, signature-dense |
Understand what it corrects
A model that has never seen lttr will fall back on habits from Handlebars, MJML or Go's html/template, and several of those habits produce templates that compile and then misbehave, or fail in ways that are hard to read. The skill front-loads exactly those cases:
- Merge tags are lower-case JSON names.
{{Name}}is not a tag: it renders literally with only a warning, and a field without ajsontag matches its lower-cased Go name, so{{first_name}}can silently fall through to the recipient's. See Merge tags and bindings. - A fallback inside a table cell needs
\|. The table parser splits cells on a bare|, so{{name | there}}breaks the row. See Comark syntax. - Merge values in URLs are escaped after the first part.
https://acme.example{{path}}fails; pass whole URLs from Go. See Merge tags and bindings. - Bindings need the exact type,
{name}placeholders exist only in family copy, and there is one:buttonper template. See Modules and Actions and spans. - Family rules are compile-time.
from,issue,legalandfooter.*depend on the family, and the registry given toCompilemust be the one inConfig.Families. See Families and streams. - Empty bound lists fail the render. There are no conditionals to hide a module. See Modules.
Every error message the skill quotes is copied from the source, and the program in SKILL.md is compiled and run as part of keeping it honest.
Keep it up to date
Re-run the install command to pull the current version. The skill is versioned with the docs site, so it describes the library as of whatever is deployed here.
Publish it from your own build
The skill lives in docs-site/skills/lttr/ and is served by the Docus skills module, which scans a skills/ directory at the Nuxt root and needs no configuration. A local pnpm dev serves the same endpoints, so you can point an installer at http://localhost:3000 to test a change before it ships.
curl -s http://localhost:3000/.well-known/skills/index.json
curl -s http://localhost:3000/.well-known/skills/lttr/SKILL.md