RusDox is designed so the YAML reads like the document.
The basic shape is always:
version: 1
output_name: my-document
blocks:
- type: title
text: My Document
- type: body
text: This is a paragraph.
Top-Level Fields
version
- Required for new files
- Current value: 1
- Use rusdox migrate legacy.yaml --in-place for legacy unversioned files
output_name
- Optional
- Controls the file name of the generated output
- If omitted, RusDox uses the spec file stem
metadata
- Optional
- Controls DOCX package properties such as title, author, subject, keywords, and custom properties
blocks
- Required for real documents
- Ordered from top to bottom
- This is the document structure
styles
- Optional
- Defines reusable named paragraph, run, and table styles
- Supports inheritance through
based_on - Paragraph styles can also set
next
variables
- Optional
- Defines reusable values for nested interpolation, repeat blocks, and bounded conditions
Metadata
Use metadata when generated documents need clean properties in Word, search tools, or downstream automation.
metadata:
title: Client Rollout Plan
author: RusDox Studio
subject: Q4 regional rollout
language: en-US
keywords:
- rollout
- planning
custom_properties:
Client: Northwind Health
Sponsor: Maya Chen
Supported metadata fields:
titleauthorsubjectlanguage: a BCP 47-style document language such asen-US,fr, ormulkeywordscustom_properties
custom_properties values are stored as string custom properties in the DOCX package.
Variables, Includes, And Repeaters
Use these features when one YAML file would otherwise become repetitive.
Variables use {{name}} placeholders:
variables:
client: Northwind Health
quarter: Q4 2026
blocks:
- type: title
text: "{{client}} Rollout Plan"
- type: subtitle
text: "{{quarter}} program snapshot"
Includes inline reusable block fragments relative to the current YAML file:
blocks:
- type: include
path: fragments/summary.yaml
variables:
sponsor: Maya Chen
An included YAML fragment can be:
- a single block mapping
- a sequence of blocks
- a mapping with optional
variablesplusblocks
Repeaters expand a block template for each item in a sequence:
variables:
regions:
- name: North America
owner: Maya
- name: EMEA
owner: Leon
blocks:
- type: repeat
variable: regions
as: region
blocks:
- type: section
text: "{{region.name}}"
- type: body
text: "Owner: {{region.owner}}"
Supported repeat fields:
variable: name of a sequence variable to iterateitems: inline sequence to iterateas: loop variable name, defaults toitemblocks: template block list
Each repeat iteration also exposes:
repeat_index: zero-based indexrepeat_number: one-based index
Conditions, filters, and escaping
Use a bounded when block for truthiness or exact scalar equality:
variables: customer: active: true blocks:
- type: when path: customer.active equals: true blocks:
- type: body text: Active customer otherwise:
- type: body text: Inactive customer
Expressions support nested mapping/array paths and exactly five deterministic filters: upper, lower, title, trim, and default("text").
text: "{{ customer.name | trim | title }}" text: "{{ customer.owner | default(\"unassigned\") | upper }}"
Write four opening braces and four closing braces for literal double braces. Expression values always become document text; they cannot inject raw OOXML or execute code. The same expression behavior is available to JSON and TOML specs. See Spec Versioning and Authoring Tools.
Named Styles
Use named styles when the document needs stable reusable formatting instead of repeating direct properties on every block.
Example:
styles:
paragraph:
- id: lead
based_on: Normal
next: body
paragraph:
alignment: center
spacing_after: 180
keep_next: true
run:
bold: true
color: "0F172A"
font_family: Georgia
font_size: 28
run:
- id: accent
based_on: DefaultParagraphFont
properties:
italic: true
color: "AA5500"
table:
- id: grid
based_on: TableNormal
properties:
width: 9360
blocks:
- type: paragraph
spec:
style_id: lead
runs:
- text: Styled
- text: " emphasis"
style_id: accent
- type: table
spec:
style_id: grid
columns:
- label: Metric
width: 4680
rows:
- cells:
- kind: text
text: ARR
Style definition groups:
styles.paragraphstyles.runstyles.table
Paragraph style fields:
idnamebased_onnextparagraph.listparagraph.alignmentparagraph.spacing_beforeparagraph.spacing_afterparagraph.keep_nextparagraph.page_break_beforerun.boldrun.italicrun.underlinerun.strikethroughrun.small_capsrun.shadowrun.colorrun.font_familyrun.font_sizerun.vertical_align
Run style fields:
idnamebased_onproperties.boldproperties.italicproperties.underlineproperties.strikethroughproperties.small_capsproperties.shadowproperties.colorproperties.font_familyproperties.font_sizeproperties.vertical_align
Table style fields:
idnamebased_onproperties.widthproperties.borders
Units:
- paragraph spacing and table widths use twips
- run
font_sizeuses OOXML half-points, so24means12pt
Simple Block Types
Use these when you want readable documents with strong defaults:
cover_titletitlesubtitleherocentered_notepage_headingsectionbodytaglineimagelogosignaturechartspacer
Example:
blocks:
- type: cover_title
text: Board Report
- type: subtitle
text: March 2026
- type: hero
text: Prepared automatically with RusDox
- type: centered_note
text: Internal use only
- type: page_heading
text: Board Narrative
- type: body
text: Revenue expanded faster than forecast.
page_heading starts a new page before the heading.
spacer adds vertical space when you want breathing room between sections.
Visual Blocks
Use visual blocks when the document needs brand marks, screenshots, signatures, or SVG charts.
Example:
- type: logo
path: ../assets/rusdox-mark.svg
alt_text: RusDox logo
max_width_twips: 2200
- type: image
path: ../assets/template-gallery.png
alt_text: RusDox template gallery
max_width_twips: 7200
- type: chart
path: ../assets/benchmark-stress-1000-pages.svg
alt_text: RusDox benchmark chart
max_width_twips: 7200
- type: signature
path: ../assets/signature-demo.svg
alt_text: Automated approval signature
max_width_twips: 2800
Supported visual fields:
pathalt_textalignment:left,center,right,justifiedwidth_twipsheight_twipsmax_width_twipsmax_height_twips
Supported file formats:
- PNG
- JPEG
- SVG
alt_text is required and must be meaningful. It is preserved in the DOCX drawing properties and checked against the PDF semantic projection; a file name or blank string does not satisfy validation. See the international and accessibility contract.
List Blocks
bullets
- type: bullets
items:
- Confirm launch date
- Finalize sales enablement
- Publish support macros
label_values
Good for notes, metadata, meeting headers, and document summaries.
- type: label_values
items:
- label: Date
value: 2026-03-10
- label: Owner
value: Operations
metrics
Good for dashboard-style cards.
Available tones:
positiveneutralwarningrisk
- type: metrics
items:
- label: ARR
value: $18.7M
tone: positive
- label: Cash Runway
value: 24 mo
tone: warning
Tables
Tables use explicit columns and rows.
Each column needs:
labelwidth
Each row has cells.
Each cell can be:
kind: textkind: status
Example:
- type: table
spec:
style_id: grid
columns:
- label: Category
width: 2800
- label: Current
width: 2000
- label: Status
width: 1600
rows:
- cells:
- kind: text
text: ARR
- kind: text
text: $18.7M
- kind: status
text: Strong
tone: positive
width values are DOCX table widths in twips.
You usually only need to copy a working table from an example and edit the content.
Custom Paragraphs
Use paragraph when you need mixed formatting inside one paragraph.
Example:
- type: paragraph
spec:
alignment: center
spacing_after_twips: 120
runs:
- text: "This is "
- text: important
bold: true
- text: " and "
- text: styled
italic: true
color: D00000
Supported paragraph fields:
runsstyle_idalignment:left,center,right,justifiedspacing_before_twipsspacing_after_twipspage_break_beforesection_break_before
Supported run fields:
textstyle_idbolditalicunderlinestrikethroughsmall_capsshadowcolorfont_familysize_ptvertical_alignhyperlink:https://,http://,mailto:, or#bookmarkbookmark: 1–40 ASCII letters, digits, or underscoresfield: currentlytable_of_contentsfootnote
Underline values:
singledoubledotteddashwavywordsnone
Vertical align values:
superscriptsubscriptbaseline
Shared Page Controls And Semantic Blocks
page_setup, header, footer, and page_numbering are consumed by both DOCX and PDF. Orientation is explicit and must agree with width and height.
page_setup:
width_twips: 15840
height_twips: 12240
orientation: landscape
margin_top_twips: 1080
margin_right_twips: 900
margin_bottom_twips: 1080
margin_left_twips: 900
header:
text: Quarterly review
alignment: right
footer:
text: Page {page} of {pages}
alignment: center
page_numbering:
start_at: 3
format: lower_roman
blocks:
- type: table_of_contents
title: Contents
- type: page_break
- type: section_break
The DOCX TOC is an updateable Word field. PDF emits the heading list known from the spec at render time and does not invent page numbers.
Rich Table Rows And Cells
Rows accept repeat_as_header and allow_split_across_pages. A kind: rich cell accepts paragraphs, horizontal grid_span, background_color, and an optional nested_table. See dual_output_contract.yaml for a complete, parity-tested example.
Best Practices
- Use variables for repeated values, not for every sentence in the document.
- Reach for
includeandrepeatbefore moving to Rust if the workflow is still mostly static content. - Prefer
title,section,body,bullets,metrics, andtablebefore reaching for custom paragraphs. - Let config control styling instead of repeating style values everywhere.
- Copy a close example and edit the content.