Boris briefing
This page is the map. The public site is about Grok. The machinery underneath is Boris 0.8.1, a Zig content compiler. The Mach-O arm64 binary is ./boris in the repository root (about 18 MB, linked only against libSystem). Upstream: github.com/drawmeanelephant/boris.
What Boris is
Boris compiles a directory of Markdown pages into a static HTML site, a JSON IR, optional RAG packs, an llms.txt, RSS, and a sitemap. It also speaks publication plans for GitHub Pages, Standard.site / ATProto, and Nostr (NIP-23). This repo uses the HTML path only.
It is not a generic static-site generator in the Jekyll sense. Pages form a graph. parent: is a real edge. [[wiki-links]] are real edges. A link to a missing page fails the build (exit 1), it does not render as a dead <a>.
Commands that matter here
./boris --version
./boris --help
# HTML site (what you want)
./boris --input content --html-dir dist --theme themes/boris
# same thing, named
./boris build --input content --html-dir dist --theme themes/boris
# validate, no artifacts
./boris validate --input content --theme themes/boris
# graph health (findings do not fail by default)
./boris check --input content
# impact of touching one page
./boris impact index --input content
# normalized publication plan
./boris plan --profile boris.json
# watch + loopback preview (default port 8090)
./boris watch --input content --html-dir dist --theme themes/boris --serve --port 8090
Bare ./boris with no flags builds HTML under dist/ as target default. This repo always passes --input, --html-dir, and --theme so the command is obvious.
Exit codes: 0 success, 1 content validation, 2 usage, 3 I/O or system.
Tree
boris # the compiler (keep this)
boris.json # publication profile
content/ # pages; entity id = path without .md
index.md # trunk
grok.md
models.md
products.md
company.md
twitter.md # pre-X history (parent: company)
people/elon.md
people/maye.md
people/figures.md
meta/boris.md # this page (entity id: meta/boris)
meta/prompts.md # verbatim user prompts + aardvark limericks
*.assets/ # images for that page only
people/*.assets/
themes/boris/
layouts/main.html # required slots: {{head}} {{content}}
assets/css/boris.css
dist/ # generated; do not edit
Frontmatter
One Markdown file is one page. Flat YAML only: no nested maps, no sequences except tags and relations. Supported keys:
| Key | Role |
|---|---|
title |
Page title, {{title}}, search |
id |
Override the path-derived entity id |
parent |
Structural parent entity id |
tags |
[a, b] |
relations |
[relates_to=other-id] (and the other relation verbs the compiler allows) |
summary |
Short description |
status |
Publication status |
published_at |
Date string |
Entity ids that differ only by case collide. parent must point at a real page and must not cycle. The trunk (index) has no parent.
Body syntax Boris actually understands
- Markdown, including tables, fenced code, and images.
- Wiki-links:
[[entity-id]],[[entity-id|label]],[[entity-id#heading-id]]. - Asides, line-start tags only:
<Aside kind="note">
...
</Aside>
Allowed kind values: note, tip, info, warning, danger.
- Includes:
{{include path/to/file.md}}. - Images on a page live in a sibling
<stem>.assets/directory. Fromcontent/index.mdthat iscontent/index.assets/earth.jpg, referenced asindex.assets/earth.jpg. No.., no absolute paths, no symlinks. - Do not mix
.mdwith.textileor.cookin the same content root unless you pass--textileor--cooklangand the tree is that format only.
There is no layout frontmatter. Layout is selected by --theme, --html-layout, or --layout-rule (id:, glob:, role:trunk|satellite).
Layout slots
themes/boris/layouts/main.html is the only layout. Keep exactly one of each referenced slot.
| Slot | Purpose |
|---|---|
{{head}} |
Compiler-owned head extras (required if you ever verify / Nostr / Standard.site) |
{{content}} |
Rendered page (required) |
{{title}} |
Frontmatter title |
{{nav}} |
Graph forest |
{{breadcrumb}} |
Parent chain |
{{toc}} |
In-page headings |
{{footer}} |
Compiler footer |
{{asset-url assets/css/boris.css}} |
Theme file under themes/boris/ |
The gold card in the bottom-right corner is ordinary HTML in that layout. It is supposed to stay visible. Do not delete it to "clean up" the Grok site; it is the on-ramp for the next agent. The header search reads _boris/search/search-index.json (Boris writes that on every HTML build). The user's original prompts are on The brief.
Modes you should not trip over
Boris will refuse combinations that mix publication kinds. The ones that bite:
--out/--no-ragselects JSON IR, not HTML.--rag/--rag-dirselects RAG packs, not HTML.--contextselects a context bundle, not HTML.--rssis its own mode and conflicts with HTML.--sitemapis HTML-only and needs--site-url.--watch,--incremental,--jobsare HTML-only.validatewrites nothing and will not accept those export flags.
Other families, unused here but in --help: standard-site (ATProto / Atmosphere publication, never implicit) and nostr (plan, sign, publish). Signing reads a key once from stdin. Never put a secret in argv, the profile, or the environment.
If the build fails
- Read the error. Validation problems are almost always a missing wiki-link target, a bad
parent, duplicateid, or illegal frontmatter. - Run
./boris validate --input content --theme themes/boris. - Run
./boris check --input contentfor graph hygiene. - Staging lives in
dist.boris-stageand is committed only on full success. Leave it alone.
A successful HTML build writes dist/**/*.html plus copied assets. Incremental / watch also write dist/.boris-cache/manifest.json.
Init, if you ever start over
./boris init scratch
writes a trunk page, two satellite guides, this theme skeleton, boris.json, and standard-site.json. This repo already replaced that starter with the Grok site. Do not run init in the repo root or it will refuse / clobber.
Version pin
$ ./boris --version
boris/0.8.1
Help text self-describes as: Boris — Zig content compiler (HTML site + IR + optional RAG).