Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

3 · The deck format

A deck is a plain-text Markdown file. You can write one in any editor with no tooling, read it back at a glance, and because it’s real Markdown, it renders sensibly anywhere else too: a preview pane, your file host, GitHub.

When you write a deck by hand, initialize it once before it appears in the picker:

alix deck init ~/decks/my-deck.md

The command adds stable deck and card IDs without rewriting the authored content. A valid id: deck-<token> in the opening frontmatter marks the file as an initialized deck. The deck- prefix on the value is what carries the meaning: it is how alix tells its own decks apart, and the same prefixed string travels everywhere the id appears, in a frontmatter key, a card marker, a filename, a prerequisite reference, or an error message. Markdown without that prefixed id is never listed or modified, so ordinary documents with ## headings can sit in a decks folder untouched. Generated, imported, received, and tutorial decks are initialized when they are created.

Choosing a card shape

Read the material before choosing its card shape. The shared guide below names the useful choices and distinguishes structural matches from judgement calls. The sections after it show the exact syntax for each shape.

Which card shape suits which material. Read the material first, then pick the shape; do not pick a shape and bend the material into it.

Some rows are structural: the material has a property the shape exploits, and any other shape wastes it. Some are judgement: more than one shape is defensible and the choice is yours. The difference is marked, because a rule that claims uniform authority gets followed badly exactly where thought was needed.

materialshapekindwhy
Paired items: a word and its meaning, a term and its definition, a symbol and its name.A card table: a GitHub pipe table with <!-- cards --> on the line directly below it, no blank line between, one row per pair, columns front, back, and an optional note.structuralOne row per pair, and each row’s Recognize options come from its own column, so the wrong answers are real siblings and cost no AI call. Prose wastes both.
Ordered steps that must be reproduced in order: a recipe, an algorithm, a procedure, a verse.reveal: line, with one step per answer line.structuralOrder is graded, and the answer uncovers one line at a time so recall is stepwise rather than all-or-nothing. A flip card cannot test order at all.
An answer that cannot be typed: a diagram, a circuit, a glyph, notation.input: drawstructuralThe learner sketches and self-grades against the reveal. Typing a diagram is not a check, it is a workaround.
A statement turning on one term, where the sentence around it is the cue.Cloze: hide the span with <!-- blank: span hidden="..." --> on its own line below the answer.judgementThe context does the cueing, so recall is anchored where it will be used. If nothing in the sentence is a natural target, this is a plain card wearing a disguise.
A fact whose common confusions are known and nameable.Authored choice: a task list with one - [x] and one or more - [ ], closed by <!-- choices: single --> on the line below it, ideally two or three (or choices: single in frontmatter, once for the deck).judgementThe distractors are the teaching. Write them only if you can say what mistaken belief each one represents; if you cannot, the shape is doing nothing.
A term that must be recalled from either side: vocabulary, symbols, names.direction: bothjudgementOne authoring act, two cards. Reach for it when both directions are genuinely useful, not by default: it doubles the review load.
Anything else: a definition, an explanation, a cause, a comparison.A plain card: ## front, answer lines below.judgementThe default, and not a failure. Most material has no structure to exploit, and a plain card drilled well beats a clever shape drilled badly.

Rules that hold whatever the shape:

  • Every card needs at least one answer line.
  • Most cards deserve a > [!NOTE] note: an example, a caveat, a mnemonic, or why it matters. Never a restatement of the answer. The badge line is required; a blockquote without one is a quotation and belongs to the answer. A card table is the exception: its note is the note COLUMN, and a blockquote below a table does not parse at all.
  • A choice card’s note names the option’s claim or mistaken premise, never its number, letter, or screen position. Options shuffle between appearances.
  • Every <!-- ... --> line trails its card: it goes directly below the card’s last content line, with no blank line between them, and never above an answer line, an option list, or a table.
  • An invocation binds the block directly above it, so it sits on the line immediately below the last option or row. <!-- cards --> takes card directives after it, an at: locator or a reveal mode, but never a blockquote: a card table’s note is its note column. <!-- choices: single --> takes a > [!NOTE] note after it.
  • One idea per card. Split compound facts rather than nesting them.
  • No two cards may test the same fact. Vary what is asked; do not rephrase.

review: and sampling: are not shapes. They modify how an existing deck is served and are documented with the other directives.

Cards

A card starts with ## at column 0, the front (the question). The lines beneath it are the answer (the back), written plainly, and may span several lines:

## What is the capital of France?
Paris.

## Name the three additive primary colors.
Red
Green
Blue
<!-- reveal: line -->

A physical newline inside an ordinary flip answer is a Markdown soft wrap: the adult and mobile clients display it as a space, so you can wrap long source lines for editing without creating visual gaps on the card. Add <!-- reveal: line --> when the lines themselves are the learning sequence; line reveal and line typing preserve them individually.

Inline formatting

Card fronts, answer lines, and note prose support **bold**, *italic* or _italic_, ~~strikethrough~~ (the double-tilde pair exactly; a single or triple tilde run stays ordinary text), and inline `code`. Inline code is verbatim, so `**literal**` displays the asterisks instead of bold text.

Formatting has two projections: styled display and plain content. Grading uses the plain content, so type Paris, not **Paris**. To keep emphasis markers literal, escape them with backslashes such as 2\*3\*4, or wrap the text in inline code such as `2*3*4`. Run alix doctor <deck> to find card text that will render as emphasis.

Inline escaping follows the CommonMark rule: a backslash before any ASCII punctuation character yields that literal character, and a backslash before anything else (letters, digits, spaces) stays a literal backslash.

A complete [label](destination) displays as just the label, styled as a link; the brackets, parentheses, and destination never reach the screen, and the deck file keeps what you wrote. Destinations are inert on study surfaces: a card is for recalling, not browsing. Every destination form displays the same way, including relative paths and #anchor fragments (alix has no heading anchors, deliberately: a card’s identity survives editing its text, so nothing may address a card by its words).

Emphasis works inside a label and across a whole link. Grading compares the label text, so type see the docs, not the syntax. An incomplete pattern such as [brackets] alone stays ordinary prose, an escaped \[label](d) stays literal, and inline code or a fence keeps the whole syntax verbatim. Autolinks (<https://...>) are covered under “HTML in a deck”.

A link-definition line ([label]: destination) in an answer is deck metadata, not content: it never displays and is never graded, and a card whose whole answer is definitions fails loud as answerless. Reference links resolve against the deck’s own definitions and render like inline links, in all three GFM forms: [text][label], [text][], and bare [text]. A footnote definition ([^label]: at the start of a line) is the one bracket-definition spelling a deck rejects outright: footnotes are not supported, and the line fails loud rather than silently becoming prose or metadata; inline [^1] (and a regex class like [^abc]) stays ordinary text. Labels match case-insensitively with interior whitespace collapsed, a label never resolves across deck boundaries, and a reference whose label is undefined stays ordinary prose.

LaTeX math

Use $...$ for a formula inside prose:

## Why does $a^2 + b^2 = c^2$ describe a right triangle?
It is the Pythagorean theorem.

Use $$...$$ for display math, either on one whole logical line or as a block: a line holding only $$ opens the block, the next such line closes it, and everything between is one formula. A ```math fence carries its body the same way. All three render identically:

## What is the Gaussian integral?
$$\int_{-\infty}^{\infty} e^{-x^2}\,dx = \sqrt{\pi}$$

## State the quadratic formula.
$$
x = \frac{-b \pm \sqrt{b^2 - 4ac}}
         {2a}
$$

A card that opens a $$ block without closing it fails to load, with an error naming the opener’s line. A closed pair in section or context prose renders as the same display formula. An unmatched opener on those surfaces stays ordinary text and does not consume the lines after it.

An opening dollar must touch the first formula character, and a closing dollar must touch the last one. A closing inline $ cannot be followed by a digit, so $5 and $10 stays literal currency. GitHub’s backtick-anchored spelling also works: $`x^2`$ renders exactly like $x^2$, with the backtick-quoted body as the verbatim formula. Escape a literal dollar as \$. Unmatched dollars and $$...$$ surrounded by prose also stay literal. Dollars inside inline code or fenced code (other than a math fence) are always verbatim.

Graphical clients render recognized math with the shared RaTeX renderer. If the delimiters are valid but the LaTeX is malformed, the card still loads and shows the source with a visible “math could not render” message. alix doctor <deck> reports the card line, formula snippet, and renderer error.

Grading uses the content between the delimiters, so type x^2, not $x^2$. Adding or removing math delimiters does not change a card token or stale its cached augmentations. Generated output that otherwise parses as a deck is checked before placement; malformed math cannot replace an existing deck.

A ## only starts a card at column 0 and outside a code fence. A ## that is indented, or sits inside a fenced block, is ordinary answer content, so a Markdown heading in a sample, a shell comment, or a Dockerfile line needs no escaping:

## What does this script print?
```bash
echo hi
## this line is just part of the answer, inside the fence
```

A fence closes only on a delimiter of its own character at least as long as its opener (the CommonMark closing-length rule); that is what lets the four-backtick fence above contain the three-backtick one.

Multi-line fronts

When the question itself spans more than one line, a --- divider marks where it ends and the answer begins:

## What does `lo` control in this signature?
def bisect_right(a, x, lo=0, hi=None)

---
The lowest index the search considers; entries below `lo` are ignored.

Here the front is two lines (the prose question plus the code it’s asking about), and without the --- alix couldn’t tell where the question stops and the answer starts. (A one-line question needs no divider: the answer just follows on the next line, as in the cards above.)

The divider’s shape is strict, so a stray break fails loudly instead of silently joining a card: a front divider sits directly above its answer, with a blank line (or the card’s own heading) above it, once per card. A break is three or more of one marker, -, *, or _, with spaces or tabs allowed between them, so ---, ----, - - -, ***, and ___ are one construct: the position decides what a break means, never how you spelled it. Dividing a card’s front from the answer below it is the only meaning a break has, so a break anywhere else is a parse error, a break alone between blank lines included: alix has no standalone horizontal rule, and the shape is reserved. A <!-- plain --> on the line below a break keeps it literal whatever its spelling, and so does a backslash on the line itself (see Escaping): \---, \----, \- - -, \***, and \___ are all literal text.

Choice cards (task lists)

A bare GitHub task list is a literal checklist: mappings are opt-in. Name the mapping on the line below the list to make it a choice card:

## Which number is prime?
- [ ] 4
- [x] 5
- [ ] 6
<!-- choices: single -->

Under choices: single the one [x] item is the correct answer. Alix shows only that answer at Recall and expects it at Reconstruct; the [ ] items are distractors shown with it at Recognize. Every option is used, so the card needs no AI choices augmentation and is skipped by that augment target. The Rust core shuffles the options: their order stays fixed while one question is on screen, then receives a fresh seed when the card reappears or a new study session starts. As with any shuffle, two appearances can still produce the same order by chance.

choices: single demands exactly one checked item and at least one unchecked item; any other shape fails loudly. Use -, *, or + bullets, with [x] or [X] for the answer. Task lists inside notes or a card’s front before the --- divider render as static checkboxes rather than interactive choices.

choices: multiple is select-all-that-apply: every [x] is a correct option and the reviewer picks all of them. A choices: multiple list that checks exactly one item is legal: a one-answer select-all is a fair question when the learner must discover how many options are correct.

A deck built of choice cards declares the mapping once in frontmatter instead of once per card: choices: single (or choices: multiple). A per-card invocation overrides the deck default, and <!-- plain --> on the line below one task list keeps that one literal.

Card tables

Flat material at scale (a vocabulary list, countries and capitals, dates) can be one Markdown pipe table instead of a ## block per fact. A bare pipe table renders as a real aligned table: the delimiter row’s alignment colons set each column’s alignment, short rows pad with empty cells, and long rows truncate to the header width. In an answer it is one block, like a quotation: under <!-- reveal: line --> it takes a single reveal rather than arriving a pipe line at a time, and Reconstruct never asks you to type pipe syntax, so a card whose whole answer is a table asks you to explain it instead. It never becomes cards on its own; <!-- cards --> on the line below maps it, and <!-- plain --> below one table keeps it literal. A table that declares neither is still rendered plain, and alix doctor flags it until you write <!-- cards --> or <!-- plain --> below it: the two meanings are too far apart to leave to accident, so the file says which one you meant. Each row is a card: first column front, second column back, optional third column note. The header row names the columns for whoever reads the file; it is never displayed and never tested:

| word      | meaning   | note                 |
|-----------|-----------|----------------------|
| purported | angeblich | often in legal prose |
| feasible  | machbar   |                      |
<!-- cards -->

The table must start at column 0 with a header row and a delimiter row (alignment colons are fine), exactly like GitHub renders it; every line starts and ends with |. Inside cells, inline formatting and math work as in any card text. A table inside a fenced code block stays literal text.

Give a table a title by putting a ## heading directly above it, with nothing between them but blank lines:

## Verbs of arguing
| English   | German      | usage                |
|-----------|-------------|----------------------|
| to refute | widerlegen  | eine These widerlegen |

The heading names the group and, when present, is the row card’s only context line; it is a title only when its body is empty, so a heading with an answer under it is an ordinary card that happens to be followed by a table. The table’s directives, including its own ID, trail the table on their own lines below it; a directive on the heading line is a parse error.

At Recognize, a table card’s wrong options are drawn from its own column: the other rows’ answers are the distractors, so a table needs no AI choices augmentation and no authored options (though both take precedence if present). A row only gets a pick when its column offers at least three other distinct values; smaller tables stay reviewable at the other depths.

That column sampling is on by default. Turn it off for a table whose rows are not interchangeable (a mixed list, a table of one-off facts) with <!-- sampling: off --> among its directive comments, or set sampling: off in the frontmatter to make that the deck’s default and re-enable single tables with <!-- sampling: on -->. A table with sampling off and no other option source is simply not offered at Recognize, and alix doctor reports a sampling: key that can affect nothing.

Identity works like card IDs, per row. alix deck init (or opening the deck for review) mints one container ID line after the table, and a short stamp at the end of each row, after the closing pipe:

| purported | angeblich | often in legal prose | <!-- r:4k2x9w -->

Renderers drop cells beyond the header count, so the stamps stay invisible in a rendered view while keeping the source columns aligned. Both kinds of marker are machine-maintained, never hand-authored, and they travel with their row, so sorting, inserting, and editing rows preserves review history.

Directive comments between the table and its ID line (direction, reveal, input, sampling) apply to every row. direction: both doubles each row into a reversed card, which samples its options from the front column.

The format is deliberately narrow: two or three columns only, no cloze blanks or images inside cells, and nothing but directive comments between a table and the next card. Anything outside that shape is a parse error rather than a guess. And a table earns its place at dozens of rows; under roughly ten cards, plain ## cards read better and can carry everything a card can.

Notes and quotes

A blockquote whose first line is one of GitHub’s five alert badges is a note: shown after you answer, never part of what’s tested. The badge sits alone on that line, and the > lines under it are the note’s body:

## Why does TCP open with a three-way handshake?
To agree on initial sequence numbers in both directions.
> [!NOTE]
> SYN, SYN-ACK, ACK: each side learns the other's starting sequence.

The five are [!NOTE], [!TIP], [!IMPORTANT], [!WARNING], and [!CAUTION], spelled exactly as GitHub spells them. Each opens its own callout with a chip naming it, coloured from whatever theme you are using rather than from GitHub’s palette. Several notes on one card stack in the order you wrote them. Spelling them GitHub’s way is the point: a deck pasted from a repository keeps its meaning without editing.

Every other blockquote is a quote, and a quote is content. It belongs to the answer and reveals with it, so you can finally put someone’s actual words on a card:

## What did Dijkstra say about testing?
That it shows the presence of bugs, never their absence.
> Program testing can be used to show the presence of bugs, but never
> to show their absence.

A quotation is one block however many > lines you wrapped it across, and it reads as one: a rule down its left edge marks it off, and the > markers are gone. Under <!-- reveal: line --> it takes a single reveal rather than arriving a marker line at a time, and at Reconstruct you are never asked to type it: typing someone else’s words back tests transcription, not understanding, so you type the answer’s own prose while the quotation stands beside it. A card whose whole answer is a quotation has nothing to type, so Reconstruct asks you to explain it instead.

A badge alix does not recognize, a badge in the wrong case, or a badge with text after it on the same line is a quote, exactly as on GitHub. That is a quiet change of meaning, so alix doctor names it rather than leaving you to find it. A badge whose body is empty, or only blank > lines, draws a warning too and shows nothing.

A note trails its card the way a directive comment does, so a <!-- reveal: line --> may stand above one, and answer content may not come after one. Prose or a quotation below a note fails loud pointing at the badge line: move the content above the note.

Keep the answer to the thing you want to recall, and put the why, the example, or the mnemonic in a note.

A cloze card can give one blank a note of its own, so a note that names an answer doesn’t give it away on the sibling cards. See a note for one blank.

Sections and sub-cards

Heading depth decides a line’s role. ## is a card front, # opens a section, and ### through ###### are sub-cards.

# — section context

A single-# heading opens a section. Its text, plus any prose that follows it outside a card, is the shared context for every card below it until the next #.

A deck body starts with a heading. Before the first one there is no section to belong to and no card to be part of, so a line there is an error rather than text that lands nowhere. A deck of plain cards needs no section at all: opening with ## is fine, and those cards simply have no context. Whatever a deck is about goes in title: and description:.

# Ocean depths

Pressure rises by about one atmosphere per ten metres.

## What is the pressure at 30 m?
About 4 atmospheres.

The web app shows a card’s section heading as a dim one-line title above the question. The first card you ever meet from a section opens the whole section in a sheet under the question, once; after that, in this sitting and every later one, the title line, the c key, or the review menu’s Context entry opens it. The Android app shows the heading as a tappable pill that opens the section in a sheet, and opens that sheet by itself under the same rule (see The mobile app). The kids client does not expose section context.

A section heading is a heading, nothing more. It takes no directives and no card ID, because a section owns no card to bind either to.

A section runs to the next # heading. To end one without opening another, write a bare #: a # with no title opens an empty context, so the cards after it carry none until the next titled # (a sub-card chain does not cross it either). Prose under a bare # belongs to the new, empty section, exactly as it would under a titled one.

A bare # needs a blank line above it, like any other block. Attached directly under a card’s own lines it is an error, since a reset there would silently truncate the card.

### to ###### — sub-cards

A card written one level deeper than the card above it is a sub-card of it: the same card syntax, gated on the parent. A sub-card stays out of review until its parent has graduated (reached FSRS’s review phase, see Scheduling), so a deck can teach the general case first and release the specialisations once it has stuck.

## What does a TCP handshake establish?
An agreed starting sequence number in each direction.

### Why does the client resend SYN if no SYN-ACK arrives?
The SYN may have been lost; nothing else can distinguish that from a slow peer.

Depth stacks: #### hangs off the ### above it, down to ###### at the deepest, matching ATX’s own ceiling. One rule is enforced when the deck is read, so a mis-indented heading fails loudly instead of silently becoming a top-level card: a sub-card needs its parent one level shallower actually open, so a ### with no ## above it, or a #### directly under a ##, is an error. Seven or more hashes are not a heading at all and stay ordinary answer text, as CommonMark reads them.

A ## closes every open sub-card chain, and a # clears the chain entirely.

Ignoring a card

A bare <!-- ignore --> among a card’s trailing comments takes the card out of learning without taking it out of the file: it is never served for review, the exam does not ask about it, and it counts in no total. Its id line stays, so removing the word later brings the card back with its history. An ignored card is the one card that may have no answer yet.

## Why does the borrow checker reject this loop?
<!-- ignore -->
<!-- id: card-3g12jfjv4pypppsrx5wvtx65y5 -->

The word trails its card like every other directive: above the card’s content it is an error, and outside any card it is one too. After a card table it applies to every row. alix stats shows the count and alix list marks the cards [ignored].

Reserved Markdown shapes

Four Markdown spellings have no alix meaning and fail loudly with the line number and a suggested rewrite, instead of showing their markers to the learner: a setext === underline directly beneath a prose line (write an ATX #-prefixed heading), four-space/tab indented code opening after a blank line or a heading (wrap the code in a ``` fence; ordinary paragraph and task-list continuation lines are unaffected), a nested > > quote (notes are flat, one > deep; put literal > text in a fence), and a blank-surrounded thematic break, whatever its spelling and wherever it sits (delete the line, or keep it literal with <!-- plain --> below it). Inside fenced code every shape is literal, as always. A trailing-two-space hard break is not a spelling at all: content lines shed trailing whitespace when the deck is read, so the break changes nothing about what a card shows. The file keeps it anyway, because GitHub renders it; see the next section.

Normalization: the bytes alix writes back

Editors add bytes you never typed, and no deck needs them, so alix settles on one form instead of carrying whatever arrived. Whenever alix writes a deck file, it normalizes it. That covers initializing a deck, stamping a new card id, augmenting, receiving a shared deck, and every alix doctor repair:

  • a leading byte-order mark is dropped;
  • a line’s trailing carriage returns are dropped, so CRLF endings become LF, everywhere in the file;
  • trailing spaces and tabs are removed;
  • invisible bytes with no rendered role are dropped from prose: form feed, DEL, a byte-order mark anywhere past the file start, a carriage return in the middle of a line, and the two bidi override characters LRO and RLO. Every invisible character that does render something keeps its place: zero-width joiners and non-joiners (Persian and Indic text), the zero-width space and word joiner (wrap control), the soft hyphen, variation selectors (emoji presentation), and the bidi isolates and embeddings that make mixed-direction text read correctly.

Two things survive. A hard line break, meaning a line ending in two or more spaces, is kept and written as exactly two spaces, so a deck that renders as several lines on GitHub still does. And a code fence keeps the trailing blanks on every line it owns, its opening and closing lines included; only its line endings change. Those bytes are code rather than layout, and alix identifies a card partly by them, so trimming a fence would quietly detach the card from its cached notes and distractors.

alix never rewrites a file it had no other reason to touch, so a deck you only read is left exactly as it is. If an editor puts those bytes back after the deck was initialized, alix doctor <deck> --normalize rewrites it.

Because the kept invisibles are, by definition, impossible to see, alix doctor tells you about them: one calm per-deck note with counts by class (bytes inside a well-formed emoji stay out of the count, since you can see the emoji). The note is informational; a Persian, Thai, or emoji-rich deck is supposed to look like that. Doctor warns in exactly two cases, because these two have no legitimate reading: tag characters outside a flag emoji, which encode invisible text, and bidi override characters inside a code fence, where the rendered order of the code can differ from the stored order.

Typed answers are graded on what the screen shows: a character that paints no ink (a zero-width joiner your emoji picker added, a soft hyphen, a variation selector) never decides pass or fail, on either side of the comparison.

HTML in a deck

alix renders Markdown, never HTML, so a tag shape is reserved rather than silently shown as text: a < directly followed by a letter, or </, on any deck surface fails to load, naming the line, the column, and the two outs (wrap literal markup in backticks, or escape a lone bracket as \<). Ordinary brackets are unaffected: a < b, a<3, and <1> are plain text.

Three HTML spellings do render, each with a fixed meaning:

  • Autolinks. <https://alix.study> and <user@host> display as the bracket-free URL styled as a link, with no navigation attached: the deck is a study surface, not a browser.
  • The styled subset. <sub>…</sub>, <sup>…</sup>, and <ins>…</ins> display as subscript, superscript, and underline on every client, tags dropped. One element opens at a time on a line, and each pair must close in order; a mismatched, doubled, or unclosed pair is a tag-shape error. Grading compares the inner text, so type H2O for H<sub>2</sub>O. A dropped tag still separates what stood on either side of it, so x<sup>2</sup>_i_ italicizes instead of reading as one word.
  • Entities. The full HTML5 named set (&amp;, &euro;, …) and the numeric forms &#65; / &#x41; decode to their characters on display, per CommonMark. Anything that is not a complete, valid entity stays literal. A decoded character is content, never markup: &#42;x&#42; shows *x* without italics, and &lt;div&gt; shows <div> without the tag-shape error. Markup beside an entity is judged on the spelling in the file, where the neighbouring character is & or ;, so &Aopf;_x_ italicizes x. Grading compares the decoded text, and the deck file keeps the entity exactly as you wrote it.

The usual protections apply on top: inline code, fenced blocks, and math bodies keep every one of these spellings literal, a whole-line <!-- --> comment protects its interior, and a complete image destination in angle brackets (![diagram](<a b.png>)) is an address, not a tag.

Title, and deck-wide settings

A deck’s name, its deck-wide settings, and its machine-maintained deck ID all live in frontmatter: a ----fenced YAML block at the very top of the file. Both fences are the same shape: a line starting with exactly ---, with spaces or tabs allowed after it and no indentation before it.

The name comes from title:. A deck without one falls back to a condensed form of its trace: sentence, and a deck with neither is named by its filename stem. A # heading is never the name: it is section context for the cards below it.

---
id: "deck-9w2c7x4k1m8q3z5t0v6b2n4d8f"
title: French vocabulary, chapter 4
description: The verbs from the chapter's dialogue, plus their prepositions.
authors: [Alex, "Claude (Opus 5)"]
license: CC-BY-4.0
created-at: 2026-07-31
reveal: line
review: sequential
---

description is a short summary. The web picker shows it when you open a deck’s drawer; nothing else reads it.

format-version is a reserved key: the version of the deck format, not of the deck itself. A deck that does not declare it is format version 1, so alix never writes the key. Declaring format-version: 1 by hand is accepted; alix refuses a deck declaring any other number rather than guessing at a format it does not know.

authors takes one value or a list; title, description, license, and created-at are single strings, by convention an SPDX identifier and an ISO 8601 date for the last two. Put both people and any AI that helped in authors. These five are yours to fill in and alix never changes them.

Apart from id, frontmatter carries only what differs from the defaults, and a command-line flag always overrides it. The full set of frontmatter and per-card keys gets its own Directives reference chapter.

Key order never matters and yours is never diagnosed. Frontmatter alix itself writes follows one canonical order: authored keys first (title and description up front), machine lines like id last. To rewrite an existing deck into that order, opt in with alix doctor <deck> --repair-frontmatter-order. The same applies to a card’s trailing comment machinery (any order parses, the id last is canonical): --repair-comment-order rewrites each machinery run into the canonical order without touching content. A run holds recognized machinery only, so an invocation reads down through the card’s own directive comments to the block above them, and an editorial comment or an unknown key ends the run: the invocation below one maps nothing and fails loud. One invocation consumes the block it maps, so a second below the first fails the same way.

Escaping

Because ##, >, a break line of any spelling, and the fence markers are structural, an answer line that must start with one literally is escaped with a leading backslash: \##, \>, \---, \***. The backslash is consumed; the line displays without it. For a break line of any spelling, <!-- plain --> on the line below keeps it as content too.

## How do you write a second-level heading in Markdown?
\## Section title

Why editing a deck is safe

Every initialized deck and card carries a stable identity. alix deck init writes the deck ID as id: deck-<token> in frontmatter and each card ID as a <!-- id: card-<token> --> line. If you later add a card to that initialized deck, opening review or augmentation assigns the missing card ID. Those tokens, not the text, are what your review history hangs on. You don’t type or manage them; alix adds and maintains them after you explicitly initialize the file.

Because identity is the token and not the words, you can edit anything (reword the question, fix a typo in the answer, rewrite a note, reorder cards) and its history follows. The only thing that starts a card’s history over is deliberately replacing it. (alix doctor warns if an id line goes missing, for instance if an external tool stripped the HTML comments.)

So a deck is safe to refactor freely: your progress rides on the token, not on the words.

Your personal file

A deck you didn’t write is still yours to annotate. Anything alix or you add to someone else’s deck goes into a personal file beside it, never into the deck itself: spanish.md gets spanish.local.md. The deck file stays byte-identical, so you can pull an updated copy of it without losing your work, and your notes never leak back when you share the deck. The personal file is the deck’s .local.md twin, following the same .local rule as alix.local.toml.

It is an ordinary Markdown file with one extra frontmatter key naming the deck it belongs to:

---
for: deck-9w2c7x4k1m8q3z5t0v6b2n4d8f
---

<!-- note: card-3f7k2m9q1x8w5z0t6v4b2n8d7c -->
> the "cuenta" is the tally you finally add up

## a gap the exam found
the answer
<!-- id: card-5k1m8q3z5t0v6b2n4d8f7c2x9w -->

Two kinds of block live there, in any order:

  • A note: a <!-- note: <card-id> --> marker followed by > lines. Those lines are appended to that card’s own note when you review it. If you want a label above your note, write a ## heading; it is yours, alix never writes or rewrites one.
  • A card, written exactly like a deck card and closed by its own <!-- id: --> line. It joins the session after the deck’s own cards and is drilled and scheduled like any other, but it does not count toward the deck’s card count.

The two machine lines sit at opposite ends of their block on purpose. A card’s id closes it, because the id names the card itself. A note’s marker opens it, because a note is an attachment: it has to say which card it belongs to before anything below it means anything.

Nothing in this file is a copy of anything in the deck, so nothing here can go stale. The card id is the only link, and it never changes.

alix writes this file for you: the tutor’s Make this a card, its Make a note, and the exam’s remediation cards all land here. You can also edit it by hand. Personal files are never listed as decks of their own, and alix share leaves them at home in both directions: a bundle you send never carries one, and a bundle you receive can’t overwrite yours.

A note addressed to a card that no longer exists is left alone rather than dropped, and alix doctor reports it.