Ordinal is my personal Markdown static site generator. I built it to turn a content/ directory into a fully linked wiki style site using Jinja templates, backlinking, and SCSS. It exists because I have taken thousands of personal notes in wiki style systems over the years, starting with Vimwiki, then Dendron, and eventually Obsidian. I wanted an easy way to put that material online without using Obsidian’s built in publishing, and with more control over structure, templates, and how everything links together.
It is not trying to be a general purpose CMS. It is meant for personal notes, project logs, technical writing, and long running thoughts/ideas.
- CLI commands for setup, generation, cleanup, and HTML snapshots.
- Front matter aware rendering for titles, domains, divisions, worked time, and timestamps.
- Wikilinks (
[[Title]]) with automatic backlink tracking. - Footnotes, tables, quotes, images/videos (with optional sizing), and external links.
- Automatic stub creation for missing pages.
- Category pages and index rendering via Jinja2 templates.
- Snapshot create/restore/delete for generated HTML.
-
main.py: is the CLI entry point. -
src/: generator logic (markdown parsing, rendering, snapshotting). -
src/templates/: holds all Jinja2 render templates. Most pages choose their template via front matter, with a few defaults (index.html, {category}.html, and wiki.html). Missing pages are generated from template.md. -
src/static/: contains SCSS and static assets. -
content/: your Markdown sources (content/articles/*.md,content/index.md). -
public/: is the generated site output. -
snapshots/: stores timestamped HTML snapshots. -
logs/: runtime logs.
- Python 3.10+
pip install -r requirements.txtsassCLI on PATH (forsrc/static/styles/main.scss→public/styles/main.css).
# set up directories
python main.py setup
# generate the whole site
python main.py generate --category all
# generate a single category (must match a folder in content/ with a {category}.md file)
python main.py generate --category articles
# remove orphaned HTML files
python main.py cleanup
# snapshots
python main.py snapshot --action create # whole site
python main.py snapshot --action create --category articles
python main.py snapshot --action restore # guided selection
python main.py snapshot --action delete # guided deletionEach Markdown file can start with YAML front matter:
---
title: "Page Title"
description: "Short summary"
division: ["Writing"]
domain: "Meta"
worked: "1.5h"
created: 2025-01-01
last_modified: 2025-01-15
template: "wiki.html" # or "section.html" for category pages
---
## Heading
Body text with [[Wikilinks]] and standard Markdown.
Wikilinks: [[Some Page]] -> some-page.html (or notes/ if present). Missing targets get auto-created from template.md.
Images/Videos: , , .
Footnotes: [^1] with definitions [^1]: Footnote text.
Default templates are selected per category ({category}.html) or overridden via template in front matter.
SCSS lives in src/static/styles/;
Static assets in src/static/ are copied into public/; content images/videos are mirrored into public/images/ and public/videos/.
Logs are written to individual .log files for each subsystem. Regeneration always overwrites public/, so the source of truth stays in content/.
Snapshots exist as a safety net. Before large edits or refactors, I take a snapshot so I can roll back rendered output without touching the source.
Ensure each category folder in content/ has a matching {category}.md to be discovered by the CLI.
Regeneration overwrites HTML in public/; keep source of truth in content/.