Templates in workflows
A template on its own is a design; a workflow makes it a production line. The AI writes the copy, a catalogue brings the facts, a photo is generated or cut out — and a template node puts it all on the page, the same way every time, for one customer or for a thousand. This page explains how to connect a template to a workflow so that the result is right and stays right.
Three nodes, chosen by the result
Section titled “Three nodes, chosen by the result”| You need | Node | What it produces |
|---|---|---|
| One document from structured data — the usual choice | Render Document Template (design/template_render) |
PDF, page images, a pages manifest, a layout report; PDF/X-4 for print; always a fixed published revision |
| One document, one input port per field | Generate PDF (document/pdf) |
one PDF |
| One PDF with a page set per item of a list — a catalogue, one certificate per participant | Multi-page PDF (aggregate/pdf) |
one PDF, with optional cover and closing PDFs |
To join a fixed set of PDFs that already exist, use Merge PDF (utility/merge_pdf) instead; it does not iterate.
How data reaches a template
Section titled “How data reaches a template”The template’s contract lists its fields: code, type, required, default, and for lists the keys of each item. Read
it before wiring (get_design_template, view contract; REST GET /api/v1/design-templates/{tpl_id}/versions/{revision}/contract).
The field codes are the keys of the data.
Render Document Template accepts the data three ways, which can be combined:
| Port | Carries | Precedence |
|---|---|---|
field inputs — one port per field code (hero_image, investment, claims) |
a single value for that field | highest |
assets |
a JSON map of image field codes to storage references or URLs | middle |
data, or data_0, data_1, … |
JSON objects keyed by field code, merged in index order (a later object overrides an earlier one’s keys) | lowest |
Generate PDF and Multi-page PDF take only field inputs: each field code of the template is an input port, typed like the field. Connect the fields to fill; the others keep the value written in the template. A connection to a field the template does not have is rejected, with the list of valid fields.
Keep AI copy and verified facts apart
Section titled “Keep AI copy and verified facts apart”The single most important rule: the AI writes words, never facts. Prices, dates, names, legal notes, claims with a source — they come from inputs, catalogues and systems, and must reach the page untouched. Two patterns make it structural:
- Separate data objects. The copy written by the AI on
data_0, the verified offer ondata_1: the offer wins on any shared key, and the AI never even sees the prices. - Field inputs for facts. Connect each fact to its own field port —
investmentfrom a number input,claimsfrom a JSON value,client_logofrom an image input. A field input overrides whatever the data says.
The F01 proposal does both:
Brief ──► Write the copy (AI, JSON) ──► Copy fits the page (JSON schema) ──data──► Render Document Template ──► PDF └─► Cover prompt ──► Paint the cover ──hero_image──► │ ──► PreviewClient logo ──client_logo──► │ Investment ──investment──► │ Approved claims ──claims──► │ ──► Layout reportAmounts computed in the workflow
Section titled “Amounts computed in the workflow”A total, a VAT amount, a deposit or an average is a fact too: the AI must not compute it, even when it has the numbers.
When the source gives the lines but not the totals, compute them with Calculate (utility/calculate): an
expression such as round(sum(quote.items[*].amount) * (1 + vat_rate), 2) whose variables — quote, vat_rate —
become its input ports. The arithmetic is exact decimal, a text value is never read as a number, and a missing field or
a division by zero stops the run instead of printing a wrong or empty amount. Connect its result to a field port
(total), or run it once per item inside an enumerator for a per-line amount.
When the source system already has the totals, pass them through instead: a document that recalculates them could disagree with the invoice by a rounding. The F12 quote does that.
Make the AI write for the page
Section titled “Make the AI write for the page”A template has limited space; the AI does not know it unless you say so, and check it.
- Ask for JSON with the template’s keys, and give each key its limit in characters, taken from the space on the page: “headline”: at most 70 characters, one or two lines. Say what must never appear (numbers, prices, promises).
- Validate it before the render with JSON Schema Validate (
utility/json_schema_validate): the exact keys,additionalProperties: false, andmaxLengthfor every text. In modefaila copy that does not fit stops the run with the list of violations — no document with a truncated headline is produced. - Let the template decide the rest: growth rules, shrink or ellipsis for the texts that vary (see Text).
{ "id": "copy_contract", "type": "utility/json_schema_validate", "parameters": { "schema_source": "inline", "mode": "fail", "schema_definition": { "type": "object", "additionalProperties": false, "required": ["headline", "subheadline"], "properties": { "headline": { "type": "string", "minLength": 20, "maxLength": 70 }, "subheadline": { "type": "string", "minLength": 40, "maxLength": 150 } } } } }Lists and structured values
Section titled “Lists and structured values”A list field (a repeated list in the template) receives one JSON value — the whole array. Pass it with a
JSON Value input (input/json_value) or from a node that produces JSON; do not use an enumerator, which would
split the list into one run per item. See Iteration.
One document per item, or one PDF for the whole list
Section titled “One document per item, or one PDF for the whole list”- One file per item — a flyer per product, a certificate per participant as separate files: put the template node inside the iterated branch. It runs once per item and produces one PDF per item.
- One PDF with a page set per item — a catalogue, a register of certificates: use Multi-page PDF after the
iterated branch. Connect the per-item values to its field ports; values that are not iterated (the course title, the
date) are the same on every item’s pages.
introPdfandoutroPdfadd a cover and closing pages — for example a cover rendered by another template node.
Participants (JSON enumerator) ──► per item: name, hours, merit ──┐Course title, dates ──────────────────────────────────────────────┼──► Multi-page PDF ──► one PDFCover (Generate PDF, another template) ──introPdf─────────────────┘The F10 certificates build exactly this.
Revisions: reproducible output
Section titled “Revisions: reproducible output”- Render Document Template always renders a published revision:
template_idplustemplate_revision; without a revision, the current published one is fixed when the workflow is saved.template_version_policylatest_compatiblelets new runs follow later compatible revisions;pinned(default) never moves. - Generate PDF and Multi-page PDF render the template’s current draft when
template_revisionis not set — useful while designing, risky in production: a later edit to the draft changes every document. Settemplate_revisionbefore you rely on the workflow.
{ "id": "render", "type": "design/template_render", "parameters": { "template_id": "tpl_…", "template_revision": 3, "output": "both", "missing_policy": "fail_required", "overflow_policy": "template" } }Render Document Template settings
Section titled “Render Document Template settings”| Parameter | Values | Use |
|---|---|---|
output |
pdf, image, both, pages |
PDF; one page image (page_selection must pick one page); both; or a manifest of every page image |
page_selection |
all, 1, 1-3, 1,3-5 |
which pages become images |
missing_policy |
fail_required (default), use_template_default |
stop when a required field has no value, or print the template’s own value |
overflow_policy |
template (default), fail, fit, clip |
keep each list’s own rule, or impose one on every list |
max_repeat |
1–100 | ceiling on the items of any list |
pdf_export_mode, color_profile_guid |
standard / pdfx4 and a workspace profile |
print-ready output (see Print-ready PDF) |
Reading the result
Section titled “Reading the result”Besides the PDF and the images, the node returns a layout report (madoo.template-layout-report/v1): the status,
the revision used, list rows printed and left out, images loaded and failed, texts that did not fit, links left out, the
time taken. Expose it as a JSON output while building a workflow — it tells you what happened on the page without
opening the PDF. quality_check is a shorter summary of the same health.
The template nodes cost no credits; the AI steps before them do.
Checklist
Section titled “Checklist”- The contract has been read, and every required field is connected or in the data.
- Facts reach the page through field inputs or a separate data object, never through the AI.
- Totals and other computed amounts come from the source system or from Calculate, never from the AI.
- AI copy is JSON with the template’s keys, validated against a schema with
maxLengthfrom the page. - Lists reach their field as one JSON value, not through an enumerator.
- The template revision is fixed for every template node in production.
- The layout report of a test run shows no rows left out, no image failed, no text cut.