Skip to content

LearnMD — Format Specification v0.2

Core principle: Markdown first

LearnMD is the companion format to QuizMD: where QuizMD covers assessment (testing what you know), LearnMD covers instruction (explaining what to know). Together they form a complete teach → assess stack, all in portable plain-text files.

A complete learning path — chapters, lessons, exercises, quizzes — can live in a single valid .learn.md file. The !import directive is an optimization tool for reusability, not a prerequisite.

PrincipleDescription
Markdown-firstA .learn.md file is valid Markdown — readable in any editor
Git-nativeVersionable, diffable, and mergeable like code
AI-nativeGeneratable and consumable by LLMs without special tooling
Progressively enrichedPlain text (Level 0) up through special fenced blocks (Level 2)
QuizMD-interoperableInline ```quiz blocks and !import directive to embed checkpoints

Format levels

LevelMechanismPurpose
0Plain .learn.md, pure MarkdownMinimal learning content, human-readable
1YAML frontmatter + GFM calloutsMetadata, estimated time, language
2Special fenced blocks + directivesExamples, summaries, inline quizzes, imports

Each level is a strict superset of the previous one. A Level 0 file is valid at Level 1 and 2.


Document architecture

Three-tier hierarchy

path (.learn.md, minimal or no frontmatter)
└── module (## heading)
    └── lesson (### heading or file imported via !import)
  • Structure is strictly linear in v0.2 (no branching)
  • ```quiz blocks and !import directives are usable at any level
  • External content is referenced via native Markdown links [text](url) and ![alt](url)

Level 0 — Plain Markdown

Conventions

SyntaxMeaning
# TitleDocument title (inferred by the parser if absent from frontmatter)
## Module titleMain section heading
### Lesson titleSub-section heading
> textGeneric blockquote or note
!import ./file.learn.mdInclude another lesson file
!import ./file.quiz.mdEmbed a QuizMD checkpoint from an external file
$...$Inline LaTeX math formula
$$...$$Block (display) LaTeX math formula

Minimal example

markdown
# Introduction to Python

## Module 1 — Variables

A variable is a named reference to a value in memory.

\`\`\`python
age = 25
\`\`\`

## Module 2 — Conditions

An `if` statement runs code only when a condition is true.

\`\`\`python
if age >= 18:
    print("Adult")
\`\`\`

Level 1 — YAML frontmatter

A YAML block at the top of the .learn.md file, between two --- lines.

yaml
---
title: Python Variables       # optional — inferred from the first # H1 if absent
lang: en                      # REQUIRED — BCP-47 code (en, fr, en-US, …)
estimated_time: 15min         # optional — free-form duration string
tags: [python, variables]     # optional — list of strings
author: Jane Smith            # optional — string or {name, email, url}
---

Frontmatter field reference

FieldRequiredTypeDescription
titleNostringOverrides the first # H1. Inferred from H1 if absent.
langYesBCP-47Language code: en, fr, en-US, etc.
estimated_timeNostringFree-form estimated reading/study time: 15min, 1h30, 2h
tagsNostring[]Thematic tags
authorNostring or objectAuthor name, or {name, email, url}
spec_versionNostringLearnMD spec version this file targets (e.g. "0.2")

lang is the only required field. All other fields are optional.

GFM callouts

Callouts use GitHub Flavored Markdown syntax and are rendered with visual emphasis by compatible players.

Supported everywhere (GitHub, Obsidian, neuroneo.md):

SyntaxSemanticTypical use
> [!note]NoteSupplementary information
> [!tip]TipBest practice, shortcut, helpful advice
> [!warning]WarningCommon pitfall, frequent mistake
> [!important]ImportantCritical point to remember
> [!caution]CautionRisk of error or data loss

Supported on Obsidian and neuroneo.md (degrade gracefully to a blockquote on GitHub):

SyntaxSemanticTypical use
> [!summary]SummaryKey takeaways at the end of a lesson
> [!example]ExampleNon-code illustrative example
> [!objectives]Learning ObjectivesWhat the learner will be able to do after this lesson — place at the top
markdown
> [!warning]
> In Python, variable names are case-sensitive:
> `Age` and `age` are two different variables.
markdown
> [!tip]
> Use descriptive names: `student_count` is clearer than `n`.

Level 2 — Special fenced blocks and directives

Special blocks follow the same fenced syntax as QuizMD. They add structured, semantically meaningful containers to the lesson content.

Inline quiz checkpoint

Embeds a single question using QuizMD syntax directly in the lesson. All QuizMD question types are supported: mcq, multi, open, tf, match, order.

Syntax:

markdown
```quiz
? What operator assigns a value in Python?
- [x] =
- [ ] ==
- [ ] :=
```

The question starts with ? followed by the question text. Answer choices use - [x] (correct) and - [ ] (incorrect), identical to QuizMD Level 0.

Attributes (appended after the word quiz on the opening line):

AttributeDefaultDescription
scored:falseYes (default)Practice mode — immediate feedback, no score recorded
scored:trueScored checkpoint — contributes to lesson score

Inline quiz vs external file:

NeedSyntax
Single simple questionInline ```quiz block
Multiple questions, advanced scoring, or shared config!import ./file.quiz.md directive

Fenced callout blocks

Fenced callout blocks are Level 2 alternatives to GFM callouts. They support richer content (multi-paragraph, nested lists, syntax-highlighted code) and are rendered with a visual header by compatible players.

Supported block types:

LanguageIconLabelTypical use
```note📝NoteSupplementary information
```tip💡TipBest practice or helpful advice
```warning⚠️WarningCommon pitfall, frequent mistake
```importantImportantCritical point to remember
```caution🔴CautionRisk of error or data loss
```summarySummaryKey takeaways at the end of a lesson
```example🔍ExampleIllustrative example
```objectives🎯Learning ObjectivesWhat the learner will achieve — place at top

Optional title attribute (title:"..."):

markdown
```example title:"Token prediction"
Context: "The capital of France is"
Most likely token: " Paris"
Less likely token: " Lyon"
```

Optional code language — place the language identifier before title: to render the body as a syntax-highlighted code block:

markdown
```example python title:"Assigning and reassigning a variable"
score = 0
print(score)   # → 0

score = 42
print(score)   # → 42
```

Composition directives

!import <path>

Includes content from another file at the current position. The file type is detected from the extension:

  • .learn.md — lesson content is inserted inline (frontmatter ignored)
  • .quiz.md — renders as an interactive QuizMD checkpoint
markdown
!import ./03-conditions.learn.md
!import ./check-variables.quiz.md

Behavior:

  • The imported file's content is inserted at the position of the directive.
  • For .learn.md: the file's content is rendered inline. Frontmatter is ignored.
  • Imports are recursive: an imported file may itself contain !import directives.
  • Circular imports are silently skipped.

Math support

LearnMD uses LaTeX formulas rendered via KaTeX. Math is auto-detected: no frontmatter flag is required.

FormSyntaxRendering
Inline$E = mc^2$Embedded in the line of text
Block (display)$$\int_0^\infty e^{-x}\,dx = 1$$Centered on its own line

ABC music notation

LearnMD supports ABC notation for embedding sheet music. Compatible renderers use abcjs to produce SVG output directly in the browser.

Use a fenced code block with the language identifier abc, optionally followed by flags:

FlagDescription
(none)Static SVG score only
playAdds audio controls
cursorHighlights the current note during playback (requires play)
colorsColors each note by pitch class (requires play)

Penrose diagrams

LearnMD supports Penrose declarative mathematical diagrams, rendered via @penrose/core. Three sections separated by ---:

  1. domain — Declares types, predicates, and constructors
  2. style — Maps domain elements to visual shapes and layout
  3. substance — Describes the specific mathematical objects to draw

Syntax reference table

ElementSyntaxLevel
Document title# Title0
Module heading## Module title0
Lesson heading### Lesson title0
Generic blockquote> text0
Import lesson!import ./file.learn.md0
Embed quiz checkpoint!import ./file.quiz.md0
Inline math$formula$0
Block math$$formula$$0
Frontmatter--- YAML ---1
Note callout> [!note]1
Tip callout> [!tip]1
Warning callout> [!warning]1
Important callout> [!important]1
Summary callout> [!summary]1
Example callout> [!example]1
Objectives callout> [!objectives]1
Inline quiz question```quiz2
Scored inline quiz```quiz scored:true2
Note callout (fenced)```note2
Summary callout (fenced)```summary2
Example callout (fenced)```example [lang] [title:"..."]2
Objectives callout (fenced)```objectives2
ABC (static)```abc0
ABC (interactive)```abc play cursor colors0

Validation

Lenient mode (default)

ConditionLevel
lang absent from frontmatterWarning
Title absent (no H1 and no frontmatter title)Warning
Unclosed fenced blockError
Inline quiz block with no ? lineError
!import pointing to a missing fileWarning

Strict mode (--strict)

ConditionLevel
lang absentError
Title absentError
All lenient-mode errorsError

Strict mode is recommended for CI pipelines and production publishing. Lenient mode is appropriate during authoring.

Released under the MIT License.