Skip to content
OpenSmartRoute
Skillv1.0.0

template-engine

Auto-fill document templates with data. Use when a user asks to create a mail merge, fill templates with data, generate documents from a template, populate placeholders, bulk generate letters or invoi

by terminalskills(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from terminalskills/skills (skills/template-engine/SKILL.md). Install upstream with npx skills add terminalskills/skills --skill template-engine. Copyright stays with the author (Apache-2.0).

Template Engine

Overview

Auto-fill document templates with data from spreadsheets, databases, or JSON. Supports mail merge for any format: DOCX, PDF, HTML, Markdown, and plain text. Generate hundreds of personalized documents from a single template and data source.

Instructions

When a user needs template-based document generation, determine the format and approach:

Task A: DOCX template filling with python-docx-template

  1. Install the library:
pip install docxtpl openpyxl
  1. Create a DOCX template with Jinja2 placeholders:

    • Use {{ variable }} for simple values
    • Use {% for item in items %}...{% endfor %} for loops
    • Use {% if condition %}...{% endif %} for conditionals
  2. Fill the template:

from docxtpl import DocxTemplate
import json

def fill_docx_template(template_path: str, data: dict, output_path: str):
    doc = DocxTemplate(template_path)
    doc.render(data)
    doc.save(output_path)

# Single document
data = {
    "client_name": "Acme Corp",
    "date": "2025-01-15",
    "items": [
        {"description": "Consulting", "amount": 5000},
        {"description": "Development", "amount": 12000},
    ],
    "total": 17000
}
fill_docx_template("invoice_template.docx", data, "invoice_acme.docx")
  1. Bulk generation from CSV:
import csv
from docxtpl import DocxTemplate

def mail_merge_docx(template_path: str, csv_path: str, output_dir: str):
    with open(csv_path) as f:
        rows = list(csv.DictReader(f))

    for i, row in enumerate(rows):
        doc = DocxTemplate(template_path)
        doc.render(row)
        filename = f"{output_dir}/{row.get('name', i)}.docx"
        doc.save(filename)
        print(f"Generated: {filename}")

    print(f"Created {len(rows)} documents")

mail_merge_docx("letter_template.docx", "contacts.csv", "./output")

Task B: HTML/Markdown templates with Jinja2

from jinja2 import Environment, FileSystemLoader
import csv

env = Environment(loader=FileSystemLoader("./templates"))
template = env.get_template("report.html")

with open("data.csv") as f:
    rows = list(csv.DictReader(f))

for row in rows:
    html = template.render(**row)
    output_file = f"./output/{row['id']}_report.html"
    with open(output_file, "w") as out:
        out.write(html)

Example Jinja2 template (templates/report.html):

<!DOCTYPE html>
<html>
<head><title>Report for {{ company_name }}</title></head>
<body>
  <h1>Monthly Report: {{ company_name }}</h1>
  <p>Period: {{ start_date }} to {{ end_date }}</p>
  <table>
    <tr><th>Metric</th><th>Value</th></tr>
    {% for metric in metrics %}
    <tr><td>{{ metric.name }}</td><td>{{ metric.value }}</td></tr>
    {% endfor %}
  </table>
</body>
</html>

Task C: PDF generation from templates

from jinja2 import Environment, FileSystemLoader
import pdfkit  # requires wkhtmltopdf installed

def generate_pdf_from_template(template_name: str, data: dict, output: str):
    env = Environment(loader=FileSystemLoader("./templates"))
    template = env.get_template(template_name)
    html = template.render(**data)
    pdfkit.from_string(html, output, options={"page-size": "A4", "encoding": "UTF-8"})

# Alternative: use weasyprint (pure Python, no external deps)
# pip install weasyprint
from weasyprint import HTML

def generate_pdf_weasyprint(template_name: str, data: dict, output: str):
    env = Environment(loader=FileSystemLoader("./templates"))
    template = env.get_template(template_name)
    html_content = template.render(**data)
    HTML(string=html_content).write_pdf(output)

Task D: Plain text templates (emails, notifications)

from string import Template
import csv

def text_mail_merge(template_str: str, csv_path: str) -> list[str]:
    template = Template(template_str)
    results = []
    with open(csv_path) as f:
        for row in csv.DictReader(f):
            results.append(template.safe_substitute(row))
    return results

# Usage
email_template = """Dear $name,

Thank you for your order #$order_id placed on $date.
Your total is $$amount.

Best regards,
The Team"""

messages = text_mail_merge(email_template, "orders.csv")
for msg in messages:
    print(msg)
    print("---")

Examples

Example 1: Generate personalized offer letters

User request: "Create 50 offer letters from a template and employee spreadsheet"

from docxtpl import DocxTemplate
import csv

with open("new_hires.csv") as f:
    hires = list(csv.DictReader(f))

for hire in hires:
    doc = DocxTemplate("offer_letter_template.docx")
    doc.render({
        "candidate_name": hire["name"],
        "position": hire["role"],
        "salary": f"${int(hire['salary']):,}",
        "start_date": hire["start_date"],
        "manager": hire["manager"]
    })
    doc.save(f"./offers/offer_{hire['name'].replace(' ', '_')}.docx")

print(f"Generated {len(hires)} offer letters in ./offers/")

Example 2: Invoice generation from JSON data

User request: "Generate PDF invoices for all clients in our billing data"

from jinja2 import Environment, FileSystemLoader
from weasyprint import HTML
import json

with open("billing.json") as f:
    clients = json.load(f)

env = Environment(loader=FileSystemLoader("./templates"))
template = env.get_template("invoice.html")

for client in clients:
    client["total"] = sum(item["amount"] for item in client["line_items"])
    html = template.render(**client)
    HTML(string=html).write_pdf(f"./invoices/invoice_{client['id']}.pdf")

print(f"Generated {len(clients)} invoices")

Example 3: Bulk email content from a spreadsheet

User request: "Create personalized email bodies for 200 contacts from a CSV"

from jinja2 import Environment, BaseLoader
import csv

template_str = """Hi {{ first_name }},

I noticed {{ company }} recently {{ trigger_event }}. We help companies
like yours with {{ pain_point }}.

Would you have 15 minutes this week to discuss?

Best,
{{ sender_name }}"""

env = Environment(loader=BaseLoader())
template = env.from_string(template_str)

with open("contacts.csv") as f:
    contacts = list(csv.DictReader(f))

for contact in contacts:
    email_body = template.render(**contact)
    with open(f"./emails/{contact['email']}.txt", "w") as out:
        out.write(email_body)

print(f"Generated {len(contacts)} email drafts")

Guidelines

  • Always validate data before rendering templates. Check for missing required fields.
  • Use safe_substitute or Jinja2's default filter to handle missing values gracefully: {{ name | default("Valued Customer") }}.
  • Preview the first 2-3 generated documents before running a full batch.
  • Keep templates in version control separate from data files.
  • For DOCX templates, test with complex formatting (tables, images, headers) early since not all features are supported.
  • Sanitize user-provided data to prevent template injection in HTML output.
  • Use consistent naming for output files that includes a unique identifier.
  • For large batches (1000+ documents), process in chunks and report progress.

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/terminalskills-skills-template-engine/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

terminalskills-skills-template-engine.ocm.jsonjson
{
  "ocm": "1",
  "id": "terminalskills-skills-template-engine",
  "kind": "skill",
  "name": "template-engine",
  "description": "Auto-fill document templates with data. Use when a user asks to create a mail merge, fill templates with data, generate documents from a template, populate placeholders, bulk generate letters or invoices, or auto-fill forms from a spreadsheet. Supports any document format including DOCX, PDF, HTML, and plain text.",
  "publisher": "terminalskills",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "general"
    ],
    "tags": [
      "skill-md",
      "template",
      "mail-merge",
      "documents",
      "automation",
      "generation",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Auto-fill document templates with data. Use when a user asks to create a mail merge, fill templates with data, generate documents from a template, populate placeholders, bulk generate letters or invoices, or auto-fill forms from a spreadsheet. Supports any document format including DOCX, PDF, HTML, and plain text."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/terminalskills/skills",
      "path": "skills/template-engine/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/terminalskills/skills/blob/HEAD/skills/template-engine/SKILL.md",
      "key": "terminalskills/skills/skills/template-engine/SKILL.md"
    },
    "compatibility": "Requires Python 3.8+ with docxtpl and Jinja2 for template filling",
    "license": "Apache-2.0"
  },
  "instructions": "# Template Engine\n\n## Overview\n\nAuto-fill document templates with data from spreadsheets, databases, or JSON. Supports mail merge for any format: DOCX, PDF, HTML, Markdown, and plain text. Generate hundreds of personalized documents from a single template and data source.\n\n## Instructions\n\nWhen a user needs template-based document generation, determine the format and approach:\n\n### Task A: DOCX template filling with python-docx-template\n\n1. Install the library:\n\n```bash\npip install docxtpl openpyxl\n```\n\n2. Create a DOCX template with Jinja2 placeholders:\n   - Use `{{ variable }}` for simple va",
  "cost": {
    "context_tokens": 1782
  }
}

Fetch it by URL: GET /api/v1/registry/terminalskills-skills-template-engine/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.