Skip to content

Quillmark Format

Quillmark is the document format TongueToQuill uses. It is CommonMark plus a structured metadata system — readable as plain text, parseable as structured data, editable by humans, LLMs, and tooling.

This page is the reference for the format itself. For producing actual documents, start at Anatomy of a Memorandum or Document Types.

Document structure

A document is a sequence of blocks. Each block has:

  • A card-yaml header — structured frontmatter.
  • A prose body — the markdown content beneath the header, up to the next card-yaml header or end of file.

Minimal document:

~~~
$quill: usaf_memo
memo_for:
  - 20 FW/CC
subject: Example
signature_block:
  - JOHN A. SMITH, Lt Col, USAF
letterhead_caption:
  - HEADQUARTERS 20TH FIGHTER WING
~~~

The body goes here. The renderer auto-numbers top-level paragraphs.

card-yaml blocks

A card block opens and closes with ~~~ — exactly three tildes, no info string — both at column zero. The ~~~card-yaml opener is also accepted; bare ~~~ is the canonical form. ~~~yaml and ```card-yaml do not open a card block. The content between the fences is YAML.

~~~
key: value
list:
  - one
  - two
~~~

Blank line above the opener

A blank line is required immediately above every ~~~ opener, unless the opener is line 1. Without the blank line, the parser treats the fence as an ordinary code block — the document looks superficially valid but silently loses its structure. This is the most common authoring mistake.

Reserved $ keys

The engine accepts a closed set of $-prefixed keys. Anything else with a leading $ is a parse error.

Key Where it appears Purpose
$quill Root block only (required) Binds the document to a Quill and version.
$kind Any block Identifies the block type. The root block's kind is main (implicit by position; explicit $kind: main is also accepted, but non-root cards must not use main). Indorsement cards use $kind: indorsement.

$ext and $seed are also accepted but exist for tooling round-trips, not for authors. Don't write them in documents you author by hand — leave them to the editor and the engine.

All other keys are user data, in lowercase snake_case. Their interpretation depends on the Quill's schema.

YAML values

The payload is YAML, and a few of its rules bite often enough to name:

  • Numbers and booleans are unquoted. font_size: 12, not font_size: "12" — quoting makes a string, and validation rejects it.
  • Quote a plain value that starts with * or &, or that contains a colon followed by a space. Both are YAML syntax. subject: "Range 7: Closure" and tag_line: '**Aim High**' need the quotes.
  • Multi-line values use a |- block, not a quoted string spanning lines.
  • A blank or null value means "not set". field:, field: null, and field: ~ all fall back to the field's default, exactly as omitting the line would.

Placeholders (!must_fill)

get_specs returns a blueprint whose unfilled fields carry the YAML tag !must_fill:

subject: !must_fill Subject of the Memorandum

Replace the value and delete the tag. A leftover !must_fill doesn't block the render — it comes back as a warning until you replace it.

Version selectors

The $quill value is <name>@<version>:

Form Meaning
usaf_memo@0.2.0 Exact version
usaf_memo@0.2 Latest 0.2.x
usaf_memo@0 Latest 0.x.x
usaf_memo@latest Latest overall
usaf_memo Latest overall

The name must match [a-z_][a-z0-9_]*.

Pin to a minor or exact version when you need bit-stable output (e.g., for archival). Use the unversioned form for "always use the current format."

Cards

A document can contain multiple cards. Each card is a separate ~~~ block plus its prose body. The root card defines $quill; later cards inherit it.

Cards are the mechanism for indorsements, attachments-as-sections, and any multi-part document structure the Quill supports.

~~~
$quill: usaf_memo
subject: Pass Request
~~~

Main body.

~~~
$kind: indorsement
format: informal
signature_block:
  - ~~~

Indorsement body.

The card sequence is significant — the renderer stacks cards in the order they appear in the source.

Supported markdown

CommonMark 0.31.2 plus three additions:

  • GFM strikethrough (~~text~~)
  • GFM pipe tables, including alignment (:---, :---:, ---:)
  • <u>text</u> for underline (the only allowed HTML tag besides comments)
Feature Syntax
Bold **text**
Italic *text*
Underline <u>text</u>
Strikethrough ~~text~~
Headings # Heading (ATX-style only)
Ordered list 1. item
Unordered list - item
Pipe tables with alignment \| col \|, \| :--- \|, \| :---: \|, \| ---: \|
Links [text](url)
Inline code `code`
Code blocks ```
HTML comments <!-- comment -->

Not rendered: images, footnotes, math ($...$, $$...$$), task lists, definition lists, raw HTML other than <u>. These parse without error but produce no output, so don't rely on them.

Code blocks in prose use backticks. A column-zero ~~~ in a prose body is read as card metadata, not as a code fence, so a literal fenced block has to open with ```.

How memo body content is numbered

The usaf_memo Quill auto-numbers top-level paragraphs as 1., 2., 3. per AFH 33-337. Do not write the numbers yourself. Nested - item bullets are auto-lettered as a., b., c.; deeper nesting continues to (1), (a), then underlined number. Each Quill controls its own numbering scheme — check the Quill blueprint (via get_specs) for non-memo formats.

Validation

The Quillmark engine validates frontmatter against the Quill's schema before composing the output:

  • Missing required fields → render error with a path into the frontmatter.
  • Wrong type (string where a list is expected, etc.) → render error with the path.
  • Unknown keys → typically a warning, not an error. Unknown keys are ignored.

The render either succeeds (you get a valid PDF) or fails with a diagnostic. There is no path where invalid input silently produces a malformed document.

For the deeper format spec and engine internals, see quillmark.readthedocs.io.