Why Canary

Canary is a CLI that turns markdown into a static site: a prerendered HTML file per route, a small client router for warm in-site clicks, widgets you add with fenced YAML, and a toolchain that can rewrite markdown before it renders. This documentation is itself a Canary site. So are consoland.net and canary.consoland.net.

The problem it started from

Canary began as a plan to split a hand-rolled TypeScript site runtime — a router, a markdown renderer, nav generation from a manifest — out of one specific site's own content and branding. That site wanted to stay a genuinely hand-built markdown wiki, but also wanted to be crawlable by search engines and shareable with real link previews, neither of which a pure client-side-rendered SPA gives you for free. GitHub Pages, the intended host, only serves static files — no server-side rendering, no rewrites. Hash routing was the original workaround (the fragment after # never even reaches the server, so client JS alone decides what renders), but hash routing and real crawlability are in tension with each other.

Canary's actual answer: prerender every route to real static HTML at build time, so a cold load — crawler, direct link, social-preview scraper — gets full content immediately with zero JavaScript required, while a warm in-app navigation still gets a router smart enough to feel instant (see Render Modes). Markdown never reaches the browser in either case.

Explicit over implicit

A recurring decision throughout Canary's design: when something could be inferred automatically, prefer requiring the author to say so explicitly instead. A widget's url/src field only gets rewritten to a site-relative path if you tag it !url — nothing resolves just because a field happens to be named that. A content directory's toolchain tools are exactly what its own .toolchain.json declares, never inherited from a parent directory. canary init refuses to touch a directory that already has a canary.jsonc, rather than guessing at intent from what's already there. The pattern shows up again and again because it was chosen deliberately, not stumbled into: a little more typing, in exchange for a page's actual behavior always being visible from the file that defines it.

Built in-house, on purpose

The markdown renderer, the templating (a real Mustache implementation), the YAML parsing widgets use, and the client router are all written from scratch in this repo, readable start to finish. When a genuinely standard, language-agnostic format already exists for something — YAML, Mustache — Canary uses the real syntax rather than inventing its own shorthand, so prior experience with either transfers directly, even though the parser/templater implementing them is a one-off.

Dogfooding, all the way down

This documentation site is itself a Canary site — its own canary.jsonc, its own markdown content, built with the exact same canary build command a real project would run, source readable in docsite/ in the repo. Not a metaphor: if a real bug exists in nav generation, page rendering, or the CSS framework layer, it will show up here first. The two named public dogfood sites are consoland.net and canary.consoland.net. The in-repo Pirates of Penzance workspace is what exercised Canary end-to-end during development. A framework whose own documentation can't be built by the framework isn't trustworthy yet.