Markus

Get started

Install Markus, convert a page, and use it from Python.

Markus is GitHub Flavored Markdown with a small vocabulary for layout intent. You write Markdown; where Markdown cannot say what you mean, you add a colon-fenced directive.

Install

Markus needs Python 3.10 or newer. The package is anthus-markus, the module is markusmd, and the command is markus.

pip install anthus-markus

Write a page

Save this as page.md. The preview beside it is what Markus renders.

Markus

---
title: Release notes
description: What changed this week.
---

We shipped **three** improvements.

:::callout{kind="tip" title="Upgrade now"}
Every change is backward compatible.
:::

::metric{value="38" unit="%" label="Faster builds" delta="-38%"}

Preview

Release notes

What changed this week.

We shipped three improvements.

Faster builds
38%-38%

Convert it

markus convert page.md -o page.html

convert writes a complete HTML document with Markus's stylesheet inlined. Useful options:

Option Effect
--fragment Emit only the <article>, for embedding in your own template
--no-css Leave the stylesheet out and link your own
--theme NAME Apply a named theme
--minify-css Minify the inlined stylesheet
-o FILE Write to a file instead of stdout; use - as the source to read stdin

Check it

markus validate page.md
markus ast page.md

validate reports the first unknown directive, unknown attribute, or misplaced child with its line number. ast prints the validated document as JSON: front matter and an ordered list of directive and Markdown block nodes.

Edit with a live preview

markus preview page.md

preview opens a local editor with the rendered page beside the source.

Use it from Python

from markusmd import convert, parse, parse_document

html = convert(open("page.md", encoding="utf-8").read())
fragment = convert(source, full_document=False, include_css=False)

document = parse(source)           # validated AST: Document, Directive, MarkdownBlock
tree = parse_document(source)      # the same structure as plain JSON-ready data

Invalid source raises MarkusSyntaxError or MarkusValidationError, both subclasses of MarkusError, each with a line attribute.

Where to next