How an AI agent should author .lx.md documents in markdown for LX Draft.
A .lx.md file is a UTF-8 text file with three parts:
--- markers at the top)The simplest .lx.md is just markdown wrapped in frontmatter:
---
format: "lxd/1.0"
title: "My Document"
revision: "v0.1"
status: "draft"
---
# My Document
This is the body. Standard Markdown works fine.
LX Draft stores a self-excluding SHA-256 hash in frontmatter.integrity to detect later
tampering (it underpins signature auto-clear-on-edit). As an agent, never write or guess the
integrity field — omit it entirely. LX Draft computes and injects the correct hash
automatically when the document is saved or edited in the app. A hash you invent would be wrong and flag
the document as modified. (Unsigned drafts don't need a hash at all; it only matters once a human/Lexis
signs the document.)
LX Draft is used two ways, and it affects governance (not how you write content):
.lx.md file the user opens/saves on
their own drive (or Google Drive). The user self-signs; revision history is a table they maintain.lexis_controlled: true in its frontmatter.
As an agent you write the same markdown either way. Do not set lexis_controlled
yourself, and do not try to sign documents — placing a {signature:...} field is
enough; the human or Lexis performs the signing.
You MUST include these:
format: "lxd/1.0" # always this exact value
title: "Document Title" # required
revision: "v0.1" # use v0.1 for first draft
status: "draft" # draft | review | approved | released | obsolete
Add these whenever you have the information:
short_title: "Short Name" # for headers / breadcrumbs
document_number: "T-XXX-001" # if there's a doc numbering scheme
date_created: 2026-03-30 # YYYY-MM-DD
classification: "internal" # public | internal | commercial-in-confidence | restricted
template: "standard" # standard | proposal | test-report | datasheet | minutes | review
project: "Project Name"
prepared_for: "Client Name"
author: "Your Name"
font: "Poppins" # default body font; use Poppins unless told otherwise
cover: true # render the LX-branded blue cover page in the PDF
LX Draft can render a branded cover page at the front of the PDF — a full-bleed page with a dark background, a blue title block, the document number, and a footer with the LX logo and a metadata table (project, client, author, revision, date). It's gated behind a single frontmatter flag so plain memo-style documents don't get a heavy cover they don't want:
cover: true
The cover only renders in the PDF export (and the in-app Print Preview, which is a PDF rendered in an iframe). The editor canvas itself stays cover-less so you can edit body content without the cover taking up half the screen. If you don't set cover: at all, the cover is suppressed by default.
Fields the cover surfaces. Populate as many as you have; missing fields are skipped gracefully:
title — the big bold title in the blue title block (already required for the body, used here too).short_title — used as the visible title if shorter than title; otherwise title is used.document_number — rendered immediately under the title in a monospace font (typical doc-control numbering like T-REV-SCH-CMP or PSD-002).revision — appears in the metadata table at the bottom of the cover (e.g. v0.1).date_created — appears in the metadata table.project — appears in the metadata table.prepared_for — appears in the metadata table (typically the client name).author — appears in the metadata table.classification — when set to commercial-in-confidence or restricted, also paints a classification banner across the cover.When to set cover: true. Use it for formal external deliverables — client proposals, design reports, test reports, formal specifications. Skip it (or set cover: false) for internal memos, meeting minutes, short notes, and anything that's going to be read on-screen rather than printed.
Templates and the cover. If the user has selected a template (e.g. template: "standard" or template: "proposal"), check that template's own frontmatter for cover: true. The shipped LX templates may already enable it — in which case the cover renders automatically without you having to add cover: true to your document. If the template hasn't enabled it but the document should have one, override by setting cover: true explicitly in your document's frontmatter.
Custom cover (cover_html). The built-in cover suits most documents, but you can replace it entirely with your own HTML by setting cover_html. When non-empty it replaces the built-in cover. Field codes (see below) resolve inside it; the HTML is sanitized (scripts/event-handlers stripped, styling + inline style kept). Leave it unset to use the built-in cover.
Every page of the PDF (not the editor canvas, and not the cover page) can carry a running header and footer. There are two layers and they stack: small field-code text boxes in the margins, and optional full-bleed custom-HTML bands behind them.
header_enabled: true # default true; false hides the header in the PDF
footer_enabled: true # default true; false hides the footer
header_left: "{title}" # field-code text, top-left
header_right: "{date:MMM YYYY}"
footer_left: "Page {page} of {pages}"
footer_center: "{revision}"
footer_right: "{document_number}"
footer_notice: "" # small centred note under the footer
Defaults vs blank. An absent field falls back to a sensible default (title / date on top; page-of-pages / revision / doc-number on the bottom). A field set to an empty string (header_left: "") stays intentionally blank — use this to clear a default you don't want (e.g. when a custom band supplies the text).
On/off. header_enabled: false / footer_enabled: false omit that band from the PDF entirely (default on). Field values are preserved either way.
header_html / footer_html)To make a branded bar — like the LX blue gradient header — put HTML in header_html (or footer_html). It renders as a full-bleed band repeated on every content page (never on the cover). The field-code text layers on top of it, so live page numbers still work over a band. Recipe for an LX-blue header:
header_html: '<div style="height:16mm;background:linear-gradient(90deg,#2ba0e8,#4ab4f5);color:#fff;display:flex;align-items:center;justify-content:space-between;padding:0 20mm;box-sizing:border-box;font-weight:700;"><span>{title}</span><span style="font-weight:400;">{date:MMM YYYY}</span></div>'
header_left: "" # clear default field text so it doesn't collide with the band
header_right: ""
margins.top / margins.bottom, default 25mm). A band taller than its margin is clipped or dropped. For a 16mm band keep margins.top ≥ ~20mm; when unsure, set the margin a few mm larger than the band.{title}, {revision}, {document_number}, {date:MMM YYYY}, …) resolve inside the HTML. {page} / {pages} do NOT resolve inside custom HTML — keep page numbers in the field-code boxes, which layer on top.div, span, svg, img, a and inline style (incl. gradients) are allowed; <script>, <iframe>, and on* handlers are stripped.#2ba0e8 → #4ab4f5).A diagonal watermark is driven by classification (there is no separate watermark field): when classification is commercial-in-confidence or restricted, the PDF paints that phrase diagonally across every page, sized to fit. (footer_notice is different — it's the small upright note under the footer.)
Header/footer fields and custom-HTML bands support these placeholders, resolved at export:
{title}, {short_title}, {document_number}, {revision}, {author}, {status}, {project}, {prepared_for} — the matching frontmatter value.{date:MMM YYYY} — date_created, formatted. {now:MMM YYYY} — today's date.{page} / {pages} — current / total pages. Field-code boxes only, not custom HTML.Force a hard page break in the body with an HTML comment on its own line:
<!-- pagebreak -->
Use it to push a section onto a fresh page (e.g. before a major appendix). Don't overuse it — the exporter already paginates and keeps headings with their content, callouts whole, and table headers with their rows.
These work as you'd expect from any Markdown:
# H1 through ###### H6 for headings**bold**, *italic*, ~~strikethrough~~, `inline code`~subscript~ (single tilde) and ^superscript^ (caret) — e.g. H~2~O, x^2^- bullet list and 1. numbered list (nest with 2-space indent)| col | col | pipe tables (with header separator row)> blockquote```language[link text](https://url) for hyperlinks--- for horizontal rules
Watch the tilde and caret. Because ~text~ renders as
subscript and ^text^ as superscript, do not type a bare
ASCII ~ to mean "approximately" — a ~500 mAh and a later ~15 mAh
will pair up and turn everything between them into subscript. Use the proper Unicode symbols instead
(neither triggers sub/superscript):
∼ (U+223C), e.g.
∼500 mAh, ∼250 mm.≈ (U+2248), e.g.
Vmp ≈ 2.2 V.Likewise avoid a stray ^ in prose (it starts superscript).
Use these for tips, warnings, important notes:
> [!NOTE]
> Informational note. Blue left border.
> [!TIP]
> Helpful tip. Green left border, "Tip:" prefix.
> [!IMPORTANT]
> Important caveat. Amber left border, "Important:" prefix.
> [!WARNING]
> Warning text. Red left border, "Warning:" prefix.
> [!STEP]
> Procedural step. Blue left border, no prefix.
Use GFM pipe tables for all tables, whether the data is a short inline grid, a BOM, a checklist, or a long list of requirements. Pipe-table cells are fully editable in place — clicking a cell selects text normally, and the table can be resized, sorted, and rearranged by the reviewer.
| Reference | Part Number | Quantity | Manufacturer |
| --------- | ---------------- | -------- | ------------------ |
| U1 | STM32F405RGT6 | 1 | STMicroelectronics |
| C1 | CL21B104KBCNNNC | 10 | Samsung |
| R1 | RC0805FR-07100KL | 4 | Yageo |
Escape any literal | inside a cell as \|. Cells may contain inline markdown
(**bold**, `code`, links, math) but not block content (lists, paragraphs).
If a workflow connector or downstream tool needs to identify a table by what kind of data it carries (e.g.
"the BOM in this doc"), place an optional <!-- table-type: X --> sentinel comment on the
line immediately above the table:
<!-- table-type: bom -->
| Reference | Part Number | Quantity |
| --------- | ---------------- | -------- |
| U1 | STM32F405RGT6 | 1 |
Common labels: bom, requirements, test-results, registers,
checklist. The label is free-text; pick whatever fits. The sentinel is invisible in the rendered
document and is preserved through editor round-trips, so a human reader never sees it but a workflow agent can
find the right table by scanning for it.
Earlier versions of LX Draft supported ```csv:label``` fenced blocks as a separate "rich CSV
table" node. That format is now deprecated: it renders as a read-only grid in the editor
(cells can't be clicked into), and inline commas inside cells silently split rows into extra columns —
both serious authoring traps. Existing documents containing csv: blocks still open and edit
cleanly (the editor converts them to native pipe tables on load), but agents should not write new
csv: blocks. Always use a pipe table; if data-typing is needed, use the
<!-- table-type: X --> sentinel above it.
Inline math: $R = V / I$ where $V$ is voltage.
Block math:
$$
P_{total} = \sum_{i=1}^{n} V_i \cdot I_i
$$
This statement needs a citation[^1].
This refers to an endnote[^note:pricing].
[^1]: Footnote text — typically appears at the bottom of the page.
[^note:pricing]: Endnote text — appears at the end of the document.
<!-- bookmark: thermal-section -->
See {ref:sec:introduction} for background.
Refer to {ref:bookmark:thermal-section|the thermal section} for details.
You can embed a live reference to a frontmatter field in the body. It renders the current value of
that field (and updates if the frontmatter changes), and resolves to the value in PDF/DOCX export. Use the
{field:NAME} token:
Document number: {field:document_number}
Revision {field:revision} — prepared for {field:prepared_for}.
Valid field names: title, short_title, document_number,
revision, author, status, classification,
date_created, project, prepared_for.
In the editor, a human inserts these via the Insert Field toolbar button; as an agent, just
write the {field:NAME} token in the markdown — it round-trips and resolves on export.
A signature field renders the signer's name (in a cursive font) once the document is signed, or a muted "Your signature here" placeholder when unsigned:
Signed: {signature:author}
Signing itself is a human/Lexis action (see "Standalone vs Lexis" above) — as an agent you place the
{signature:...} token where the signature should appear; you do not sign the document.
If you need a hard page break in the printed output:
<!-- pagebreak -->
<!-- columns: 2 -->
Content here flows into two columns.
<!-- /columns -->
<!-- textbox -->
Content inside a bordered box.
<!-- /textbox -->
For external images (URLs), use standard Markdown:

For embedded images, use the asset reference syntax:

Then add the image to a document-assets block at the end of the file (see "Embedded images" below).
Size, alignment and crop are persisted as an HTML comment immediately after the image. You normally don't need to write these (the human adjusts images by dragging in the editor), but they round-trip and the exporter honours them:
<!-- width=320 height=180 align=center crop=10,10,10,10 -->
width / height — display size in px.align — left | center | right | inline.
left/right float the image so body text wraps around it; center is a
centered block.crop — top,right,bottom,left inset in px (the visible region is the image minus
these insets). Omit if not cropped.Insert a self-updating TOC anywhere:
<!-- toc -->
The editor renders this as an actual TOC. In source form it stays as the directive.
Do not base64-encode media inside the .lx.md. LLM output is unreliable for large binary blobs — you will silently truncate, corrupt, or hit token limits. Instead, deliver two things:
.lx.md (or .md) file with asset:<id>
references in the body..zip archive containing the actual media files, named to match those
references.LX Draft's import dialog has a "Document + Archive" tab that does the embedding for you — it reads the archive, matches each ref to a file, base64-encodes server/browser-side, and produces a self-contained .lx.md.
Strongly preferred — use bare asset:<id> references with no folder prefix:


<id> must match a filename stem somewhere in the bundle folder (e.g.
asset:photo-013435032 matches photo-013435032.jpg). or
. If you change the folder name later, every
reference breaks. Use  and let LX Draft handle the lookup.
Relative paths (./diagrams/field-plot.png) are accepted as a fallback — LX Draft matches them by
exact path then by basename — but they couple the document to the directory layout. Avoid them in agent output.
Absolute filesystem paths (C:\..., /home/...) can never resolve in a browser.
Don't use them.
The folder can be flat or have subfolders — both work, because LX Draft matches by filename stem. Filename
stems must be unique within the bundle when you use asset:<id> references.
my-report/ ← name doesn't matter; user picks this folder
├── photo-013435032.jpg ← matches asset:photo-013435032
├── photo-013449261.jpg ← matches asset:photo-013449261
└── pcb-rev-b.png ← matches asset:pcb-rev-b
If you have many media files of different types, put them in subfolders for your own organisation — the matcher still works:
my-report/
├── photos/
│ ├── photo-013435032.jpg ← still matches asset:photo-013435032
│ └── photo-013449261.jpg
└── diagrams/
└── pcb-rev-b.png ← still matches asset:pcb-rev-b
The asset:<id> reference does not include the subfolder.
Anything LX Draft can render or link: png, jpg/jpeg, gif,
webp, svg, bmp, tiff, pdf, mp4,
webm, mp3, wav, ogg. The MIME type is inferred from the
extension.
For flowcharts, block diagrams, and sequence/state/ER diagrams, write a Mermaid
diagram in a fenced code block. LX Draft renders it live in the editor and in the PDF
export — you do not hand-draw the SVG. Tag the fence ```mermaid so it
is recognised (a bare fence whose first line is a Mermaid keyword like flowchart is also
auto-detected, but tag it to be safe):
```mermaid
flowchart TB
A["<b>Shared core</b><br/>control board"] --> B["Path 1"]
A --> C["Path 2"]
```
Inside node labels you may use <br/> for line breaks and
<b>…</b> for bold (they render). Keep one diagram per fence, and write the
fence as plain body text — do not wrap it in review/change markers. Mermaid is the
best choice for structural diagrams; for schematic sketches or highly custom artwork, use an
inline ```svg fence instead (below) — both render the same way and keep the document
self-contained.
Mermaid is laid out automatically and can only be changed by editing its text — the
human cannot hand-edit a Mermaid diagram graphically (there are no coordinates to drag;
the layout engine derives positions from the relationships you describe, so a manual nudge has nowhere to
be saved). So if a Mermaid diagram can't capture the detail or exact layout the user wants,
or they are unhappy with how it came out and want to fine-tune it by hand, produce an
```svg version instead: an inline SVG fence renders the same way, but the human
can open it in the in-app graphical editor (the Edit graphically button) and
adjust shapes, arrows and text directly. In short — Mermaid for quick structural diagrams; escalate to an
```svg fence whenever the user needs precise, hand-tunable control.
Like Mermaid, a ```svg fenced code block renders live in the
editor and in the PDF export — the SVG source sits directly in the document body as plain
text. This is the preferred way to hand-author a diagram: no base64, no
document-assets block, no separate media bundle to deliver alongside the
.lx.md. Use it for schematic sketches, custom layouts, or any vector artwork that
doesn't fit Mermaid's flowchart/sequence grammar:
```svg
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="120" viewBox="0 0 300 120">
<rect x="10" y="10" width="120" height="50" rx="6" fill="#eaf6fe" stroke="#2ba0e8"/>
<text x="70" y="40" text-anchor="middle" font-family="Inter, sans-serif" font-size="14">Block A</text>
</svg>
```
The content must be a valid standalone <svg>…</svg> document (same
explicit width/height rule as below). It is run through a strict
sanitizer on render, so do not include <script>, event-handler
attributes (onclick, onload, …), <foreignObject>, or
external http(s):/javascript: URLs in href/xlink:href
— all of these are stripped. Inline data:image/* URIs and local #id
references (gradients, clip-paths, markers) are fine. Like a normal image, the rendered fence
carries a size/alignment comment that round-trips, so the human can resize or realign it in the
editor afterwards — and, unique to ```svg (not Mermaid), the human can click
Edit graphically on the block to adjust the drawing by hand in the built-in editor.
Prefer ```mermaid or ```svg fences over the base64
document-assets approach below whenever the diagram is text-derivable or
hand-authored — both travel inside the document as text, so the doc stays self-contained. Keep
base64/asset embedding for genuinely binary raster media (photos, screenshots).
For block diagrams, schematic sketches, flowcharts, and similar figures where you want the SVG
treated as an image object (draggable, resizable, croppable like a photo) rather than an inline
fence, write the diagram as an SVG and embed it like any other image
( + matching my-diagram.svg in the media
folder). SVG scales perfectly at any zoom, survives PDF and DOCX export, and remains editable. It
is much better than ASCII art in a fenced code block, which depends on a monospace font being
installed and renders inconsistently in different browsers and exports. For most diagrams, though,
the inline ```svg fence above is simpler and keeps the document self-contained.
Critical: the <svg> root element MUST carry explicit
width and height attributes. viewBox on its own is not
enough — without intrinsic size, the image collapses to 0×0 in the editor and disappears
visually even though it is technically embedded. Set them to the natural pixel dimensions of the
diagram (the same numbers you use in viewBox):
<svg xmlns="http://www.w3.org/2000/svg"
width="920" height="1120"
viewBox="0 0 920 1120">
...
</svg>
Other SVG authoring tips:
<text> elements
(font-family="Inter, -apple-system, Segoe UI, Roboto, sans-serif") so the diagram
renders consistently without depending on a web font being loaded.<defs><style> block and reference classes
on each shape — keeps the SVG small and the look uniform.<marker> elements for arrowheads instead of drawing triangles by
hand — they scale, recolour, and align with the line automatically.<g transform="translate(x,y)"> so you can
reposition whole blocks by changing one number rather than every coordinate inside..lx.md files unwieldy.
When a diagram is derived from a text source — typically an ASCII sketch handed to you, but also
Mermaid, Graphviz DOT, or a brief prose description — include that source in the document so a
future human or agent can read, copy, and refine it. Place an
<!-- ascii-source: ... --> HTML comment immediately above the image's markdown
reference:
<!-- ascii-source:
[100–240 V AC]
│
[EMI Filter] ← Common-mode choke + X/Y capacitors
│
[Bridge Rectifier + Bulk Cap]
-->

The source is invisible in the rendered document, survives save/load round-trip, and is shown
in the editor's Image Properties panel (right-hand sidebar) whenever the image
is selected — so a human can read it, copy it, or paste an updated version that will then be
used to regenerate the SVG. The label ascii-source is fixed; the content is
free-form text. If your source contains a literal -->, the editor inserts an
invisible zero-width space to break the closing sequence so the comment doesn't truncate.
.lx.md file (with asset: references, no document-assets block).You don't need to zip anything. Write the files into a folder; LX Draft reads only the files actually referenced by the document and ignores the rest.
If you absolutely cannot deliver media files (e.g. you only have URLs), use plain HTTPS image references. They'll work but won't be embedded — the document depends on the URL staying live.
The format is documented for completeness. Avoid using it from an agent:
<!-- document-assets
- id: pcb-rev-b
filename: pcb-layout-rev-b.png
mime: image/png
size: 145832
data: iVBORw0KGgoAAAANSUhEUgAA[... full base64 string, no line breaks ...]
/document-assets -->
The data: field must be the complete base64 (no line breaks, no truncation). The
size: field should match the original file's byte length.
The <!--[c1]-->...<!--[/c1]--> and
<!--{ch1:del}-->...<!--{/ch1}--> syntax is for review comments and tracked changes.
Do not generate these manually. Use the API endpoints if you need to add review data
programmatically.
To change wording wherever it appears in the document — for example, rewording every mention of a fixed quantity into a range — work like a person using Find & Replace, do NOT write a summary of the places that need changing:
lxdraft_find_text with the phrase to see every hit and its surrounding
context, so you know how many places there are.lxdraft_replace_text with find (the exact words you read) and
replace (your new wording). With from omitted it changes the FIRST match from
the top of the document, as a tracked change the user reviews.remaining_matches in the result. If it is greater than 0, call
lxdraft_replace_text again with from set to the returned next_from,
wording that replacement for its own context. Repeat.remaining_matches is 0.
Never append an appendix or list describing the changes to make — make each edit with
lxdraft_replace_text.
Engineering documents are read for reference, not narrative. Structure beats prose. Use these tools deliberately:
## 1 Section — top-level. Numbered. Examples: Introduction, Scope, Requirements, Test Plan.### 1.1 Subsection — major topic within a section. Numbered.#### Subtopic — finer division. Usually unnumbered.##### Detail and ###### Note — rare; only for deep technical reference material.Don't skip levels. Going from ## straight to #### confuses readers
and breaks the table of contents.
Don't use # (H1) inside the body — the document title is in the frontmatter and
rendered as the cover. Body sections start at ##.
> [!IMPORTANT] callout.> [!WARNING].> [!TIP].> [!STEP].> [!NOTE].Don't overuse callouts. If every other paragraph is a callout, none of them stand out.
**bold** for terms being defined and absolutely critical phrases. Two or three per page
maximum.*italic* for proper nouns, document titles, and gentle emphasis.`inline code` for identifiers, filenames, signal names, command-line arguments, register
names — anything the reader might type or look up literally.Use GFM pipe tables for every table — BOMs, checklists, requirements, test results, register maps, sign-off
sheets, narrative grids. They're fully editable in place and serialize cleanly. If a downstream tool needs to
identify a particular table by its data-type, prefix it with a <!-- table-type: X -->
sentinel comment (see the Tables section above). Do not use the legacy ```csv:label``` fence in
new documents — it's deprecated.
A typical LX engineering document has this structure:
---
[frontmatter]
---
<!-- toc -->
## 1 Introduction
Brief overview of the document and project.
## 2 Scope
What this document covers.
## 3 [Main content section]
### 3.1 Subsection
Content here.
### 3.2 Another subsection
<!-- table-type: requirements -->
| ID | Description | Criticality |
| ------- | ------------------------------------ | ----------- |
| REQ-001 | System must boot in under 5 seconds | High |
| REQ-002 | Battery life must exceed 8 hours | High |
## 4 [Another main section]
## Appendix
### A. Additional Information
If you're an agent producing a document, you have two options:
Just write standard markdown. The user clicks "Import Markdown" in LX Draft and uploads the file. LX Draft wraps it in default frontmatter automatically.
Write the full file with frontmatter. The user clicks "Import Markdown" → "Upload File" and selects the .lx.md. It imports as-is.
Stuff agents have actually done that broke the import or rendering. Don't repeat these:
layout: "page",
page_size: "A4", margins: "standard". LX Draft has a fixed schema; unknown fields
are silently ignored. If you think you need a layout option, you don't — page geometry is decided by the
renderer.Components not
Table 3: Components. The renderer numbers tables, figures, and equations automatically.# Title. The title goes in the
YAML frontmatter only. Body sections start at ## 1 Section.. Use
. The folder name doesn't survive into the import.document-assets. If you find yourself writing a
data: field by hand, stop. Deliver media as separate files alongside the .lx.md and let the
user import the bundle. LLMs cannot reliably emit hundreds of KB of base64 in one shot — output gets
truncated silently.<!--[c1]-->...<!--[/c1]--> or
<!--{ch1:del}-->. Those are for human review tooling. Agents should never write them
manually.```csv:label``` blocks in new documents. That format is
deprecated — use a pipe table, and add a <!-- table-type: X --> sentinel above it if
data-typing is needed. CSV blocks render read-only at the cell level and silently corrupt rows whose cells
contain unquoted commas.## → ####). Breaks the table of
contents and the document map.
LX Draft has a public validation endpoint. Run your .lx.md through it before handing the document
to the user — you'll catch malformed YAML, missing required fields, broken asset references, and the rest of
the issues listed above.
From the command line (Node 18+, no npm install needed; the script lives in the LX Draft repo):
node scripts/lint-lxdoc.mjs path/to/your/doc.lx.md
It exits 0 on success and 1 on validation errors, so you can use it in scripts.
As an HTTP endpoint (for agents that have internet but not the LX Draft repo):
POST https://lxdraft.lx-cloud.com/api/validate-public
Content-Type: text/plain
<the entire .lx.md content as the request body>
Returns:
{
"valid": true,
"issues": [
{ "rule": "V003", "severity": "warning", "message": "...", "location": "..." }
]
}
valid: false means there is at least one error-severity issue. Fix all errors before delivery;
warnings are advisory.
Your output will be validated. To avoid rejection:
format: "lxd/1.0" must be presentasset:id, that asset must be in the document-assets blockformat: "lxd/1.0"## 1 Section format (number + space + name)```csv:label``` blocks); semantic data-type, if needed, is marked with a <!-- table-type: X --> sentinel above the tableasset:id (with assets block) or external URLs<!--[c1]--> etc.) unless you're using the API# Agent Writing Guide for LX Draft Documents
This guide tells AI agents how to write `.lx.md` documents that LX Draft can render and edit. Give this guide to any agent that needs to produce engineering documents for the LX Design House team.
## What is an .lx.md file?
A `.lx.md` file is a UTF-8 text file with three parts:
1. **YAML frontmatter** — metadata and document properties (between `---` markers at the top)
2. **Markdown body** — the actual content using standard Markdown plus a few extensions
3. **Optional document-assets and document-meta blocks** — for embedded images and review data (you usually don't need these)
The simplest .lx.md is just markdown wrapped in frontmatter:
```
---
format: "lxd/1.0"
title: "My Document"
revision: "v0.1"
status: "draft"
---
# My Document
This is the body. Standard Markdown works fine.
```
## The integrity hash — do NOT write it
LX Draft stores a self-excluding SHA-256 hash in `frontmatter.integrity` to
detect later tampering (it underpins signature auto-clear-on-edit). **As an
agent, never write or guess the `integrity` field — omit it entirely.** LX Draft
computes and injects the correct hash automatically when the document is saved
or edited in the app. A hash you invent would be wrong and flag the document as
modified. (Unsigned drafts don't need a hash at all; it only matters once a
human/Lexis signs the document.)
## Standalone vs Lexis (context you should know)
LX Draft is used two ways, and it affects governance (not how you write content):
- **Standalone** — the document is a plain `.lx.md` file the user opens/saves on
their own drive (or Google Drive). The user self-signs; revision history is a
table they maintain.
- **Lexis-managed** — the document is a controlled project artifact. Lexis owns
its lifecycle (releases, version history, signing). A controlled document
carries `lexis_controlled: true` in its frontmatter.
As an agent you write the same markdown either way. Do **not** set
`lexis_controlled` yourself, and do **not** try to sign documents — placing a
`{signature:...}` field is enough; the human or Lexis performs the signing.
## Required frontmatter fields
You MUST include these:
```yaml
format: "lxd/1.0" # always this exact value
title: "Document Title" # required
revision: "v0.1" # use v0.1 for first draft
status: "draft" # draft | review | approved | released | obsolete
```
## Recommended frontmatter fields
Add these whenever you have the information:
```yaml
short_title: "Short Name" # for headers / breadcrumbs
document_number: "T-XXX-001" # if there's a doc numbering scheme
date_created: 2026-03-30 # YYYY-MM-DD
classification: "internal" # public | internal | commercial-in-confidence | restricted
template: "standard" # standard | proposal | test-report | datasheet | minutes | review
project: "Project Name"
prepared_for: "Client Name"
author: "Your Name"
font: "Poppins" # default body font; use Poppins unless told otherwise
cover: true # render the LX-branded blue cover page in the PDF
```
## The cover page
LX Draft can render a branded **cover page** at the front of the PDF — a full-bleed page with a dark background, a blue title block, the document number, and a footer with the LX logo and a metadata table (project, client, author, revision, date). It's gated behind a single frontmatter flag so plain memo-style documents don't get a heavy cover they don't want:
```yaml
cover: true
```
The cover only renders in the **PDF export** (and the in-app Print Preview, which is a PDF rendered in an iframe). The editor canvas itself stays cover-less so you can edit body content without the cover taking up half the screen. If you don't set `cover:` at all, the cover is suppressed by default.
**Fields the cover surfaces.** Populate as many as you have; missing fields are skipped gracefully:
- `title` — the big bold title in the blue title block (already required for the body, used here too).
- `short_title` — used as the visible title if shorter than `title`; otherwise `title` is used.
- `document_number` — rendered immediately under the title in a monospace font (typical doc-control numbering like `T-REV-SCH-CMP` or `PSD-002`).
- `revision` — appears in the metadata table at the bottom of the cover (e.g. `v0.1`).
- `date_created` — appears in the metadata table.
- `project` — appears in the metadata table.
- `prepared_for` — appears in the metadata table (typically the client name).
- `author` — appears in the metadata table.
- `classification` — when set to `commercial-in-confidence` or `restricted`, also paints a classification banner across the cover.
**When to set `cover: true`.** Use it for formal external deliverables — client proposals, design reports, test reports, formal specifications. Skip it (or set `cover: false`) for internal memos, meeting minutes, short notes, and anything that's going to be read on-screen rather than printed.
**Templates and the cover.** If the user has selected a template (e.g. `template: "standard"` or `template: "proposal"`), check that template's own frontmatter for `cover: true`. The shipped LX templates may already enable it — in which case the cover renders automatically without you having to add `cover: true` to your document. If the template hasn't enabled it but the document should have one, override by setting `cover: true` explicitly in your document's frontmatter.
## Standard Markdown features (just use them)
These work as you'd expect from any Markdown:
- `# H1` through `###### H6` for headings
- `**bold**`, `*italic*`, `~~strikethrough~~`, `` `inline code` ``
- `- bullet list` and `1. numbered list` (nest with 2-space indent)
- `| col | col |` pipe tables (with header separator row)
- `> blockquote`
- ` ```language ` fenced code blocks
- `[link text](https://url)` for hyperlinks
- `---` for horizontal rules
## LX-specific extensions (use these for engineering docs)
### Callout boxes
Use these for tips, warnings, important notes:
```markdown
> [!NOTE]
> Informational note. Blue left border.
> [!TIP]
> Helpful tip. Green left border, "Tip:" prefix.
> [!IMPORTANT]
> Important caveat. Amber left border, "Important:" prefix.
> [!WARNING]
> Warning text. Red left border, "Warning:" prefix.
> [!STEP]
> Procedural step. Blue left border, no prefix.
```
### Tables
Use GFM pipe tables for *all* tables, whether the data is a short inline grid, a BOM, a checklist, or a long list of requirements. Pipe-table cells are fully editable in place — clicking a cell selects text normally, and the table can be resized, sorted, and rearranged by the reviewer.
```
| Reference | Part Number | Quantity | Manufacturer |
| --------- | ---------------- | -------- | ------------------ |
| U1 | STM32F405RGT6 | 1 | STMicroelectronics |
| C1 | CL21B104KBCNNNC | 10 | Samsung |
| R1 | RC0805FR-07100KL | 4 | Yageo |
```
Escape any literal `|` inside a cell as `\|`. Cells may contain inline markdown (`**bold**`, `` `code` ``, links, math) but not block content (lists, paragraphs).
#### Marking a table's semantic data-type (optional)
If a workflow connector or downstream tool needs to identify a table by what kind of data it carries (e.g. "the BOM in this doc"), place an optional `` sentinel comment on the line immediately above the table:
```
| Reference | Part Number | Quantity |
| --------- | ---------------- | -------- |
| U1 | STM32F405RGT6 | 1 |
```
Common labels: `bom`, `requirements`, `test-results`, `registers`, `checklist`. The label is free-text; pick whatever fits. The sentinel is invisible in the rendered document and is preserved through editor round-trips, so a human reader never sees it but a workflow agent can find the right table by scanning for it.
#### Legacy CSV blocks (deprecated)
Earlier versions of LX Draft supported ` ```csv:label ` fenced blocks as a separate "rich CSV table" node. That format is now **deprecated**: it renders as a read-only grid in the editor (cells can't be clicked into), and inline commas inside cells silently split rows into extra columns — both serious authoring traps. Existing documents containing `csv:` blocks still open and edit cleanly (the editor converts them to native pipe tables on load), but agents should not write new `csv:` blocks. Always use a pipe table; if data-typing is needed, use the `` sentinel above it.
Reference only — the legacy CSV block format looks like this and is kept here so agents can recognise it when reading older documents (do not write it in new documents):
````markdown
```csv:bom
reference,part_number,quantity,manufacturer
U1,STM32F405RGT6,1,STMicroelectronics
C1,CL21B104KBCNNNC,10,Samsung
R1,RC0805FR-07100KL,4,Yageo
```
````
### Equations (LaTeX)
```markdown
Inline math: $R = V / I$ where $V$ is voltage.
Block math:
$$
P_{total} = \sum_{i=1}^{n} V_i \cdot I_i
$$
```
### Footnotes and endnotes
```markdown
This statement needs a citation[^1].
This refers to an endnote[^note:pricing].
[^1]: Footnote text — typically appears at the bottom of the page.
[^note:pricing]: Endnote text — appears at the end of the document.
```
### Cross-references and bookmarks
```markdown
See {ref:sec:introduction} for background.
Refer to {ref:bookmark:thermal-section|the thermal section} for details.
```
### Document-property fields (live values from frontmatter)
You can embed a *live* reference to a frontmatter field in the body. It renders
the current value of that field (and updates if the frontmatter changes), and
resolves to the value in PDF/DOCX export. Use the `{field:NAME}` token:
```markdown
Document number: {field:document_number}
Revision {field:revision} — prepared for {field:prepared_for}.
```
Valid field names: `title`, `short_title`, `document_number`, `revision`,
`author`, `status`, `classification`, `date_created`, `project`, `prepared_for`.
In the editor, a human inserts these via the **Insert Field** toolbar button; as
an agent, just write the `{field:NAME}` token in the markdown — it round-trips
and resolves on export.
### Signature fields
A signature field renders the signer's name (in a cursive font) once the
document is signed, or a muted "Your signature here" placeholder when unsigned:
```markdown
Signed: {signature:author}
```
Signing itself is a human/Lexis action (see "Standalone vs Lexis" below) — as an
agent you place the `{signature:...}` token where the signature should appear;
you do not sign the document.
### Page breaks
If you need a hard page break in the printed output:
```markdown
```
### Multi-column sections
```markdown
Content here flows into two columns.
```
### Text boxes (bordered content)
```markdown
Content inside a bordered box.
```
### Images
For external images (URLs), use standard Markdown:
```markdown

```
For embedded images, use the asset reference syntax:
```markdown

```
Then add the image to a `document-assets` block at the end of the file (see "Embedded images" below).
**Size, alignment and crop** are persisted as an HTML comment immediately after
the image. You normally don't need to write these (the human adjusts images by
dragging in the editor), but they round-trip and the exporter honours them:
```markdown

```
- `width` / `height` — display size in px.
- `align` — `left` | `center` | `right` | `inline`. `left`/`right` float the
image so body text wraps around it; `center` is a centered block.
- `crop` — `top,right,bottom,left` inset in px (the visible region is the image
minus these insets). Omit if not cropped.
### Table of contents
Insert a self-updating TOC anywhere:
```markdown
```
The editor renders this as an actual TOC. In source form it stays as the directive.
## Media attachments (preferred: deliver a bundle, don't base64 yourself)
**Do not base64-encode media inside the .lx.md.** LLM output is unreliable for large binary blobs — you will silently truncate, corrupt, or hit token limits. Instead, deliver two things:
1. A clean **`.lx.md` (or `.md`) file** with `asset:` references in the body.
2. A **`.zip` archive** containing the actual media files, named to match those references.
LX Draft's import dialog has a "Document + Archive" tab that does the embedding for you — it reads the archive, matches each ref to a file, base64-encodes server/browser-side, and produces a self-contained .lx.md.
### Reference syntax in the markdown
**Strongly preferred — use bare `asset:` references with no folder prefix:**
```markdown


```
- `` must match a filename **stem** somewhere in the bundle folder (e.g. `asset:photo-013435032` matches `photo-013435032.jpg`).
- The folder name is **irrelevant** — LX Draft strips the top-level folder when matching. Don't put the folder name in the reference.
- The id should be a slug: letters, digits, hyphens. No spaces, no slashes.
- **Don't write `` or ``.** If you change the folder name later, every reference breaks. Use `` and let LX Draft handle the lookup.
Relative paths (`./diagrams/field-plot.png`) are accepted as a fallback — LX Draft matches them by exact path then by basename — but they couple the document to the directory layout. Avoid them in agent output.
Absolute filesystem paths (`C:\...`, `/home/...`) can never resolve in a browser. Don't use them.
### Folder structure
The folder can be flat or have subfolders — both work, because LX Draft matches by filename stem. Filename stems must be unique within the bundle when you use `asset:` references.
```
my-report/ ← name doesn't matter; user picks this folder
├── photo-013435032.jpg ← matches asset:photo-013435032
├── photo-013449261.jpg ← matches asset:photo-013449261
└── pcb-rev-b.png ← matches asset:pcb-rev-b
```
If you have many media files of different types, put them in subfolders for your own organisation — the matcher still works:
```
my-report/
├── photos/
│ ├── photo-013435032.jpg ← still matches asset:photo-013435032
│ └── photo-013449261.jpg
└── diagrams/
└── pcb-rev-b.png ← still matches asset:pcb-rev-b
```
The `asset:` reference does **not** include the subfolder.
### Supported media types
Anything LX Draft can render or link: `png`, `jpg`/`jpeg`, `gif`, `webp`, `svg`, `bmp`, `tiff`, `pdf`, `mp4`, `webm`, `mp3`, `wav`, `ogg`. The MIME type is inferred from the extension.
### Inline SVG — self-contained diagrams, no asset bundle
Like Mermaid, a ` ```svg ` fenced code block renders live in the editor and in the PDF export — the SVG source sits directly in the document body as plain text. This is the preferred way to hand-author a diagram: no base64, no `document-assets` block, no separate media bundle to deliver alongside the `.lx.md`. Use it for schematic sketches, custom layouts, or any vector artwork that doesn't fit Mermaid's flowchart/sequence grammar:
````markdown
```svg
```
````
The content must be a valid standalone `` document (same explicit `width`/`height` rule as below). It is run through a strict sanitizer on render, so **do not include** `