A CLI tool that scaffolds Quarto course websites from a
single course.yaml definition file.
- Single source of truth — define your entire course (modules, artifacts, schedule, instructors) in one
course.yamlfile - Two-stage pipeline — separate generation (scaffold
.qmdstubs + Quarto config) from rendering (Quarto → HTML/PDF) - Multiple output formats — reveal.js slides, Beamer PDF, HTML handouts, PDF assignments, and a full course website from the same source
- Smart overwrite policy — stubs are never overwritten after the first run; navigation and sub-project configs are always kept up to date
- Customisable templates — override any built-in Jinja2 template locally without forking the tool
- i18n support — UI strings and labels are externalised in
lang/*.yaml(English and German included) initcommand — bootstraps a ready-to-use course repo with a sensible directory structure in one step
Requires Python ≥ 3.11.
pip install quarto-coursegenOr with uv:
uv tool install quarto-coursegen# 1. Create and bootstrap a new course project
quarto-coursegen init my-course
cd my-course
# 2. Edit course.yaml (title, modules, artifacts, instructors, …)
# 3. Scaffold .qmd stubs and Quarto config from course.yaml
quarto-coursegen generate
# 4. Fill in content in the generated .qmd files
# 5. Render with Quarto
quarto render # course website → docs/
make slides # reveal.js + Beamer PDF → docs/slides/
make handouts # PDF handouts → docs/handouts/For the full reference — course.yaml schema, command options, templates,
i18n, rendering guide, Python API — see the documentation.
course-repo/
│ ← quarto-coursegen init
├── course.yaml ← edit this: title, modules, artifacts
├── Makefile ← rendering targets (make website / slides / …)
├── assets/
│ └── styles/
├── templates/ ← built-in Jinja2 templates (customise locally)
├── lang/ ← built-in language files (customise locally)
│
│ ← optional
├── coursegen.yaml ← tool config (overrides)
│
│ ← quarto-coursegen generate
├── _quarto.yml ← generated once, then hand-editable
├── _quarto-nav.yml ← always regenerated
├── index.qmd ← generated once, then hand-editable
└── content/
├── modules/
├── slides/
├── handouts/
├── notes/
├── assignments/
└── syllabus.qmd
git clone https://github.com/xylomorph/quarto-coursegen.git
cd quarto-coursegen
uv sync --dev
uv run pytest| Layer | Technology |
|---|---|
| Language | Python ≥ 3.11 |
| CLI framework | Typer |
| Templating | Jinja2 |
| Config parsing | PyYAML + Pydantic |
| Output formatting | Rich |
| Publishing | Quarto |
| Package manager | uv |
| Testing | pytest |
quarto render docs_src/ # output → docs/src/quarto_coursegen/
├── cli.py ← Typer app (init, generate commands)
├── config.py ← CoursegenConfig, resolve_config, i18n loading
├── core.py ← pure logic (normalize, resolve, collect)
├── env.py ← Jinja2 environment factory
├── generators.py ← generate() and per-file generator functions
├── initializer.py ← init_project()
├── writer.py ← write_file() with Rich output
└── package_data/
├── skeleton/ ← files copied by init (course.yaml, Makefile, …)
├── templates/ ← built-in Jinja2 templates
└── lang/ ← built-in i18n files