The tree

The directories of a repository carry its structure. No file declares its kind or its id.

ThisCarries
a directorywhat it contains
a filename stem, or a directory namethe id
the depththe kind
order: in the index.md of a containerthe order
the front matterthe title, and the other fields of the node

Kinds by depth

PathKind
index.mdthe repository root
<domain>/index.mda domain
<domain>/<section>/index.mda section
<domain>/<section>/<topic>/index.mda topic
<domain>/<section>/<topic>/<deck>.mda deck
<domain>/checkpoints/index.md, and the index.md in each directory under ita checkpoint folder
any other .md file under <domain>/checkpoints/a checkpoint

The root, a domain, a section, a topic and a checkpoint folder are containers. A container is a directory with its own index.md. A deck and a checkpoint are single files.

The app shows a topic as a chapter in its menu.

Three reserved names

NameMeans
index.mdthe file of a container
checkpoints/the checkpoints of a domain, beside its sections (Exams)
assets/pictures, beside any index.md (Math, figures and assets)

What the tree reads, and what it ignores

  • At the root, every directory is a domain, and it must have an index.md.
  • In a domain, every directory is a section, except checkpoints/.
  • In a section, every directory is a topic.
  • In a topic, every .md file except index.md is a deck. A subdirectory other than assets/ is an error.
  • The tree ignores a .md file where only directories belong. So a README.md at the root, or a note beside the sections, is not content.
  • The tree ignores a directory whose name starts with ., so .github/ is safe.
  • The tree ignores a file that is not .md and not a picture, for example LICENSE.
  • A picture (.png, .jpg, .jpeg, .webp, .svg) outside an assets/ directory is an error.

So keep only domains at the root, beside index.md, the files the tree ignores, and an optional assets/.

A subdirectory in a topic gives this fault:

ERROR ./math/alg/linears/more: `more` is a directory, and only files belong at this depth, so nothing can ever reach it: move it up a level

Two limits hold for every file. A .md file is 512 KB at most: a deck that long is many decks. A path is 16 levels at most below the root, its own name included, so phy/checkpoints/mit/2020/fall/q.md is six levels. The checker reads nothing deeper.

ERROR ./math/alg/linears/big.md: this file is 600000 bytes, over the 524288-byte cap on a `.md` file: split it into more decks
ERROR ./math/checkpoints/a/b/c/d/e/f/g/h/i/j/k/l/m/n/q.md: this sits more than 16 levels below the repository root, and nothing is read that deep: move it up

On disk, the checker reads files and directories only. It does not follow a symbolic link, and it refuses one. It also refuses a device, a pipe or a socket:

ERROR ./math/alg/linears/link.md: `link.md` is a symbolic link, and the check does not follow one: put the file itself in its place

Every container must hold at least one child:

ERROR ./math/alg/linears/index.md: this topic holds nothing: give it children, or take it out

Ids

An id is the filename stem of a file, or the name of a directory. The deck solving.md has the id solving. The topic linears/ has the id linears. Nothing declares an id.

  • An id is unique per kind in a domain. Two topics in different sections cannot both be basics. Two decks in different topics cannot both be intro.
  • Checkpoints are free from this rule. Two checkpoint folders can each hold a 2020.md.
  • Some ids are reserved. The app uses these words in its routes, so a domain, a section, a topic or a deck cannot take them: index, today, practice, account, cards, checkpoint, checkpoints, exam, exams, reference, test.

Use lowercase letters, digits and - in an id. The id is part of the address of each page in the app.

Two decks with one id:

ERROR ./math/geo/lines/solving.md: `solving` is already the id of a deck, at math/alg/linears/solving.md: ids are unique per kind

A reserved id:

ERROR ./math/alg/test/index.md: `test` is reserved, because the app routes on it: rename this one

The id of a domain in the app

In the app, the id of a domain is not its directory name. It is a hash of the repository address and the directory name, for example bfa9e982. So two repositories can each hold a math/, and their progress never mixes. The ref is not part of the hash, so a branch and a tag of one repository give the same domain.

The address folds before the hash: https://GitHub.com/Alice/Algebra.git and github.com/alice/algebra give the same id. The directory name does not fold: Math/ and math/ are two domains.

A rename

A rename changes an id, and the ids of everything under it. A refresh in the app finds a renamed deck by its content and moves the progress with it. Publish and add to Stemin gives the rules. A change of order changes no id, so you can reorder at any time.

order:

The index.md of a container lists its children by id, in the order the learner meets them:

---
title: Electromagnetism
order: [fields, direct-current, components, dc-analysis, electromagnetic, alternating-current]
---

The checker holds order and the directory to an exact match, in both directions:

FaultMessage
a child that order does not list`extra` is here and `order` does not list it: add it to `order`, or mark the file `draft: true`
a name in order with no child`order` names `missing`, and no file or directory here carries that id
a name twice`order` names `solving` more than once
a name of a draft`order` names `extra`, which is marked `draft: true`: take it out of `order`, or take the draft mark off

order is optional. Without it, the children sort by id, in byte order: uppercase before lowercase, and 10 before 9.

The order of a domain lists its sections. It never lists checkpoints.

To add a deck, make two changes: add the file, and add its id to the order of its topic.

draft: true

Put draft: true in the front matter of a file to hold it back. A draft is outside the order match, and the app never builds it.

---
title: Phasors
draft: true
---

It works on every kind: a deck, a checkpoint, or the index.md of a container. On an index.md, it holds back the whole container and everything in it.

Front matter

Each file can start with YAML front matter between two --- lines. The first line of the file must be ---.

KindFields
the rootformat (required), author, description, order
a domaintitle, lang (required), author, labels, order, draft
a sectiontitle, tiers, order, draft
a topictitle, tier, requires, order, draft
a decktitle, draft
a checkpoint foldertitle, order, draft
a checkpointtitle, draft

The root and the domain explains the fields of the root, the domain and the section. References and derivations explains requires.

A field that is not in this table is an error. The checker names the fields that the file takes:

ERROR ./math/alg/linears/solving.md: `titel` is not a field of a deck: a deck takes title, draft

YAML that does not parse is an error in every file, a deck and a checkpoint too:

ERROR ./math/alg/linears/solving.md: front matter will not parse: did not find expected ',' or ']' at line 2 column 1, while parsing a flow sequence at line 1 column 8

An index.md holds front matter and nothing else. Text after it is an error.

A node without a title: shows its id. A deck without a title: shows its full id in the app, for example bfa9e982/alg/linears/solving. Give each node a title.

A full example

This is the tree of the Stemin Foundations repository, shortened:

index.md                              the root: format, author, description, order
README.md                             ignored
math/                                 domain       id: math
├── index.md                            title, lang, labels, order
└── alg/                              section      id: alg
    ├── index.md                        title, tiers, order
    ├── linears/                      topic        id: linears
    │   ├── index.md                    title, tier, order
    │   ├── solving.md                deck         id: solving
    │   ├── matrix-form.md            deck         id: matrix-form
    │   └── glance.md                 deck         id: glance
    └── quadratics/                   topic        id: quadratics
        ├── index.md                    title, tier, requires, order
        └── quadratic-formula.md      deck         id: quadratic-formula
phy/                                  domain       id: phy
├── index.md
├── eam/                              section      id: eam
│   ├── index.md
│   ├── fields/                       topic        id: fields
│   │   ├── index.md
│   │   ├── field.md                  deck
│   │   ├── electric-field.md         deck
│   │   └── assets/                   pictures for the decks of this topic
│   │       ├── gravity-field.svg
│   │       └── capacitor-field.svg
│   └── direct-current/               topic        id: direct-current
│       ├── index.md
│       ├── charge.md
│       └── ohms-law.md
└── checkpoints/                      the checkpoints of the domain
    ├── index.md                        order
    └── eam/                          checkpoint folder
        ├── index.md                    title, order
        └── direct-current-quantities.md   checkpoint

The two index.md files of the root and of math/:

---
format: 3.0.0
author: Alice Smith
description: Mathematics and physics, from first principles to exam practice.
order: [math, phy]
---
---
title: Mathematics
lang: en
labels: { reference: Formula, references: Formulary, derivation: Proof, checkpoint: Exam, checkpoints: Exams }
order: [alg]
---