Plattform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Modelle Tools & Services
Lösungen
Organisationen Entwickler Internet Service Provider Managed Service Provider AI-in-a-Box
Ressourcen
Support Documentation Blog Downloads
Unternehmen
Über uns Forschung Karriere Investieren Kontakt
Anmelden

Templates

A template is a pre-formatted .docx containing {{ variable }} markers that get replaced at instantiation time with structured data. Use templates when you want a designer-controlled visual artefact (letterhead, contract, branded report) that produces one document per request without the AI/agent needing to know about the visual design at all.

This is different from themes: a theme controls styling that applies on top of any spec; a template is a specific document skeleton you fill in.

End-to-end flow#

tsql
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[Designer] creates letterhead.docx with {{ recipient }}, {{ date }}, etc.
            
            
[Operator] POST /v1/templates     register once
            
            
[App / Agent] POST /v1/documents/from_template
              { template_id, variables: {...} }     fill each time
            
            
[ScaiScribe] returns a new doc_id you can finalize, edit, preview

The template lives in object storage; the database keeps a row with the placeholder catalogue and metadata. Each instantiation produces a brand-new document (with its own doc_id) — templates are immutable; the instantiation is the variable thing.

Register a template#

python
1
2
3
4
5
6
7
8
with open("letterhead.docx", "rb") as f:
    template = scribe.upload_template(
        file=f.read(),
        name="letterhead",
        format="docx",
    )
print(template.template_id)       # tpl_01HXYZ...
print(template.placeholders)      # ['recipient', 'date', 'subject']

The server parses the binary, extracts every {{ name }} marker, and returns the list. If your template references {{ recipient.address.street }}, the placeholder list reports recipient.address.street — nested paths are first-class.

Instantiate#

python
1
2
3
4
5
6
7
8
9
doc = scribe.from_template(
    template_id="tpl_01HXYZ...",
    variables={
        "recipient": "Marketing department",
        "date": "2026-06-14",
        "subject": "Q4 review highlights",
    },
)
print(doc.doc_id)                  # doc_01HXYZ...

The response is a normal DocumentEnvelope — same shape create_document returns. From here you can finalize, preview, or patch the spec like any other doc.

Templating engine#

Under the hood, ScaiScribe uses docx-templates with cmdDelimiter: ["{{", "}}"]. Every command lives inside {{ ... }} — there is no {% ... %} block syntax. The grammar at a glance:

Marker Effect
{{ name }} Substitute the value.
{{ user.email }} Nested path access.
{{ INS expression }} or {{ = expression }} Insert (explicit / shorthand).
{{ IF active }}…{{ END-IF }} Conditional block.
{{ FOR row IN rows }}…{{ $row.cell }}…{{ END-FOR row }} Loop block. Note the $ prefix on the loop variable inside the body.
{{ ALIAS x INS something }} … {{ *x }} Reusable inline alias.
{{ LINK ({url, label}) }} Hyperlink.

The expression inside any command is JavaScript — filtering, arithmetic, formatting via toFixed, ternaries all work inline.

For the complete grammar (every command, every quirk, the placeholder extraction story, the limitations vs. upstream docx-templates) see the Templates reference.

Format coverage#

Format Substitution Expressions FOR / IF Slide / row replication Image insertion
DOCX ✓ (docx-templates) ✓ full JS ✓ table-row replication ✓ via IMAGE (inlined image objects)
PPTX ✓ safe subset ✓ text-frame level ✓ slide-level ✗ — roadmap
XLSX ✓ safe subset ✓ row level ✓ row replication with formula refs n/a

DOCX goes through the docx-templates library and gets the full grammar (loops, conditionals, aliases, JS expression evaluation in a VM sandbox).

PPTX and XLSX use a hand-rolled engine in workers/node/lib/ooxml-template-fill.js (Tier 2):

  • Expressions — safe subset of JS via a recursive-descent parser. No eval, no new, no arrow functions, no arbitrary globals. Supports path access, method chains (with a per-type allowlist: strings get toUpperCase/toLowerCase/slice/replace/…, numbers get toFixed/toLocaleString/…, arrays get length/join/slice/…), arithmetic, comparisons, logical ops, and ternaries.
  • {{ FOR x IN list }} … {{ END-FOR x }} — replicate paragraphs (PPTX) or rows (XLSX) per item. Inside the body, $x is the current item and $idx the 0-based index. PPTX has TWO FOR scopes: text-frame level (within one shape) and slide level (a whole slide cloned per item).
  • {{ IF expr }} … {{ END-IF }} — gate content on a truthy expression.
  • Missing variables render as empty strings (not errors) + emit TEMPLATE_VARIABLE_MISSING warning.
  • Run-span coalescing preserves a token across multiple <a:r> / <w:r> runs when PowerPoint or Excel splits it during authoring.

What's NOT supported in PPTX/XLSX expressions (DOCX still has these via docx-templates):

  • Arrow functions / lambdas (items.filter(x => x.urgent))
  • The IMAGE, LINK, HTML, EXEC, ALIAS commands
  • Arbitrary globals (Math, Date, JSON, etc.)

What you can't do#

  • Use a template AND a theme together for the body content. The template controls every visual aspect — it IS the styling. The theme isn't consulted during template instantiation. (Themes still apply to spec-driven documents you create separately.)
  • Patch a template-instantiated document and re-render against the template. Once instantiated, the document is a normal spec — the template binding is lost. The instantiation is one-shot.
  • Use FOR/IF in PPTX or XLSX templates. v1.x — see the matrix above. DOCX gets the full grammar today.

Quotas#

The templates_count axis (default 20 per tenant) limits how many templates you can register. Instantiation doesn't have a separate quota — every instantiated doc is just a normal doc, counted under documents_count.

When templates are the right tool#

Use templates when:

  • The visual design is owned by a non-technical stakeholder
  • You produce the same document shape over and over with different data
  • The design is more elaborate than themes alone can express (specific tables, header/footer art, complex page geometry)
  • You need pixel-stable output across runs

Don't use templates when:

  • The document structure varies per request (build the spec dynamically instead)
  • An agent is supposed to author content semantically (let the agent compose elements via MCP tools)
  • You need to edit the produced document after generation (you can, but the template binding is one-shot)

Where to next#

Updated 2026-07-03 13:00:09 View source (.md) rev 10