Skip to content

Template Authoring

Codraft templates are standard .docx or .html files with Jinja2-style markup embedded in the content. This guide covers everything you need to write templates that work correctly with the interview engine.

Use double-brace syntax to mark any text that should be collected from the user:

This Agreement is entered into by {{ disclosing_party_name }}
(the "Disclosing Party") with address at {{ disclosing_party_address }}.

Rules:

  • Always include spaces inside the braces: {{ name }} not {{name}}
  • Variable names must be valid Python identifiers: lowercase letters, numbers, and underscores; no spaces or hyphens
  • The same variable can appear any number of times — it is collected once and substituted everywhere

In .docx files, place placeholders directly in the document text. Codraft uses docxtpl, which preserves all formatting around the placeholder. In .html files, placeholders can appear anywhere in the body, attributes, or <style> blocks.

Use {% if %} / {% else %} / {% endif %} to include or exclude a section based on the user’s answer:

{% if include_warranty %}
The Seller warrants that the goods are free from defects for a period
of {{ warranty_period }} from the date of delivery.
{% else %}
The goods are sold "as is" without warranty of any kind.
{% endif %}

When Claude reaches a conditional gate variable (include_warranty above), it asks a yes/no question. If the answer is no, the entire {% if %} block — and all variables inside it — is skipped.

Truthiness — the variable is truthy (boolean true, or any non-empty string):

{% if include_ip_assignment %}
...
{% endif %}

Equality — the variable equals a specific value:

{% if payment_method == 'bank_transfer' %}
Bank: {{ bank_name }}
Account: {{ account_number }}
{% else %}
Payment will be made via {{ payment_method }}.
{% endif %}

For equality conditions, Claude collects the gate variable first (using a choice list if configured), then shows only the relevant branch questions.

You can use {% if %} / {% endif %} without an {% else %} block. If the condition is false, the section is simply omitted.

Use {% for %} / {% endfor %} for repeating sections — line items, milestones, signatories, or any list:

{% for milestone in milestones %}
Milestone: {{ milestone.description }}
Due Date: {{ milestone.date }}
Amount: {{ milestone.amount }}
{% endfor %}

Inside the loop body, sub-variables are referenced with dot notation: {{ loop_variable.field_name }}.

Claude collects the first item’s fields, then asks “Would you like to add another milestone?” The loop continues until you say no. The loop variable (milestones) holds a list of objects, each with the sub-fields you defined.

  • One template file per directory — each template directory contains exactly one .docx or .html file, not both
  • Single-level nesting only — do not place {% for %} inside {% if %}, or {% if %} inside {% for %}
  • No {% elif %} — use separate {% if %} blocks instead
  • No expressions{{ price * quantity }} is not supported; collect pre-calculated values from the user
  • Variables are always user-supplied — there are no computed or derived fields in v2
Feature.docx.html
Enginedocxtpljinja2
Output.docx.html + .pdf
FormattingPreserved from templateControlled by CSS
SyntaxSame Jinja2 syntaxSame Jinja2 syntax
TablesNative Word tablesHTML <table>

For legal documents where formatting matters (line spacing, fonts, headers), .docx is usually the right choice. For documents that will be sent digitally or embedded in web workflows, .html + PDF is more flexible.