A compiler that turns a directory of structured language data (YAML) into study artifacts: lesson markdown and Anki spaced-repetition decks.
The name is the linguistics term — a lemma is the canonical dictionary form of a word, the headword every inflection lists under. It's also the logic sense: a small proven step toward a larger result, which is what each lesson is in a spiral curriculum.
One engine, many languages. Everything language-specific — pronunciation and
stress rules, which grammatical dimensions exist, the formality (T-V) model,
template tweaks — lives in each language's language.yaml profile as data.
The engine contains no Czech (or Spanish, or Swedish) assumptions, so a single
lemma version serves every language. Upgrade the engine once; each language
adopts the new version by bumping lemma_version when it's ready.
czech/
language.yaml # the per-language profile (pronunciation, grammar
# features, register model, template overrides)
curriculum.yaml # what each lesson teaches, dependencies, review ids
lexicon.yaml # vocabulary, one entry per word id
grammar.yaml # grammar points, one entry per grammar id
lessons/ # generated — do not edit
anki/ # generated — do not edit
# what's ready to build vs what still needs data
lemma status --lang ~/dev/czech
# build one lesson (writes lessons/NN-*.md and anki/NN-*.csv)
lemma build --lang ~/dev/czech --lesson 1
# build everything that has complete data
lemma build --lang ~/dev/czech --allbuild and status validate references: if a lesson names a vocabulary or
grammar id that isn't in lexicon.yaml / grammar.yaml yet, you get a clear
error listing exactly what's missing. That list is the authoring to-do for
that lesson — there's no lesson prose to write by hand, only data to fill in.
Generation is deterministic: the same input directory always produces the same output, so generated files can be reviewed as diffs and committed alongside the sources.
lemma status --lang <dir>— find a lesson marked NEEDS DATA.- Add its missing vocab entries to
lexicon.yamland grammar points togrammar.yaml(real target-language data: correct gender, plural, IPA, stress per the profile's rule). lemma build --lang <dir> --lesson N. Fix any remaining missing-id errors and rerun.
The generated CSV has columns: Front, Back, Example, Pronunciation,
AudioFilename, Tags. Import into Anki with File → Import, comma-separated,
mapping fields in order. AudioFilename is left blank until a TTS pipeline is
added. Cards are recognition (target→English), production (English→target),
and one grammar cloze per grammar point.
Create a directory with the four YAML files. The language.yaml profile is
where a language declares itself — see czech/language.yaml for a worked
example (7 cases, first-syllable stress, ř and friends, vy/ty). Spanish and
Swedish are planned; each will differ in that profile (no cases + rich
conjugation for Spanish; en/ett gender + pitch accent for Swedish) while
reusing this engine unchanged.
- Lexicon field names are
cs:/en:(target headword / English gloss) for historical reasons; they're just keys, reused verbatim by every language. A future rename totarget:/gloss:is a data migration, not an engine change.