Feature list¶
The complete, numbered list of what the format supports — one row per feature,
each with a stable F<n> that the rest of the project can cite. This card is
the index; it is deliberately not the normative text. Where a construct has
a specification, the row points at it, because a feature list that restates its
own spec drifts from it by the second edit.
Two things live here and nowhere else: the numbering, and the status of every feature including the ones that do not exist yet. See hyper-markdown for what the format is for, and md-hmd-interop for its relation to plain markdown.
How to read the table¶
One flat table, six columns, every feature the format has or has considered — built or not, accepted or rejected.
| Column | Meaning |
|---|---|
| # | Stable identifier. Never reused, never renumbered. |
| Feature | The name to call it in prose. |
| Written | What an author types. |
| Comes from or inspired by | Where the idea is sourced from. |
| Implemented by | What makes it work — the format itself, an extension, a binary — or — if unbuilt. |
| Status | Where it stands, from the vocabulary below. |
Status vocabulary — shipped works today and is gated by a test ·
planned specified or agreed, not built · nice to have wanted, unspecified,
nobody has committed · deferred explicitly postponed to a later spec ·
rejected decided against, recorded so it is not relitigated.
| # | Feature | Written | Comes from or inspired by | Implemented by | Status |
|---|---|---|---|---|---|
| F1 | Wikilink | [[page]] |
MediaWiki / WikiWikiWeb | the format, HMD-0001 §2 / §5 | shipped |
| F2 | Aliased wikilink | [[page|display text]] |
MediaWiki | the format, HMD-0001 §2 | shipped |
| F3 | Heading reference | [[page#Section]] |
MediaWiki | the format, HMD-0001 §2 / §3 | shipped |
| F4 | Block anchor | text ^block-id |
Obsidian | the format, HMD-0001 §2 | shipped |
| F5 | Block reference | [[page#^block-id]] |
Obsidian | the format, HMD-0001 §2 | shipped |
| F6 | Embed | ![[…]] |
Obsidian (spelling), MediaWiki transclusion (concept) | the format, HMD-0001 §6 | shipped |
| F7 | Tags | tags: [area/auth] |
Jekyll frontmatter, GitHub | the format, HMD-0001 §5.3 | shipped |
| F8 | Per-card toggles | use: [no_autodiscovery] |
— | the format, HMD-0001 §5.3 | shipped |
| F9 | Explicit imports | import: [from /shared import *] |
Python's import |
the format, HMD-0001 §5.3 | shipped |
| F10 | Nav position | nav: 10 |
MkDocs nav: |
the format, HMD-0002 §2 | shipped |
| F11 | Callouts | !!! note |
reStructuredText admonitions | admonition |
shipped |
| F12 | Collapsible callouts | ??? tip |
reStructuredText admonitions | pymdownx.details |
shipped |
| F13 | Fenced code | ```lang |
GFM | pymdownx.superfences |
shipped |
| F14 | Tables | | a | b | |
GFM | tables |
shipped |
| F15 | Task lists | - [x] item |
GFM | pymdownx.tasklist |
shipped |
| F16 | Footnotes | text[^1] |
Pandoc | footnotes |
shipped |
| F17 | Display and inline math | $x$, $$…$$ |
LaTeX | pymdownx.arithmatex + MathJax |
shipped |
| F18 | D2 diagrams | ```d2 |
D2 | diagram.py + the d2 binary |
shipped |
| F19 | Heading permalinks | (automatic) | MkDocs / Sphinx | toc |
shipped |
| F20 | Strikethrough | ~~text~~ |
GFM | pymdownx.tilde |
shipped |
| F21 | Inline properties | key:: value |
Logseq | — (HMD-0003 §2) | deferred |
| F22 | Highlights | ==text== |
Obsidian, CriticMarkup | — | nice to have |
| F23 | Mermaid diagrams | ```mermaid |
Mermaid | — | rejected |
| F24 | Templates | — | Confluence, MediaWiki | — (HMD-0003 §5) | deferred |
| F25 | HQL — query language | — | Obsidian Dataview, Confluence CQL, SQL | — (HMD-0003) | nice to have |
| F26 | Backlinks and category pages | — | Wikipedia, Obsidian | — | nice to have |
| F27 | Escapes for reserved characters | — | — | — | nice to have |
| F28 | A literal [[ outside a code span |
— | — | — | nice to have |
F6 is any of F1–F5 with a ! in front, so it multiplies the table rather than
adding a new construct. Expansion is textual, does not shift heading levels,
detects cycles (HMD007), and caps depth at 16 (HMD008).
F18 is the one row whose implementation is not purely bought: a d2 fence is a
diagram, not a code block, it renders through the binary to a data: URI
image, and it degrades to a labelled placeholder when the binary is absent. F19
is load-bearing rather than decorative — F3 resolves against the slugs toc
assigns, so the link and its destination cannot disagree.
F23 is rejected by the source, not merely unbuilt, because D2 (F18) already
covers diagrams and two diagram languages is one too many. F22 was rejected on
the same footing and is no longer — it is now nice to have, wanted but
unspecified and uncommitted.
The Comes from column distinguishes the wiki tradition from Obsidian
deliberately, because the two are routinely conflated. F1–F3 are MediaWiki
syntax, and older than that in spirit: [[…]] and its | alias have been the
wiki link since MediaWiki carried them to Wikipedia in 2002, with WikiWikiWeb
(1995) upstream of both, and # for a fragment is older still — it is URI
syntax. Obsidian adopted all three in 2020 because they were already the
convention every wiki reader knew; it did not invent them. What Obsidian did
contribute is the block layer, F4 and F5: the ^block-id anchor and the
[[page#^block-id]] reference have no MediaWiki ancestor, since MediaWiki
addresses sections but never blocks. F6 splits — the ![[…]] spelling is
Obsidian's, the idea of transcluding one page into another is MediaWiki's
({{Template}}, 2004), which is the same lineage F24 cites.
Note that F26 already credited Wikipedia while F1–F3 credited Obsidian for that same inheritance; the rows now agree.
Where the format does diverge from Obsidian is the part that matters most: F1–F6 explicitly do not copy Obsidian's link-text character restrictions or its shortest-unique-path resolution. The format takes the wiki tradition's syntax and rejects Obsidian's resolution semantics.
F27 and F28 are the two real gaps, and they are the same gap seen from either
end. There is no escape mechanism anywhere: the reserved set inside a target is
exactly [, ], |, #, ^, and newline, so a target needing one of them is
simply malformed (HMD010) — and in the other direction, the only way to show a
wikilink without resolving it is to put it in a code span or a fence, because
those are the regions the scanner masks. Raw inline HTML is not masked, so
<code> written by hand still gets scanned.
The F2 row above is where that bites: it renders a pipe inside a table cell,
which forces raw <code> (issue 0006), which in turn forces [[ for
the brackets so the scanner does not read the cell as a real link. A card that
documents the format is the one card most likely to need this, which is why the
gap is recorded rather than worked around quietly.
Presentation layers¶
The feature list above is renderer-agnostic — it says what the format has. What reaches a reader depends on which surface renders it, and there are two. Both consume the same semantics; neither redefines them.
Layer 1 — MkDocs, the published book¶
Specified by HMD-0002, implemented as a
single file, mkdocs_plugin.py, registered through
[project.entry-points."mkdocs.plugins"]. It expands embeds and rewrites links
at on_page_markdown, before Python-Markdown runs, so every bought extension in
Blocks C and D sees ordinary markdown and needs to know nothing about the
format.
This layer is erasure: the output is flat HTML in which the boundary between a card and the content it embedded is gone, along with the provenance of every link. That is correct for a shipping format and fatal for a preview — see md-hmd-interop, which is where the argument lives. Book mode only; backlinks and category pages are F26.
One structural property is worth stating, because it is what keeps the layer
cheap: MkDocs touches exactly one file. parse, resolve, embed, urls, and
lint do not import it, and HMD-0002 §1–§4 name no renderer. Swapping it is one
file and mkdocs.yml, not a re-specification.
Layer 2 — preview mode, the editor surface¶
The sibling line: a TypeScript document model and a VS Code webview that renders
a card as you edit it. It is specified on the feat/vsc-ext branch by HMD-0020
(@hyper-markdown/core, the document model), HMD-0021 (the extension and its
preview surface), and HMD-0022 (D2 in the webview, under its content security
policy). Those proposals are not on this branch yet — the branch merges soon,
and the links belong here once it does.
The load-bearing difference from Layer 1 is that preview mode keeps the embed boundary. It renders F6 as visibly embedded content with its source attached, which is the one thing it does that a plain markdown previewer cannot, and the reason the editor line rejected flat markdown as its transport. Layer 1 throws that away deliberately; Layer 2 cannot.
Python stays canonical for semantics. A second parser that resolved a name differently from the command line would be worse than no second parser, so HMD-0001 and the conformance corpus are the contract between the two layers rather than a shared runtime.
Support matrix¶
Where the two layers differ. Everything not listed is shipped on Layer 1 and tracked against Layer 2 by its own proposals.
| # | Feature | Layer 1 — MkDocs | Layer 2 — preview |
|---|---|---|---|
| F6 | Embed | expanded, boundary erased | expanded, boundary kept |
| F10 | nav: |
orders the site nav | no meaning |
| F18 | D2 diagrams | data: URI <img> |
data: URI under the webview CSP |
| F26 | Backlinks | out of scope | the natural home for it |
Changing this card¶
Add a feature by appending the next free number in its block; never renumber and never reuse. Move a row's Status in the same commit that changes the code, the way a proposal's tracker moves a work point — see tracking. This card tracks the format; a tracker tracks the implementation of one proposal, and the two answer different questions.