The build pipeline

A build is a token passed through nine ordered stages. Each stage either enriches the build or halts it with a diagnostic naming the file at fault; there is no partial output. The whole thing is one Elixir pipeline, and you can drive it programmatically if the CLI is not enough.

What each stage does

stage responsibility
Load Reads cherry.exs, content collections, portfolio, CV, and static files into one in-memory site.
Validate Frontmatter against the schemas, date sanity, duplicate slugs, token overrides against the theme manifest. Fails loud, names the file.
Transform Content components expand first, then markdown becomes HTML: tables, footnotes, autolinks, and class-based syntax highlighting coloured by theme tokens.
Layout Resolves the theme chain, renders every page through its template (EEx or HEEx), injects the SEO head, token overrides, and custom.css.
Feeds feed.xml (Atom), feed.json, sitemap.xml, canonical URLs, all derived from your configured url.
Machine llms.txt plus a markdown mirror beside every page: the machine surface.
Search Builds the search index. search: "cherry" needs no Node anywhere; "pagefind" shells out after Emit instead.
Emit Writes the tree. The only stage that touches disk.
Post Post-emit hooks: Pagefind indexing, anything that needs the finished tree.

Determinism is a gate, not a goal

The same input tree produces the same output bytes, every time, on every platform. Cherry's own CI double-builds its fixture sites and the demo on every commit and fails if a single byte differs. What that buys you:

  • Diffs mean something. If the deployed tree changed, you changed it.
  • Caches work. Unchanged pages hash identically across builds.
  • CI can prove drift. Build twice in your own pipeline and compare; a mismatch is a bug in Cherry, and we treat it as one.

Where the randomness went

No timestamps in output, no build IDs, no "generated at" footers, stable ordering everywhere a map could have leaked iteration order. The discipline is invisible until you need it, and then it is everything.