*This is a draft. I'm working on designing a new mnemonic medium for the web.*
# Introduction
Mnemonic markdown is an extension of CommonMark markdown that allows you to specify memory prompts for spaced recall practice directly inline with the document and provides additional extensions to enable the authoring of mnemonic texts.
## What is mnemonic markdown?
Mnemonic markdown is an extension of markdown that allows you to specify memory prompts for spaced recall practice directly inline with the document.
This makes it conceptually different from markdown, which renders to HTML. Mnemonic markdown renders to HTML and JavaScript, but additionally describes *intent* not only for static display, but also for interactivity.
So while markdown is really about typesetting for the web, mnemonic markdown is about interactive typesetting. This presents a challenge in specifying the format. When specifying markdown, the creators of CommonMark, for example, could list the html that would result from some specific syntax. When specifying the extensions that mnemonic markdown provides, we need to specify not only the document rendered for reading, but also the retrieval prompts created.
Mnemonic markdown presents a further opportunity. While markdown was specified in the context of creating a simple and elegant way to write rich text as plain text. With Mnemonic markdown we want to create a {{medium}} ^'362c for thinking with a computer, both as an individual, and with others. For this reason, we will incorporate additional syntax for citation, links, references, special list formatting, etc... as inspired by pandoc.
Mathematics is obviously essential. And we will strive for excellent math support with single and double dollar sign syntax as well as the ability to number of reference functions.
Obsidian has contributed several improvements that we would like to incorporate as well.
This document will eventually grow to be a formal specification of Mnemonic Markdown, but at first it will be an informal specification during alpha development, while the syntax is still in flux.
# Planned Ecosystem
## Workflow Cycle
```mermaid
```
- Authoring
- Publishing
- Mnemonic Markdown is designed to be published to the web or to a web view embedded inside an application.
- All published mnemonic markdown (Mnemonic Hypertext) is
- Mnemonic Markdown also supports the creation of manuscripts (export) for print and e-books and the generation of flashcard decks for Anki and Mochi Cards.
- Reading, Annotating, Note Taking
## Technologies
- Mnemonic Markdown
- Mnemonic.js: A javascript library that adds the appropriate interactivity
- Mnemonic Hypertext
## Affordances of the Mnemonic Markdown Ecosystem
- Write mnemonic markdown in any editor. It's just a plain text file.
- Create Vaults (i.e. project directories) of mnemonic markdown with coherent internal links to facilitate site generation
---
---
# Initial Thoughts
*This is an AI summary of a conversation wtih Claude 4.5 where I described my ideas for a mnemonic syntax*
Since we don't have a content aware scheduler, you're going to need a review history for each card.
---
## Overview
A lightweight, Markdown-native syntax for creating spaced repetition flashcards using cloze deletion. Designed for Obsidian, this system keeps your study materials integrated with your notes while providing powerful card creation capabilities.
## Core Principles
- **Simple**: Everything uses `{{...}}` syntax
- **Markdown-native**: Works with standard Markdown formatting
- **Context-aware**: Cards display surrounding content
- **Flexible**: Supports simple clozes, grouped blanks, sequences, and custom Q&A
## Card Scope
**Card scope** determines which clozes are grouped together and what context appears on cards.
### Definition
A card scope is a contiguous block of text separated by blank lines (2 or more newlines).
**Exception**: A list and its immediately preceding paragraph form one card scope, even if there's a blank line between them.
### Examples
**Separate scopes:**
```markdown
This is one scope {{1>foo}}.
This is another scope {{1>bar}}.
```
Result: Two separate cards (blank line creates new scope).
**Same scope (no blank line):**
```markdown
Regular paragraph {{1>foo}}.
Another paragraph {{1>bar}}.
```
Result: One card with two blanks.
**List with intro (merged scope):**
```markdown
Introduction to my list:
1. {{1>first item}}
2. {{1>second item}}
```
Result: One card with two blanks. "Introduction to my list:" appears as context on the card.
## Syntax Elements
### 1. Basic Cloze Deletion
**Syntax**: `{{text}}`
Creates a single flashcard with the text hidden as a blank.
**Example:**
```markdown
The capital of France is {{Paris}}.
```
**Card displays:**
- Front: "The capital of France is ___."
- Back: "The capital of France is Paris."
### 1.2 Hints
Syntax: `{{clozed thing|hint goes here}}`
The cloze will display the hint on the front size of the card with special formatting to make it clear it is a hint.
---
### 2. Grouped Cloze Deletion
**Syntax**: `{{N>text}}` where N is any positive integer
Multiple clozes with the same number within the same card scope appear as blanks on a single card.
**Scope**: Numbers are scoped to the card scope level. Same number in different scopes = different cards.
**Example:**
```markdown
The {{1>mitochondria}} is the {{1>powerhouse}} of the cell.
```
**Card displays:**
- Front: "The ___ is the ___ of the cell."
- Back: "The mitochondria is the powerhouse of the cell."
**Cross-scope behavior:**
```markdown
Paragraph one has {{1>foo}}.
Paragraph two has {{1>bar}}.
```
Result: Two separate cards (different card scopes, even though both use `1>`).
---
### 3. Sequence Cloze Deletion
**Syntax**: `{{N.>text}}` where N is any positive integer
Creates multiple cards that reveal answers progressively in document source order.
**Display**: Each card shows all previous answers filled in, current answer as blank, and future answers as "???".
**Scope**: Sequences are scoped to the card scope level.
**Example:**
```markdown
Steps in the Krebs cycle:
1. {{1.1>Acetyl-CoA combines with oxaloacetate}}
2. {{1.2>Citrate is formed}}
3. {{1.3>Isocitrate is oxidized}}
```
Max came up with this great idea of using 1.1 1.2 1.3 instead of 1. 1. 1. which was less useful and expressive!!!
**Cards display:**
- Card 1: "1. ___ / 2. ??? / 3. ???"
- Card 2: "1. Acetyl-CoA combines with oxaloacetate / 2. ___ / 3. ???"
- Card 3: "1. Acetyl-CoA combines with oxaloacetate / 2. Citrate is formed / 3. ___"
**Order note**: "Text order" means document source character order, regardless of list numbers or formatting.
**Non-list sequences:**
```markdown
First {{1.>Napoleon}} was born, then he became {{1.>Emperor}}, then he was {{1.>exiled}}.
```
Creates three progressive cards in order.
---
### 4. Cloze with Extra Content
**Syntax**: `{{text<extra content}}`
The extra content appears on the card back/reveal side only.
**With literal text:**
```markdown
The heart has {{four chambers<two atria and two ventricles}}.
```
**Card displays:**
- Front: "The heart has ___."
- Back: "four chambers" + "two atria and two ventricles"
**With reference injection:**
```markdown
The ACL connects the {{femur<(^acl-detail)}} to the tibia.
[^acl-detail]: Prevents anterior translation of the tibia {.card-only}
```
**With multiple references:**
```markdown
Napoleon was born in {{Corsica<(^corsica-info) See also: (^napoleon-timeline)}}.
[^corsica-info]: Island in the Mediterranean {.card-only}
[^napoleon-timeline]: Born 1769, died 1821 {.card-only}
```
---
### 5. Content Injection (Card Front)
**Syntax**: `(^ref)`
Injects content from a reference definition onto the card front as context.
**Example:**
```markdown
(^heart-diagram) This structure is the {{left ventricle}}.
[^heart-diagram]: {#heart-diagram .card-only}
```
**Card displays:**
- Front: [Heart diagram image] + "This structure is ___."
- Back: "left ventricle"
**Multiple injections on front:**
```markdown
(^diagram1) (^diagram2) What process is shown? {{Mitosis}}
[^diagram1]: {.card-only}
[^diagram2]: {.card-only}
```
---
### 6. Reference Definitions
**Syntax**: Standard Pandoc footnote syntax with optional attributes
```markdown
[^ref-name]: content
[^ref-name]: content {.card-only}
```
**Behavior:**
- **Without `.card-only`**: Renders as normal footnote in reading view AND available for card injection
- **With `.card-only`**: Hidden in reading view, only appears on cards that reference it
**Content types**: Text, images, or any Markdown content.
**Error handling:**
- Duplicate definitions: Warning issued, first definition used
- Undefined reference: Error
- Same ref on front and back: Allowed (content appears in both places)
**Text reference example:**
```markdown
The patient needs {{intubation<(^intubation-criteria)}}.
[^intubation-criteria]: When ventilatory failure is not easily reversible or persistent hypoxemia despite maximal O2 {.card-only}
```
**Image reference example:**
```markdown
[^ecg-normal]: {#ecg .card-only}
(^ecg-normal) What rhythm is this? {{Normal sinus rhythm}}
```
---
### 7. Images
**Standard image**: ``
**With reference ID**: `{#ref-id}`
**Card-only images**: `{#ref-id .card-only}`
**Display rules:**
- Standard images display normally in document
- Images with `{#ref-id}` can be referenced via `(^ref-id)` for card injection
- Images with `.card-only` are hidden in reading view, only appear on cards
- Images do NOT automatically appear from context window
- Images only appear on cards when explicitly injected via `(^ref)`
**Example:**
```markdown
{#acl-diagram .card-only}
(^acl-diagram) What ligament prevents anterior tibial translation? {{ACL<(^acl-function)}}
[^acl-function]: Anterior Cruciate Ligament - most commonly injured knee ligament {.card-only}
```
**Image on both document and cards:**
```markdown
{#heart-img}
The heart has (^heart-img) {{four chambers}}.
```
Result: Image shows in document normally AND on the flashcard.
---
### 8. Custom Q&A Format
You can write explicit question-answer pairs using blockquotes for visual separation.
Here, the block quote is purely sylistic and has no speical meaning for the parser.
**Example:**
```markdown
#### Heart Anatomy
The heart pumps blood through the {{circulatory system}}.
> What are the four chambers called?
> {{Two atria and two ventricles}}
> Why do ventricles have thicker walls?
> {{They pump blood further distances<(^ventricle-pressure)>}}
[^ventricle-pressure]: Left ventricle pressure: 120mmHg systolic {.card-only}
```
Note: The `>` blockquote is purely stylistic - it's just regular Markdown. The `{{cloze}}` syntax works the same anywhere.
#### Special quote block
If you want to define a card scope, you can use a > ? to state, this entire quote block will be presented as a card.
> ?
> My question
>
> {{
> My answer
> | hint goes here...
> <
> My extra goes here
> }}
---
### 9. Nesting
**Syntax**: `{{outer {{nested}} content}}`
Nested clozes are supported.
**Example:**
```markdown
{{The equation {{E=mc²}} relates energy and mass}}.
```
Creates separate cards:
1. "The equation ___ relates energy and mass" → "E=mc²"
2. "The equation ___ relates energy and mass" → "The equation E=mc² relates energy and mass"
---
### 10. Escape Sequences
**Use backslashes to write literal cloze syntax:**
```markdown
To create a cloze, write \{\{text\}\}.
```
Displays: "To create a cloze, write {{text}}."
**Alternative for code (add spaces):**
```markdown
In JavaScript, use { { destructuring } } for objects.
```
---
## Context Display
Cards automatically show surrounding context from their card scope:
### Regular Text
~5-10 lines above and below the cloze with fade effect (opacity gradually decreases).
### Lists
The preceding paragraph (if merged into scope) + faded context within the list.
**Example:**
```markdown
Three types of muscle tissue:
1. {{Skeletal}} - voluntary control
2. {{Cardiac}} - heart muscle
3. {{Smooth}} - involuntary, found in organs
```
All three cards show "Three types of muscle tissue:" as context.
### Code Blocks
Full code block with fade to either end if too long. Context is scrollable while maintaining syntax highlighting.
**Example:**
````markdown
Python list comprehension:
```python
squares = [{{x**2}} for x in range(10)]
print(squares)
````
````
Card shows the complete code block with syntax highlighting.
---
## Complete Examples
### Example 1: Medical Study Material
```markdown
#### Indications for Intubation
Failure of ventilation or oxygenation is a {{1>primary}} indication for {{1>intubation}}.
Assessment includes evaluation of:
1. {{eval>Patient's general status}}
2. {{eval>Oxygen saturation by pulse oximetry}}
3. {{eval>Ventilatory pattern}}
Arterial blood gases are {{not required<(^abg-note)}} to determine intubation need.
[^abg-note]: ABGs may be misleading and cause false sense of security - can delay intubation in deteriorating patient {.card-only}
````
**Cards created:**
1. One card: "Failure of ventilation or oxygenation is a ___ indication for ___."
2. One card: Three blanks for assessment items
3. One card: "ABGs are ___ to determine..." with extra note on back
---
### Example 2: Programming Concepts
````markdown
{#react-img .card-only}
(^react-img) The {{useState}} hook allows {{functional components}} to have state.
Syntax:
```javascript
const [{{state}}, {{setState}}] = useState({{initialValue}});
````
The setter function {{setState<(^rerender-note)}} triggers a re-render.
[^rerender-note]: React compares old and new state, only re-renders if different {.card-only}
````
---
### Example 3: Historical Timeline
```markdown
Key events in Napoleon's life:
- {{1.>Born in Corsica}} (1769)
- {{1.>Became First Consul}} (1799)
- {{1.>Crowned Emperor}} (1804)
- {{1.>Invaded Russia}} (1812)
- {{1.>Exiled to Elba}} (1814)
- {{1.>Defeated at Waterloo}} (1815)
- {{1.>Died on Saint Helena}} (1821)
````
Creates 7 progressive cards revealing events in chronological order.
---
### Example 4: Anatomy with Images
```markdown
[^anterior-view]: {.card-only}
[^lateral-view]: {.card-only}
#### Knee Ligaments
(^anterior-view) The {{ACL<(^acl-detail)}} prevents anterior translation.
(^lateral-view) The {{MCL<(^mcl-detail)}} prevents valgus stress.
[^acl-detail]: Most commonly torn during pivoting sports {.card-only}
[^mcl-detail]: Broad, flat ligament - more stable than ACL {.card-only}
```
---
## Edge Cases & Special Behaviors
### Empty Clozes
`{{}}`, `{{<extra>}}`, `{{1>}}` are ignored (no card created).
### Special Characters in References
Reference names support letters, numbers, hyphens, and underscores (standard Pandoc footnote format).
### Code Blocks
Clozes work inside code blocks. Context scope is the entire code block.
### Same Reference Multiple Times
A reference can be used on multiple cards and on both front and back of the same card.
### Cross-Scope Sequences
Sequence clozes in different card scopes are separate sequences, even if they use the same number.
```markdown
First paragraph: {{1.>a}} then {{1.>b}}.
Second paragraph: {{1.>x}} then {{1.>y}}.
```
Creates two separate 2-card sequences.
---
# Block IDs for Card Stability
## Overview
Block IDs provide stable identity for cards across edits to the source markdown. They are automatically generated and allow the spaced repetition system to track review history even as you refine and improve your notes.
## Syntax
**Basic pattern**: `{{cloze}} ^block-id`
The block ID is placed immediately after the closing `}}` of a cloze.
**Format**: `^` followed by alphanumeric characters (typically 6-8 characters)
**Example**:
```markdown
The capital of France is {{Paris}} ^c4f2a9.
```
## Behavior
### Auto-Generation
Block IDs are **automatically added** the first time a cloze is reviewed. You don't need to manually create them.
**Before first review**:
```markdown
The mitochondria is the {{powerhouse}} of the cell.
```
**After first review (auto-generated)**:
```markdown
The mitochondria is the {{powerhouse}} ^a7k3m9 of the cell.
```
### Multiple Clozes
Each cloze gets its own block ID:
```markdown
The {{mitochondria}} ^abc123 is the {{powerhouse}} ^def456 of the cell.
```
### Grouped Clozes
For grouped clozes (multiple blanks on one card), only **one block ID is required** for the entire group:
```markdown
The {{1>mitochondria}} is the {{1>powerhouse}} ^card-001 of the cell.
```
The block ID can be placed after any cloze in the group.
### Sequence Clozes
Each card in a sequence gets its own block ID since they are separate cards:
```markdown
Napoleon's life:
1. {{1.>Born in Corsica}} ^seq-001
2. {{1.>Became Emperor}} ^seq-002
3. {{1.>Exiled to Elba}} ^seq-003
```
## Editing Rules
### Rule 1: Same Block ID = Same Card
If the block ID is preserved, the card is updated with new content but **all review history is kept**.
```markdown
# Original
A {{patent}} ^c4f2a9 airway is essential.
# After edit
A {{patent and unobstructed}} ^c4f2a9 airway is critical.
```
**Result**: Card content updates, review history preserved.
### Rule 2: Deleting Block ID = Deleting Card
To delete a card, delete its block ID.
```markdown
# Original
A {{patent}} ^c4f2a9 airway is essential.
# Delete the card (remove block ID)
A {{patent}} airway is essential.
```
**Result**:
- Old card archived in database
- New block ID auto-generated on next review: `A {{patent}} ^x9k2m7 airway is essential.`
- New card created (fresh review history)
### Rule 3: Edit Freely, Keep Block ID
You can change anything about the cloze - the answer, the context, the surrounding text - as long as the block ID stays, it's the same card.
```markdown
# Original
The capital is {{Paris}} ^geo-001.
# Change answer
The largest city is {{Paris}} ^geo-001.
# Change context completely
{{Paris}} ^geo-001 is a major European city.
```
All three are treated as the **same card** (same `^geo-001`), review history preserved.
## Visual Display
Block IDs are part of your markdown but can be visually de-emphasized:
### In Editor (CSS)
```css
/* Fade out block IDs */
.cm-blockid {
opacity: 0.25;
font-size: 0.75em;
color: var(--text-faint);
}
/* Optional: Hide completely */
.hide-block-ids .cm-blockid {
display: none;
}
```
### In Reading View
Block IDs are typically hidden completely in reading view since they're metadata for the review system.
## Database Relationship
```sql
CREATE TABLE cards (
id TEXT PRIMARY KEY, -- Same as block_id
block_id TEXT UNIQUE NOT NULL, -- The ^abc123 from markdown
file_path TEXT,
-- Card content (cached from markdown)
question TEXT,
answer TEXT,
context TEXT,
-- FSRS scheduling data
stability REAL,
difficulty REAL,
state INTEGER,
due TEXT,
-- ... etc
-- Change detection
content_hash TEXT,
modified_at TEXT
);
CREATE TABLE archived_cards (
-- Same schema as cards
-- Cards moved here when block ID is deleted
archived_at TEXT
);
```
The `block_id` is the **stable link** between markdown source and review database.
## Complete Example
```markdown
#### Intubation Criteria
The decision to intubate is based on three criteria:
1. {{Failure to maintain or protect the airway}} ^intub-01
2. {{Failure of ventilation or oxygenation}} ^intub-02
3. {{Anticipated clinical deterioration}} ^intub-03
A {{patent}} ^patent-01 airway is essential. Patency should be established using {{airway maneuvers such as repositioning, chin lift, jaw thrust, or insertion of an oral or nasal airway}} ^maneuvers-01.
The gag reflex is {{not reliable}} ^gag-01 for assessing airway protection because it is {{absent in 12-25% of normal adults}} ^gag-02.
```
**Cards created:**
- 7 separate cards
- Each with stable block ID
- Edit text freely → card updates, history preserved
- Delete block ID → card archived, new card created
## Benefits
✅ **Simple rule**: Same ID = same card, always
✅ **Edit freely** - Change anything, keep block ID, history preserved
✅ **Explicit deletion** - Remove block ID to delete card
✅ **No prompts** - System never asks for confirmation
✅ **Obsidian-native** - Uses existing block reference syntax (`^block-id`)
✅ **Future-proof** - Can link to cards using `[[note#^block-id]]`
## Edge Cases
### Duplicate Block IDs
If two clozes share the same block ID (user error), the system auto-generates new unique IDs for the duplicates.
### Block IDs on Non-Clozes
Block IDs placed elsewhere in markdown (not after a cloze) are ignored by the card system.
### Moving Cards Between Files
```markdown
# file1.md
The capital is {{Paris}} ^geo-001.
# Move to file2.md (copy-paste with block ID)
The capital is {{Paris}} ^geo-001.
```
Same block ID → same card. The database updates `file_path` to track the new location.
### Special Characters
Block IDs support: letters (a-z, A-Z), numbers (0-9), hyphens (-), underscores (_)
Invalid characters are stripped during auto-generation.
---
## Design Philosophy
1. **Write naturally**: The syntax shouldn't interrupt your writing flow
2. **Context matters**: Cards stay connected to their source material
3. **Flexibility**: Support simple clozes and complex multi-part cards
4. **No lock-in**: It's just Markdown - your notes remain portable
5. **Progressive disclosure**: Start simple with `{{cloze}}`, add features as needed
#tft #softwaredesign