lexicon-docx
A Rust CLI that converts Lexicon Markdown legal contracts into formatted Word (.docx) documents.
Website | Playground | Specification | Example Document
Requirements
- Rust (2024 edition)
Installation
The binary is at target/release/lexicon-docx.
Usage
Build a .docx
The output flag is optional — without -o, the output file uses the input filename with a .docx extension.
Validate without building
Parses the document, resolves cross-references, validates defined terms, and prints diagnostics without producing output.
Options
lexicon-docx build <INPUT> [OPTIONS]
Options:
-o, --output <FILE> Output .docx path (default: <input>.docx)
-s, --style <FILE> Style configuration (TOML)
--signatures <FILE> Signature template definitions (TOML)
--strict Fail on warnings (exit code 1)
Config resolution and priority
Style settings are resolved in this order (highest priority first):
- CLI flags —
--font-size 11,--no-cover, etc. - TOML file in the input directory —
style.tomlnext to the contract - TOML file in XDG config —
$XDG_CONFIG_HOME/lexicon/style.toml(defaults to~/.config/lexicon/) - Built-in defaults
An explicit --style flag replaces steps 2–3 (the specified file is loaded, then CLI flags still override it).
Signature definitions (signatures.toml) follow the same discovery order (input dir → XDG), overridden by an explicit --signatures flag.
CLI style overrides
Every style.toml setting can also be set from the command line. This is useful for one-off builds or scripting without creating a TOML file.
Typography:
| Flag | Description | Default |
|---|---|---|
--font-family <NAME> |
Body text font family | Times New Roman |
--font-size <PT> |
Body text size in points | 12 |
--heading-font-family <NAME> |
Heading font family | Times New Roman |
--title-size <PT> |
Document title size in points | 20 |
--heading1-size <PT> |
Level 1 heading size in points | 14 |
--heading2-size <PT> |
Level 2 heading size in points | 12 |
--heading-space-before <PT> |
Space before section headings in points | 18 |
--heading-space-after <PT> |
Space after section headings in points | 12 |
--paragraph-space-before <PT> |
Space before paragraphs in points | 0 |
--paragraph-space-after <PT> |
Space after paragraphs in points | 6 |
--line-spacing <N> |
Line spacing multiplier | 1.5 |
--defined-term-style <STYLE> |
bold, quoted, or bold-quoted |
bold |
--brand-color <HEX> |
Brand color (e.g. "#2E5090") |
none |
Page layout:
| Flag | Description | Default |
|---|---|---|
--page-size <SIZE> |
a4 or letter |
a4 |
--margin-top <CM> |
Top margin in cm | 2.54 |
--margin-bottom <CM> |
Bottom margin in cm | 2.54 |
--margin-left <CM> |
Left margin in cm | 2.54 |
--margin-right <CM> |
Right margin in cm | 2.54 |
Clause indentation:
| Flag | Description | Default |
|---|---|---|
--indent-per-level <CM> |
Indent per clause level in cm | 1.27 |
--hanging-indent <CM> |
Hanging indent for numbers in cm | 1.27 |
--body-align-first-level |
Align first-level body clauses with second level | off |
--no-body-align-first-level |
(opposite of above) | |
--recitals-align-first-level |
Align first-level recital clauses with second level | off |
--no-recitals-align-first-level |
(opposite of above) |
Formatting:
| Flag | Description | Default |
|---|---|---|
--date-format <FMT> |
chrono strftime format string | %e %B %Y |
Cover page:
| Flag | Description | Default |
|---|---|---|
--cover / --no-cover |
Enable/disable cover page | on |
--cover-between-label <TEXT> |
"Between" label on cover | BETWEEN |
--cover-party-format <FMT> |
name-spec-role, name-role, or name-only |
name-spec-role |
--cover-ref / --no-cover-ref |
Show/hide reference on cover | on |
--cover-author / --no-cover-author |
Show/hide author on cover | on |
--cover-status / --no-cover-status |
Show/hide status on cover | on |
Table of contents:
| Flag | Description | Default |
|---|---|---|
--toc / --no-toc |
Enable/disable table of contents | on |
--toc-heading <TEXT> |
TOC heading text | Contents |
Footer:
| Flag | Description | Default |
|---|---|---|
--footer-ref / --no-footer-ref |
Show/hide reference in footer | on |
--footer-page-number / --no-footer-page-number |
Show/hide page numbers | on |
--footer-version / --no-footer-version |
Show/hide version in footer | off |
Preamble:
| Flag | Description | Default |
|---|---|---|
--preamble / --no-preamble |
Enable/disable parties preamble | off |
--preamble-style <STYLE> |
simple, prose, or custom |
simple |
Schedule:
| Flag | Description | Default |
|---|---|---|
--schedule-position <POS> |
end or after-toc |
end |
--schedule-order <ORDER> |
document or alphabetical |
document |
Signatures:
| Flag | Description | Default |
|---|---|---|
--enable-signatures / --no-signatures |
Enable/disable signature pages | on |
--signatures-heading <TEXT> |
Heading text for signature section | none |
--signatures-template <KEY> |
Default signature template key | none |
--signatures-separate-pages |
Each signature block on its own page | off |
Note: Preamble templates (
preamble.template,preamble.party_template,preamble.party_separator) and per-party signature overrides (signatures.party.*) are TOML-only — they contain structured data that doesn't lend itself to CLI flags.
Man pages
Generate man pages with:
This creates lexicon-docx.1, lexicon-docx-build.1, and lexicon-docx-validate.1 in the output directory. Install them to your man path (e.g. /usr/local/share/man/man1/) to use with man lexicon-docx.
Features
| Feature | Description |
|---|---|
| Cover page | Title, parties, date, status, version, author, reference |
| Table of contents | Auto-generated from clause headings |
| Legal numbering | Native Word numbering: 1., 1.1, (a), (i), (A), (I) |
| Cross-references | {#id} anchors resolved to clickable Word hyperlinks |
| Defined terms | Bold terms validated for usage; warnings on unused terms |
| Recitals / Background | Optional pre-body section with independent numbering |
| Parties preamble | Configurable introductory block with party details |
| Schedule pages | Terms referencing a schedule auto-collected into a completion table |
| Signature pages | Template-based execution blocks with jurisdiction-aware defaults |
| Exhibit pages | Imported images (PNG/JPG) and PDFs, or placeholder pages |
| Draft watermark | Diagonal "DRAFT" watermark when status: draft |
| Headers/footers | Document reference, page numbering, optional version |
Style Configuration
Copy style.example.toml and customise it. All fields are optional — sensible defaults are built in.
Typography and layout
= "Times New Roman"
= 12.0
= "Times New Roman"
= 20.0
= 14.0
= 12.0
= 1.5
= "a4" # "a4" or "letter"
= 2.54
= 2.54
= 2.54
= 2.54
Clause indentation
= 1.27
= 1.27
= false # true: body levels 0 and 1 share the same indent
= false # true: recitals levels 0 and 1 share the same indent
Defined term rendering
= "bold" # "bold", "quoted" (curly quotes), or "bold_quoted"
Date formatting
= "%e %B %Y" # chrono strftime format
Cover page
[]
= true
= "BETWEEN"
= "name_spec_role" # "name_spec_role", "name_role", or "name_only"
= true
= true
= true
Set enabled = false for a minimal inline title instead of a full cover page.
Parties preamble
[]
= false
= "simple" # "simple", "prose", or "custom"
With style = "custom", you define templates with placeholders:
[]
= true
= "custom"
= "This {title} (**{type}**) is dated {date} between"
= "{name} ({specifier}) (**{role}**)"
= "; and"
Table of contents
[]
= true
= "Contents"
Footer
[]
= true
= true
= false # appends version to ref, e.g. "OK:RP:20260115v3"
Schedule
= "end" # "end" (after addenda/exhibits) or "after_toc"
= "document" # "document" (source order) or "alphabetical"
Spacing
= 18.0 # space before section headings (pt)
= 12.0 # space after section headings (pt)
= 0.0 # space before paragraphs (pt)
= 6.0 # space after paragraphs (pt)
Branding
= "#2E5090" # applies to title and heading text
Signature Pages
Signature blocks are generated from templates based on each party's entity_type and whether the document is a deed or agreement.
Setup
- Add
entity_typeto parties in the front-matter:
parties:
- name: Acme Corp Pty Ltd
specifier: ACN 123 456 789
role: Acme
entity_type: au-company
- Enable in
style.toml:
[]
= true
- Place
signatures.tomlalongside your contract or in~/.config/lexicon/.
Entity types
| Value | Meaning |
|---|---|
au-company |
Australian company |
au-individual |
Australian individual |
au-sole_director |
Australian sole director company |
uk-company |
UK company |
uk-individual |
UK individual |
us-company |
US company |
us-individual |
US individual |
nz-company |
New Zealand company |
nz-individual |
New Zealand individual |
The execution method is inferred from the type front-matter field: Deed uses deed-style wording, anything else uses agreement-style.
Template resolution
For each party, the processor resolves a template in this order:
- Explicit TOML override (
signatures.party.{Role}.template) - Definitions file lookup (from
entity_type+ execution method) - Hardcoded fallback (minimal signature block)
Per-party overrides
[]
= "au.sole_director.deed"
= [
{ = "Sole Director and Sole Company Secretary" },
]
[]
= true
See SIGNATURES.md for the full signature page documentation, including how to write custom templates.
Exhibits
Exhibits attach external documents to the contract. Declare them in the front-matter:
exhibits:
- title: Floor Plan
path: ./floor-plan.png
- title: Technical Specifications
Supported file types: PNG, JPEG, and PDF (rendered to images via hayro, a native Rust PDF renderer — no external dependencies required). When path is omitted, a placeholder page is generated. Relative paths are resolved against the input file's directory.
Diagnostics
The processor emits warnings and errors during validation:
- Undefined cross-references (broken
#anchorlinks) - Defined terms that are never used in the document
- Declared schedules with no referencing terms
- Missing signature definitions
- Invalid front-matter (bad dates, empty parties)
Use --strict to treat warnings as errors:
License
MIT