Hugo, and provenance as data
ADR-0001's revisit trigger fired. Move to Hugo so every page can carry who made it.
- Status
- accepted
- Date
- 2026-10-07
- Words
- xyz · 27
- Brief
- mrls
- Pen
- opus-5.5 · claude-code
Context
ADR-0001 said to revisit the static-first choice once the site needed structured metadata and generation. The October 2026 design system needs both. Every page and every paragraph carries a provenance mark (human, machine, or not recorded), the machine side records which model held the pen, and the home page shows a log of who did what. Doing that by hand in plain HTML would drift within a week.
The site is now one of several projects built mostly by agents, with mrls steering. Whatever we pick has to be easy for any model, in any harness, to work on.
Decision
- Build with Hugo. One binary, no runtime dependencies, Markdown in, static HTML out. It is already installed, and Go is the house language.
- Provenance is front matter.
byis the author of the words (mrls,xyz,both, orunrecorded),briefis who set the direction,penis the model and harness. Abyshortcode hands a stretch of a post to the other author; anoteshortcode puts a margin note in the other voice. - Pages written before this ADR carry
by: unrecordedand show no mark. We don’t guess, and we don’t draw attention to the gap. - The log is data (
data/log.yaml). Kept by hand for now; generating it from git history and agent runs is the next step. - Content domains (amends ADR-0002):
projects/replacesexperiments/,writing/replacesessays/, the log replacesnow. The manifesto stays. Decisions get their own section,adrs/. - The February prototype is kept untouched under
archive/2026-02-prototype/.
Consequences
- Pros: provenance can’t be forgotten, because the templates render it from data. Static output keeps hosting trivial. Nothing here is tied to one model or tool.
- Cons: a build step now exists. Fonts load from Google Fonts until they are self-hosted.
Revisit trigger
Revisit if the log generator needs more than a small script, or if publishing project notes needs per-project access control.
Amendment, 2026-10-10: provenance on each block
This amendment replaces the page-wide by field and the by shortcode from the Decision section. A page is no longer “by” one author. Each block says who wrote it. mrls asked for this on 2026-10-09. The reason: every page is by both of us in some way, so one mark on the page tells the reader little.
Three kinds of block
- mrls (●, a circle): mrls wrote the block. There is no source and no record of steps.
- xyz (■, a square): the machine wrote the block. There is no source and no record of steps.
- together (▲, an orange triangle): both of us had a hand in it. The page keeps the source and the final text, and nothing between them.
An author gives a block its kind with a class on the line under the block, for example {.mrls}. A heading takes the class on the same line. The classes are mrls, xyz and both. A page with no class shows no marks. A page with at least one class must class every block, or the build stops and names the block. Code blocks and margin notes are exempt.
The original behind a together block
A source goes in the post as a paragraph with the class original and the class of its author, for example {.mrls .original}. It stands right before the final block, which has the class both. The reader sees a line under the final block, such as “written by mrls, edited by xyz · show the original”. A click opens the originals. The line names two roles: who wrote the original, and who edited it. Either one can be the human or the machine. mrls editing a machine paragraph is a together block too. When the originals come from both of us, the line says “written by mrls and xyz, edited together”.
A together block with no original gets a hollow triangle (△). It means that the block is together and the original is not recorded. The manifesto and the Noj notes are like this. Nobody saved the first versions.
What the build checks
The build stops when:
- a page with classes has a block with no class;
- an original is not a paragraph, has no author class, or has no
bothblock right after it; - a
bothblock has the same text as its originals, because nothing was edited and the author’s own class is the true one; - a
bothblock shares no sentence and no half of the words with its originals, because they probably stand before the wrong block; - a page with originals has no
descriptionor nosummary, because the list rows and the feed would take their text from the opening of the page.
The count of what was left out
The build compares each original with its final block, by words. It cuts the original into sentences at a full stop, an exclamation mark or a question mark. It makes the text lower case and removes the punctuation. Then it counts:
- kept: the sentence appears in the final block, word for word;
- reworded: the sentence is not kept, but half or more of its distinct words (three letters or more) appear in the final block;
- left out: fewer than half of those words appear.
The counts go in the line under the block. The page header shows one figure: the share of the originals’ words that sit in left-out sentences. This is a count of words. It does not understand meaning, and a sentence can be left out in words and kept in meaning, or the other way round.
Limits
- A class is a declaration. Nothing checks that the author is the one named. The reader has to trust it, as with the older
byfield. - Nothing records the steps between the original and the final text. They live in the Forgejo pull requests and their review comments. The site does not copy them. If more is needed, we decide that later.
- When mrls edits an xyz paragraph in a pull request, the lane that merges it puts the text from before his commit above the paragraph as
{.xyz .original}and changes the paragraph to{.both}. mrls sees it in the same pull request. Nothing checks this step. - Only a together block counts the text that was left out. If the machine deletes a whole mrls paragraph, the site shows no trace of it. The deleted text stays only in the Forgejo history.
- A block that is fully mrls is a block he wrote himself. The site cannot tell dictated text from typed text.
- The fonts do not change by kind. Only the mark does.
The colours stay: green for mrls, purple for xyz, and a new orange token, --joint, for the triangle. The day green is a little darker (#548E37), because the old one gave the circle a contrast under 3:1 on the day background.