resilient.sile

An overview of Djot extensions and interpretations in re·sil·ient

Going on an adventure with re·sil·ient #2

Authored 02/12/2025 (aligned with re·sil·ient v3.x), revised 13/12/2025 (some insights on future plans), revised 04/03/2026 (more bibliography extensions), revised 07/03/2026 (task list extensions, multiple captions).

In our series of “Going on an Adventure”, we’ll explore below the Djot syntax extensions and specific interpretations of Djot constructs implemented in re·sil·ient, our collection of SILE add-on modules.

The Markdown and Djot to PDF with SILE — User Guide document describes how to use the Djot lightweight markup as a native source format for re·sil·ient and the SILE typesetting system. It does cover syntax extensions and specific interpretations of Djot constructs in re·sil·ient. However,

This document focuses specifically on Djot syntax extensions and interpretations in re·sil·ient,, in a more focused way.

The target audience is therefore more technical, and the document is oriented towards people already familiar with “standard” Djot (at the time of writing; Djot being a work in progress). By “standard”, we mean version 0.2.x (as supported by the djot.lua reference implementation). The Typescript reference implementation (djot.js) is (again at the time of writing) at version 0.3.x, but this has little impact on the topics discussed here.

We are well aware that extensions beyond any “standard” are always a delicate matter, as they may lead to fragmentation of the ecosystem, with different implementations supporting different sets of extensions. This is what happened with Markdown, and its many “flavors” over the years.

Nevertheless, these extensions and interpretations are the result of practical needs encountered while developing re·sil·ient and its book class, over the last few years, composing a few documents and publishing books with it, and trying to solve actual typesetting problems while keeping a “lightweight” markup approach. Therefore, they are shared for documentation purposes, but also to help other Djot enthusiasts interested in similar features, as challenges faced by re·sil·ient and how they were addressed. We hope they may be useful to others, and possibly inspire future discussions.

Syntax extensions

This section describes the Djot syntax extensions implemented in re·sil·ient.

Attribute syntax extensions

Conditionals

The Djot attribute syntax is extended with conditionals on symbols.

For the reminder, in standard Djot, a symbol is entered in the text flow using the syntax :symbol:.

Initially, it was intended for emojis, but the specification now leaves it open to other uses. We will have more to say about that later, for now let’s just assume that some symbols may be available in your document context…

Conditionals allow to render content depending on whether a symbol is defined or not.

Conditions work on block and inline elements alike. This author, however, ended up using them mostly on block elements.

In re·sil·ient, they only apply to user-defined symbols (defined as pseudo-footnotes) and contextual metadata symbols (set by the calling context).

Before using a symbol in the text flow (:symbol:), one can thus test for its existence. Compared to a more general templating logic (that would take place outside the Djot source), it allows to express conditional rendering directly in the Djot document, respecting the structure of block and inline elements.

Here is a practical example, extracted from the default template for “end-papers” in a book (using the book class in re·sil·ient).

{custom-style="center"}
::::
{?title}
:::
_:title:_
:::

{?isbn}
:::
ISBN: :isbn:

:isbn:{custom-style=bookmatter-ean13}
:::
::::

In this example, a custom style is applied to center the content of a block. Then:

When both symbols are defined, one would get the following type of output.

Conditional attributes example

While it only offers a very simple and basic templating capability, the adavantages, of course, are that the same Djot template file will work for documents with or without titles and ISBNs, and that the Djot structure is entirely preserved.

Here is another example, extracted from the default template for the verso of the title page in a book. Depending on whether the pubdate-year and publisher symbols are defined, different copyright lines will be rendered.

{?pubdate-year ?publisher}
:::
© :pubdate-year:, :publisher:.
:::
{?pubdate-year !publisher}
:::
© :pubdate-year:.
:::
{!pubdate-year ?publisher}
:::
© :publisher:.
:::

It is totally acceptable to have other attributes alongside conditionals, although this author recommends to keep things simple for readability.

Index entries

The Djot attribute syntax is extended with a “shortcut” syntax for marking index entries.

The syntax is a compact alternative to using standard attributes for that purpose.

Multiple indexes can be specified by separating them with spaces, as any other Djot attribute — so any text element can be marked as belonging to several indexes at once, with possibly different replacements for each index.

Theses shortcuts can currently be used on any inline or block element. In re·sil·ient, however, they are only processed when used on inline elements, and ignored on block elements.

In re·sil·ient, the shorter compact syntax is equivalent to the following “standard” attribute syntax:

In other words, the shortcut syntax is just a more concise way to express the same information. The rationale is that annotating text elements is a tedious task, and the shortcut compact syntax makes it a bit easier and semantically clearer.

Consider for instance the following example using the shortcut syntax:

[John Doe]{:main="Doe, John"} and Aristote{:main}
A fox{:animals} or an ox{:animals=cow}

It is equivalent to the following using the standard attribute syntax:

[John Doe]{index=main indexed-main="Doe, John"} and Aristote{index=main}
A fox{index=animals} or an ox{index=animals indexed-animals=cow}

Multiple indexes can be listed by separating them with spaces, as other Djot attributes.

[Simon's Cat]{:main :animals="cat" :genus=Felis}
[Nils Olav III]{:main :animals="penguin" :genus=Aptenodytes}

Or the equivalent standard attribute syntax:

[Simon's Cat]{index="main animals genus" indexed-animals="cat" indexed-genus=Felis}
[Nils Olav III]{index="main animals genus" indexed-animals="penguin" indexed-genus=Aptenodytes}

It is possible to have other attributes alongside index markup. At this point, the order in which attributes are applied, and whether they impact the indexed terms (and not just the rendered element in the text flow) are left unspecified.

How the index entries are collected and rendered is outside the scope of this specification. In re·sil·ient, there are ways to generate indexes from the collected entries, and to customize the rendering of the indexes, but these are implementation details not covered here. For details, refer to The re·sil·ient collection of classes & packages for SILE — User Guide document.

Inline element syntax extensions

Citations

The Djot inline syntax is extended with a citation syntax.

It allows to reference bibliographic entries in the text flow, by their unique keys, with an optional locator.

The supported syntax is a simplified subset of the Pandoc citation syntax and follows one of the proposals made on te Djot discussion forum. The rationale for using a naive simplified citation syntax derives from the fact that CSL 1.0.2 does not really address in a clear way prefixes and additional suffixes for citations, not to say multiple locators per citation. The supported syntax in re·sil·ient is therefore limited to basic citations with optional locators, as described below.

A standard citation element starts with [@ and ends with ]. In that inline element, multiple citations can be grouped together, separated by semicolons. Each citation can optionally include a locator after the key, separated by a comma (or spaces). The locator consists of a name and a value, separated by spaces. In re·sil·ient, locators must match CSL locator types, or some usual abbreviations (with or without trailing dot) for convenience.

How the bibliography references are provided to the document, and how the citations are rendered, is outside the scope of this specification. In re·sil·ient, there are ways to declare bibliography files (e.g. in BibLaTeX-like format), and rendering rules (i.e. according to a given Citation Style Language CSL style), but these are implementation details not covered here. For details, refer to The re·sil·ient collection of classes & packages for SILE — User Guide.

Citation syntax

Here are some examples of valid citation syntax, with the rendered output in Chicago author-date style.

Citation syntax Rendered
[@doe2020] A simple citation (Doe 2020).
[@doe2020, chapter 5] A citation with a locator (Doe 2020, chap. 5).
[@doe2020; @smith2019] Multiple citations (Doe 2020; Smith 2019).

But a few other features are available, via modifiers before the @ sign.

Description Example Rendered output (Chicago author-date style)
No-cite [!@doe2020] Bibliography only
Author suppression [-@doe2020] (2020)
Integral citation [+@doe2020] argued… Doe (2020) argued…

The “no-cite” syntax is useful to include works in the bibliography as if they were cited, but without actually rendering a citation in the text flow. Obviously, content around the citation element is rendered as usual, so be aware that spaces etc. may need to be adjusted accordingly.

The “author suppression” syntax is useful to suppress the author part of a citation, which is also a common need, especially when the author name is already mentioned in the text, one way or another. Obviously, with styles with a different citation format (e.g. numeric), author suppression may not make much sense, but the syntax is still accepted and processed, even if it doesn’t have any visible effect in that case.

The “integral citation” (a.k.a. “narrative”) syntax is useful to integrate the citation, but let the engine format the author name, in a sentence flow. For instance “[+@doe2020] argues that...” may render as “Doe (2020) argues that…” in Chicago author-date style, or as “Doe [1] argues that…” in a numeric style. Wait a minute, you may say, how is the name supposed to be formatted in the sentence flow, in a consistent form with how such things should appear there, independently from the citation style being used?

After all, some styles may use numeric citations, and one cannot trust either the bibliography format, which may capitalize names or do other things to them. One wouldn’t want to have “DOE, John (2020) argues that…” in the text, just because the bibliography entry is in uppercase, right? Moreover, in bibliographies, some name particles can be “demoted” (for sort or display), multiple authors can be collapsed into “et al.”, substitutions might be used… and so on. So the name formatting from either the bibliography or the in-text citation is not convenient for use in a sentence, really!

In re·sil·ient, the formatting of names in integral citations is handled via a dedicated CSL-like style subset. It can be customized separately, so the user can define how the author name is supposed to be formatted in the sentence flow, and how to handle multiple authors, name particles, etc. without depending on the main bibliography style, while at the same time benefiting from the CSL localization and other features. So it is for instance possible to consistently obtain “Jan de Vries (1961)…” or “Jan de Vries [1]…” in the text (here, with the first name, particle and last name all appearing in the text flow in a regular order). But for that reason too (at least for now, to keep things simple) in re·sil·ient, the integral citation syntax is only supported with one citation item at a time, not mixed with any other citation forms in a grouped citation element.

In-text vs. note citations

In some citation styles, references appear in the text (in numeric or author-date style), while in others they appear as footnotes. The syntax is the same for both, but how they are rendered depends on the chosen style.

For in-text citation styles, you should place the citation where you want it to appear within the sentence.

In-text citation Rendered
Some text [@doe2020]. Some text (Doe 2020).
[+@doe2020] argues that... Doe (2020) argues that…

For note-based styles, the engine will automatically wrap citations in footnotes when required. In the main text, you should therefore place the citation where a footnote call is expected. In English, footnotes are typically placed at the end of a clause, after the punctuation. In other languages, authors should follow the appropriate typographic conventions.

Note citation in main text Rendered
Some text.[@doe2020] Some text.ⁿ
[+@doe2020] argues that... Doeⁿ argues that…

However, if you place a citation inside a footnote, it will be rendered in-text, since nested footnotes are not allowed.

Note citation in footnote Rendered
[@doe2020]. Doe, J. “An interesting article,” 2020.
[+@doe2020] argues that... Doe (“An interesting article,” 2020) argues that…

Block element syntax extensions

Generalization of captions

The Djot syntax is extended to allow legends on any block element, with the same syntax as for tables.

For the reminder, in standard Djot, captions are only supported on tables, and ignored on other block elements.

| Header 1 | Header 2 |
|:--------:|:--------:|
| Cell 1   | Cell 2   |
^ This is a standard table caption.

In re·sil·ient, captions on other blocks are interpreted in several ways.

On a block quote, the block is rendered as an epigraph (in a broad sense), with the caption content used as its “source”.

> The Library is a sphere whose exact centre is any one of its
> hexagons and whose circumference is inaccessible.
^ Jorge Luis Borges{.smallcaps}, "The Library of Babel"

Epigraph example

On a code block, the block is considered as a listing with a caption.

```lua
print("Hello, world!")
```
^ A simple Lua program.

On a div block, the block is considered as a figure with a caption.

:::
Some complex figure or diagram here.
:::
^ A figure caption.

This is especially interesting when the figure contains several elements, or rendered code blocks (such as diagrams generated from code blocks, e.g. with Graphviz or other tools). For a single image, the “implicit figure” interpretation discussed later might be sufficient (see below).

On other block elements, the caption is currently ignored.

Note that tables, figures and listings are sectioning elements in re·sil·ient. The captions are usually rendered below these elements, and depending on the style being used, they may be numbered automatically, and appear in lists of tables, figures or listings, respectively.

As div blocks can be nested, it is theoretically possible to have nested sub-figures with their own captions. This specification does not forbid it. The re·sil·ient book class however does not currently support this feature, but it could be implemented in the future. It’s a limitation of the book class, not of the proposed Djot syntax extension itself.

Secondary captions (legends)

In standard Djot, there can only be one caption line (on a table). More precisely, the Djot parser accepts multiple caption lines, but only the last one is used, and the others are ignored.

In re·sil·ient, multiple caption lines are supported, and interpreted as a main caption line followed by one or more “secondary” caption lines, assembled as paragraphs in a “legend”.

This feature applies to tables, figures and listings.

Such “long captions” are not uncommon in books, and often obey different rules than the main caption line. As noted, the latter may be numbered automatically, and appear in lists of tables, figures or listings, while the legend is just additional information displayed below the main caption line, possibly with a distinct style.

:::
_Some complex figure or diagram here._
:::
^ Some caption.

^ We can have multiple caption lines, which are then considered as a legend.

^ Each extra caption line is rendered as a separate paragraph in the legend.

Caption and legend example

Interactive forms and radio buttons

Standard Djot supports GFM-style task lists, with checkboxes:

- [ ] An unchecked task
- [x] A checked task

In re·sil·ient, the syntax for task lists is extended to support radio buttons.

- ( ) A non-selected option
- (x) A selected option

By default, these are rendered using appropriate character glyphs (☐, ☑, ○, ◉) in the text flow. Whether these look good or not depends on the current font being used.

Moreover, if a .form class is applied to the list, these elements are rendered as actual interactive form elements in the output PDF. A “readonly” boolean attribute is also supported, to make the form non-interactive, while still rendering the checkboxes and radio buttons as form elements, with a proper appearancce.

{.form readonly=true|false}
- ( ) A non-selected radio button
- (x) A selected radio button

Obviously, for radio buttons, only one list item at most should be selected at a time.

Interactive forms

For the mere record, in re·sil·ient, this condition is currently checked at the point of rendering, and only enforced when radios are rendered as form elements; but this is just a practical design choice. Finally, the .form class also be applied on span elements (to render other form elements, such as text fields or choice menus), but this is not a syntax extension of Djot per se, and is therefore not covered here.

Interpretations beyond standard Djot

This section describes specific interpretations of Djot constructs in re·sil·ient. These are not syntax extensions per se, but rather specific ways to interpret standard Djot constructs.

Implicit figures

For the reminder, in standard Djot, an image is encoded as follows:

![This man is Gutenberg.](gutenberg.jpg){width="3cm"}

In re·sil·ient, by default, an image with a nonempty caption (as above), occurring alone by itself in a paragraph, is interpreted as a figure with a caption. Otherwise, when used as an inline element surrounded by other inline content, the caption is ignored.

Implicit figure example

Pandoc users will find this behavior similar to Pandoc’s “implicit figures” option.

Above, we mentioned that div blocks with captions are also interpreted as figures, as an extension of the standard Djot syntax. So it implies, in theory, that both the following syntaxes are more or less equivalent for creating a figure with a caption.

![A figure caption](figure.png)

And:

:::
![](figure.png)
:::
^ A figure caption.

What we mean by “more or less equivalent” is that:

As mentioned earlier, figures are sectioning elements in re·sil·ient, so the captions may be numbered automatically, and appear in lists of figures, depending on the style being used.

This specification does not try to clarify how captions on images are handled for images on their own paragraph, but in a captioned div block. It’s left unspecified here, but this author will note that the “implicit figure” interpretation and the actual syntax for images, being reminiscent of Markdown and Pandoc’s implicit figures, might however not be perfectly aligned with the more general Djot philosophy. While Djot improves on Markdown in several ways (incl. generalized attributes on block and inline elements), it keeps some Markdown-isms that may not be fully consistent with the rest of the specification (like captions on tables being done in one way, and in another way for images if used as implicit figures, and not offered on other block elements in standard Djot).

In standard Djot, an empty internal link syntax, such as [](#some-id), is not forbidden, and may even generate something in the rendered output… but without text, it’s not very useful!

In re·sil·ient, empty internal links are interpreted as cross-references to the target element with the specified identifier, and replaced by the closest applicable numbering of that element.

For instance, if the target element is a section heading, the cross-reference will be replaced by the section number; if the target element is a figure, the cross-reference will be replaced by the figure number; if the target element is in a footnote, the cross-reference will be replaced by the footnote number; etc.

Additional class attributes are accepted on the empty link, to tune that behavior, e.g. [](#some-id){.page} is resolved to the page number where the target element appears, rather than its containing number.

Standard Djot, as well as Markdown, do not provide any syntax for cross-references as found in print books (e.g. “see section 3.2 on page 45”), so this ad-hoc interpretation fills a practical need for authors, without introducing new syntax.

Symbols as a generic leaf-extension mechanism

As noted earlier, in standard Djot, symbols are entered in the text flow using the syntax :symbol: but their use is not further specified.

In re·sil·ient, symbols are used as a generic leaf-extension mechanism. They come in different flavors:

Some precedence rules apply here: user-defined > metadata-originated > programmatically-registered > predefined.

Predefined symbols

The res·sil·ient implementation comes with a set of predefined symbols: :U+xxxx: is interpreted as a Unicode character, where xxxx is a hexadecimal value in upper case. For instance, :U+2122: gives the trademark symbol (™).

It’s a “convenience” feature, since users can as well enter Unicode characters directly in the source text, but it may be useful in some contexts, esp. for characters not easily typable on a keyboard, or not easily available on your system (and/or text editor).

Programmatically-registered symbols

Programmatically registering symbols can be declared via a Lua API provided by the SILE component implementing Djot support.

The re·sil·ient book class, typically, registers a set of symbols, significant for book authoring.

Each of these symbols must stand alone in its own paragraph, and is rejected with an error if used inline with other content. They all accept optional attributes to customize their rendering, but most of these are specific to the underlying implementation and its capabilities, and not covered here (e.g. the depth of a table of contents, and other settings of that nature).

Well, :_INDEX_: at least may be presented, as it doesn’t depend as much on the underlying implementation as the other symbols do.

By default, it will insert the “main” index. When using multiple indexes, you can specify which index to insert, either with a “standard” attribute or the same compact syntax as for marking index entries (see above).

For instance:

Note that the attributes are declared on the same line, i.e. as “inline” attributes in a way. Block attributes before these symbols apply to the containing implicit block.

Other rules may apply (such as the bibliography of cited works being cleared after its insertion, so the subsequent content starts afresh), but this document focussed on the syntax aspects, not the implementation details.

N.B. For users familiar with the (La)TeX world, please note that in re·sil·ient, these constructs do not insert any type of heading or title. If you want a heading line for your table of contents (etc.), just add it manually using the appropriate heading level or styled element in your Djot source.

Metadata-originated symbols

The re·sil·ient implementation allows some symbols to be set by the calling context, allowing to inject contextual metadata in the text flow.

For instance, the :title: symbol may be set to the document title, the :author: symbol to the document author, etc.

These symbols can then be used in the text flow, without having to hardcode these values in the Djot source.

How these metadata-originated symbols are set is outside the scope of this specification. Eventually some metadata declaration syntax might be added to Djot, but the topic is a matter of debate, and not addressed here. In the case of re·sil·ient, the metadata are usually defined in a “master document” outside the Djot source(s).

User-defined symbols & variable substitutions

Finally, re·sil·ient allows user-defined symbols, defined as follows in the source document.

[^:symbol:]: Any content, block or inline.

It’s not really a syntax extension, since it uses standard Djot footnote syntax, but repurposes it for defining symbols when the above syntax is used.

When the symbol is used in the text flow (:symbol:), the associated content is rendered in place, with appropriate rendering (or error handling) depending on whether the substitution content is block or inline.

One can regard this way to define custom symbols as “pseudo-footnotes” as some sort of hack, or as a clever reuse of existing syntax with an additional level of namespacing.

This specification does not even forbid the use of the “pseudo-footnote” syntax for actual footnotes (that is, called from the text flow using the standard Djot footnote syntax, as in ... some content[^:footnote:] ...), though whether it’s a good idea or not is another matter.

Here is an example of defining and using a user-defined symbol.

[^:pumpernickel:]: Herbert J.\ G. _"Froggie"_ Pumpernickel{.smallcaps}

Then one can use the :pumpernickel: symbol in the text flow, and it will be replaced by the defined content. For cumbersome but often repeated content, it can be a real time-saver, helping to ensure consistency.

Since such user-defined symbols can contain arbitrary Djot content, they can even refer to other symbols. Thus, it adds some sort of templating with recursive variable substitution to Djot, which may be useful in some contexts (though one should be careful to avoid infinite recursion).

Additional clarifications & specificities

The elements described in this section are not syntax extensions, and not really specific interpretations of the standard either, but rather clarifications and generalizations of existing Djot constructs in re·sil·ient.

Knowning these points can be useful when round-tripping documents between different formats (e.g. betwween Djot and Markdown), or exchanging documents between different Djot implementations.

Styling

Styling equivalences

In re·sil·ient, some Djot inline constructs have strictly equivalent ways to be expressed, with various degrees of syntactic sugar.

Djot syntax Description Equivalent attribute syntax in re·sil·ient Equivalent interpretation in re·sil·ient
{+text+} Insertion [text]{.inserted} [text]{custom-style="md-insertion"}
{-text-} Deletion [text]{.deleted} [text]{custom-style="md-deletion"}
{=text=} Highlight [text]{.mark} [text]{custom-style="md-mark"}
N.A. Underline [text]{.underline} [text]{custom-style="md-underline"}
N.A. Strikethrough [text]{.strike} [text]{custom-style="md-strikethrough"}

Semantically, insertions and deletions are not necessarily the same as underlines and strikethroughs. Depending on the context (e.g. academic editing, critical apparatus, etc.), they may be rendered quite differently.

In res·sil·ient, moreover, all these constructs eventually rely on styles, which come with default settings but can be defined and customized at will by the user (in terms of colors, line styles, filling patterns, etc.).

Small capitals

The re·sil·ient implementation supports a few other “pseudo-classes” which do not have to be documented here in full detail. But one at least is worth mentioning here for its practical usefulness.

Small caps are often used in book authoring. Using a custom-style construct is possible, and the re·sil·ient styling paradigm allows to define such styles, but having a dedicated syntax makes it easier and clearer to use: [text]{.smallcaps}.

One could expect Djot to eventually specify a shortcut syntax for small caps… But as of now, no consensus has emerged on what that syntax should be (and it’s not easy to think of anything that would remain intuitive).

Language attribute & smart quotes

In re·sil·ient, the lang attribute on inline and block elements is interpreted as setting the language for that element and its content.

The “smart” quotes in Djot are interpreted according to the specified language. In other words, straight quote marks are converted to language-appropriate opening and closing quotation marks.

For most languages, paired " and ' are interpreted as mapping to the primary and secondary quotations marks, respectively.

For instance, take "..." and '...':

Note that some languages use them the other way round for primary and secondary quotation marks. UK English, Scottish Gaelic etc. use ‘…’ and “…” as primary and secondary quotation marks, respectively. In that case, the user’s input is respected, so that "..." and '...' still become and “…” and ‘…’. In other words, paired " and ' are replaced by the primary and secondary quotation marks for most languages, or by the secondary and primary quotation marks for languages where that is the convention.

Also note that some languages (as French and Russian in the examples above) use double marks for secondary quotations. In other words, the smart substitution of ' is not necessarily a single quotation mark.

Finally, note that other language-specific typographic rules are applied by the underlying typesetting engine, SILE, as appropriate — but that’s beyond the point discussed here. How the global default document language is set is outside the scope of this document. (In re·sil·ient, it’s usually set in the master document outside the Djot source.)

Future extensions and proposals

These are being considered for future versions of re·sil·ient, but not yet implemented at the time of writing.

They are mentioned here for documentation purposes, without commitment to follow through with these preliminary proposals.

Line-obeying blocks & poetry

When dealing with poetry, this author had to used transcluded Markdown (which re·sil·ient also supports via annotated code blocks) to get proper line breaks, stanzas, etc. — then relying on Markdown’s extended “line block” syntax.

A few other approaches were considered.

It is felt that Djot could benefit from a dedicated block-level syntax for switching to “line-obeying” mode, for poetry and other similar constructs.

A strategy could be to introduce a specific block-level marker, say ~~| to start and end a line-obeying block (and either the same closing marker, or the symmetrical |~~, or plain ~~).

This syntax might be generalized to support other types line/space-preserving blocks:

Examples:

~~|
First verse first stanza.
Second line first stanza.

First line stanza.[^note]
Last line second stanza.
~~~
~~/
Typesetter line input
  Preserving    spaces
    And line breaks
  But still processing *markup*.
~~~

Document-level metadata declaration syntax

Standard Djot does not provide any syntax for declaring document-level metadata. The topic has been much debated, without any consensus emerging so far.

In re·sil·ient, for complex book projects, document-level metadata are usually defined in a “master document” outside the Djot source.

However, having a way to declare such metadata directly in the Djot source could be useful in some contexts, e.g. for a one-file self-contained document.

The general idea is to allow special blocks at the start of the document:

+++ FORMAT IDENTIFIER
metadata declarations
(in some format, and respecting some identified schema)
+++

In re·sil·ient, it could accept a subset of the “master document” format (more or less everything but the content inclusion directives). Here is an example (not exhaustive) of what such a metadata block could look like.

+++ application/yaml urn:example:omikhleia:resilient:document:v1
metadata:
  title: Djot extensions and interpretations in re·sil·ient
  subtitle: Going on an adventure with re·sil·ient #2
  keywords:
    - Djot
    - Markup
  publisher: Omikhleia
  pubdate: 2025-12-02
  url: https://github.com/Omikhleia/resilient.sile
font:
  family: Libertinus Serif
  size: 10pt
language: en-US
bibliography:
  style: chicago-author-date
  names: long
  files:
    - typography.bib
sile:
  options:
    papersize: a5
    layout: isophi
    resolution: 300
  settings:
    textsubsuper.fake: true
    typesetter.italicCorrection: true
+++

The content section of a “master document” in re·sil·ient lists the source files (Djot, Markdown, SIL, XML, etc.) to be included in the document, in a hierarchical way. While not applicable here for a standalone Djot self-contained document, some of its features may have to be considered:

The other way round, to allow the smooth inclusion of standalone documents with their embedded metadata in a larger master document, the specification would also have to clarify how metadata declared in the standalone document interact with elements declared in the master document. Some (e.g. fonts, bibliobraphy style, etc.) may be overridden by the master document. Others (e.g. bibliography files) may have to be merged. Some (e.g. title, author, etc.) may have to be scoped to the included document only (for metadata-originated symbols), and overridden by the master document in the global context. Finally, a few (e.g. language) may imply the implicit addition of div blocks with appropriate attributes around the content of the included document.