Mu is for authors of online courses. It allows you to cross-compile courses from one format to another. For instance, you can write your courses in a human-friendly format, such as Markdown, and convert them to a format that can be imported in your learning management system (LMS).
Supported formats:
- Markdown: single file with Pandoc-flavoured header attributes.
- Folder Markdown: organized folder structure with multiple Markdown files.
- HTML 5
- Open Learning XML (OLX) from Open edX.
Check out the course.md file to see what an actual course in single-file Markdown format looks like.
This fork extends the original overhangio/mu with features designed for team collaboration and better course organization:
- Multi-file course structure: Organize large courses across multiple Markdown files in a hierarchical folder structure
- YAML frontmatter support: Store metadata (title, order, visibility) in frontmatter
- Automatic ordering: Control content order with
orderfield in frontmatter - Smart index files: Course, chapter, and sequential
index.mdfiles contain only metadata; body text is ignored with warnings
- Debug mode: Set
MU_DEBUG_FOLDER_MD=1to inspect merged markdown during compilation - Improved documentation: Comprehensive guides with examples for folder markdown format
- Complete example course: Full multi-chapter, multi-sequential example in
examples/course_folder/
pip install mu-courses
Since the PyPI version may not include the latest features and fixes, you can install directly from the repository:
-
Clone the repository:
git clone https://github.com/overhangio/mu.git cd mu -
Create a virtual environment:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install in editable mode with development dependencies:
pip install -e .
Alternatively, if you only want the latest features without development tools:
bash pip install -e .
Conversion from and to Markdown is handled with the help of Pandoc. Thus, a recent version of Pandoc is required when working with Markdown documents. See the corresponding installation instructions.
# Markdown -> OLX
mu /path/to/course.md /path/to/olx/
# OLX -> HTML
mu /path/to/olx/course/ /path/to/course.html
# HTML -> OLX
mu /path/to/course.html /path/to/olx/course/
...
When writing Markdown files, the generated documents will include non-standard (but widely recognized) header identifiers to store the course unit attributes.
For large courses, you can organize your content across multiple Markdown files in a folder structure instead of a single file. This is useful for team collaboration and better file organization.
Folder structure:
course_folder/
├── index.md # Course metadata and description
├── chapter1/
│ ├── index.md # Chapter metadata
│ ├── sequential1/
│ │ ├── index.md # Sequential metadata
│ │ ├── unit1.md # Content units
│ │ └── unit2.md
│ └── sequential2/
│ └── ...
└── chapter2/
└── ...
File format: Each Markdown file can include optional YAML frontmatter for metadata:
---
title: My Unit Title
order: 1
hidden: false
---
Metadata fields:
title: Display name (uses filename if not specified)order: Numeric ordering (default: 9999, sorted ascending)hiddenordraft: Set totrueto exclude from compilationorg,course,url_name: Available at course level for OLX metadata
Important: Course, chapter, and sequential index.md files should contain only frontmatter. Any text in the body of these files will be ignored with a warning. If you need to add notes or comments for organization, use HTML comments:
---
title: Chapter 1
order: 1
---
<!-- This is an internal note and will be ignored -->Only unit files (non-index markdown files within sequentials) should contain actual content in their body.
Usage:
# Compile folder markdown to single markdown
mu /path/to/course_folder /path/to/compiled.md
# Or directly to OLX
mu /path/to/course_folder /path/to/olx/Debug mode:
To debug the folder markdown compilation process, set the MU_DEBUG_FOLDER_MD environment variable:
MU_DEBUG_FOLDER_MD=1 mu /path/to/course_folder /path/to/olx/This will keep the temporary merged markdown file and print its location to the console, allowing you to inspect the intermediate merged markdown before it's converted to the target format.
Example courses are provided in the examples directory.
For each unit type, we indicate whether reading from (R) and writing to (W) the corresponding format are supported.
| Unit type / Format | OLX | HTML/Markdown |
|---|---|---|
| Collection | ✅ | ✅ |
| Video | ✅ | ✅ |
| Free text question | ✅ | ✅ |
| Multiple choice question | ✅ | ✅ |
| Raw HTML | ✅ | ✅ |
- Multiple choice questions are always rendered as checkboxes, and not as single-choice questions.
Install development requirements:
pip install -r requirements/dev.txt
pip install -e .
Run tests:
make test
Reformat your code with black:
make format
Re-generate course samples:
make examples
Upgrade pinned requirements:
make upgrade-requirements
Publish a new release:
python setup sdist
twine upload dist/mu-courses*.tar.gz
Want to add a new type of content to your course? Here's a general approach:
- Start by creating a new type of unit in the mu/units.py module.
- Add such a unit to the examples/course.md sample file, using your desired syntax.
- Implement the corresponding HTML reader in the mu/formats/html/reader.py module. You should draw your inspiration from the
Reader.on_sectionmethod. You are strongly encouraged to add at least one unit test to tests/test_html.py. - Now, implement the HTML writer in the mu/formats/html/writer.py module. This should be as simple as creating a new
Writer.on_yournewunitnamemethod. Add a unit test. Verify that your writer is generating the right HTML output by runningmake example-html. - Implement the corresponding OLX reader and writer in mu/formats/olx/writer.py and mu/formats/olx/writer.py. Check that the OLX course is correctly generated when you run
make example-olx.
Would you like to use Mu with an LMS that is not currently supported, or with your own course format? You will need to implement two Python classes: a Reader and a Writer.
In Mu, converting from one format to another works as follows:
Reader -----------> unit.Course object ---------> Writer ------------> final path
generates sent to writes to or directory
- The new
Readerclass must implement the methods frommu.formats.base.reader.BaseReader. - The new
Writerclass must implement the methods frommu.formats.base.writer.BaseWriter.
You should make sure to add unit tests to the tests/ directory.
At the moment, all reader/writers must live in the mu package. In the future, we expect that it will be possible to auto-discover different reader and writer packages.
This project was created by Matthew Brett (@matthew-brett) and funded by a grant from the Chan Zuckerberg Initiative. The project is maintained by Régis Behmo from Overhang.IO. Would you like to report an issue or request a feature? Then open a new GitHub issue.
This work is licensed under the terms of the GNU Affero General Public License (AGPL).