MD ↔ HMD interoperability¶
Markdown is JavaScript. Hyper-markdown is TypeScript.
That analogy is the shortest way to say what hyper-markdown is for, and it carries further than a slogan should. This card sketches how far. Nothing here is decided — no proposal owns it yet.
What the analogy claims¶
TypeScript is a superset of JavaScript that adds structure a machine can check,
compiles away to the thing it extends, and can be adopted one file at a time.
.hmd stands in the same relation to .md:
| TypeScript | Hyper-markdown |
|---|---|
every .js is valid .ts |
every .md is valid .hmd |
| types, interfaces, imports | wikilinks, embeds, frontmatter import |
tsc erases types, emits .js |
hmd resolves the graph, emits .md |
tsc --noEmit checks without building |
hmd lint |
adopt file by file, allowJs |
adopt card by card, red links are warnings |
.d.ts describes untyped code |
(no analogue yet — see below) |
The claim is not type checking. The added structure is a graph: which page a name means, which block a reference points at, which namespace a card lives in. Ambiguity is the error condition, the way a type mismatch is.
Compilation is the deeper step¶
The MVP stops at checking. The analogy says the toolchain is really a compiler
with two directions, and linting is just the --noEmit mode of one of them.
hmd → md is erasure. Resolve every link to a path, expand every embed
inline, drop the frontmatter the toolchain owns, and what remains is ordinary
markdown that GitHub, Obsidian, or a plain renderer reads without knowing the
format exists. This is exactly what compiling TypeScript does, and it is lossy
in the same way: the source of a link — spine walk, named import, sweep — is
gone from the output, and so is the boundary between a card and the content it
embedded.
That last loss is not free. A preview that renders an expanded embed as anonymous prose has thrown away the one thing it does that a markdown previewer cannot, which is why the editor line rejected flat markdown as its transport even while erasure stays the right build output. Erasure is a shipping format, not an interchange format.
md → hmd is conversion. Take a folder of ordinary markdown and convert
it: relative links become wikilinks where the target is unambiguous, folders
become namespaces, sibling references collapse to bare names. Where the
converter cannot be certain it leaves the relative link alone — the mixed state
is valid, which is the whole point of a superset.
Conversion is not only a migration path. It is the fastest way to write hyper-markdown: draft in plain markdown at speed, with ordinary relative links and no namespace in your head, then convert and let the resolver tell you what it could not place. Authoring stops requiring you to know the tree.
That is where the analogy earns its keep. Nobody rewrites a wiki by hand, and
allowJs is why TypeScript won.
Why this is canonical, not a plugin¶
Both directions are semantics, and semantics live in the Python implementation.
An editor, a second parser, or a future language server consumes them; none of
them redefine them. A md → hmd promotion that guessed differently in the
editor than on the command line would be worse than no promotion at all.
The reverse direction also suggests the missing table row: what plays the part
of .d.ts — a way to describe a body of plain markdown to the resolver without
touching it? Sidecar frontmatter, a manifest, or nothing at all. Open.
Open threads¶
- Is erasure a build product only, or is round-tripping
hmd → md → hmda guarantee worth paying for? The lossy parts say no; the adoption story says it would be nice. - What does erasure emit? "Ordinary markdown" is not one target — plain markdown and GFM disagree about tables, task lists, and strikethrough, and neither expresses callouts or math. A third target, single-file HTML, expresses everything and reads back as nothing. Tracked as issue 0007.
- Does conversion ever run destructively, or only ever as a diff a human accepts? An authoring loop wants it in place; a migration wants review.
- Does a compiler framing want a
hmd buildcommand distinct fromhmd render, the waytscis distinct from a formatter?
See hyper-markdown for the format itself, and HMD-0002 for the erasure direction as it is actually being built — MkDocs output, one way only.