/_primitives · v1 set + v2 (Provenance · MarginNote · Telemetry) + MiniTool
Primitive showcase
The six display primitives that case pages compose from, plus
three from the v2 set — <Provenance>,
<MarginNote>, and <Telemetry>
— and the late-v1 addition <MiniTool> for
interactive in-prose widgets. Each is shown at two container
widths where the layout differs — full-width on the left,
narrow column on the right — so the container-query layout
switches are visible side-by-side. Most content is
illustrative; the Provenance and Telemetry demos render live
build time, commit hash, and primitive count, and the
MiniTool demos run deterministic JS locally.
<CodeChip>
Evidence pill referencing a file, repo, dashboard, commit, or
screenshot. Add a snippet slot to make it expandable.
In prose flow:
The skill catalogue is generated by build-catalog.py on every push, pushed to the marketplace via gitlab-ci/publish.yml, and verified end-to-end before release — commit a4f2b1c was the last passing run. Operational view in graylog · skills-prod.
Expandable (click to reveal snippet):
The renderer config lives at and is read by every render job.
<LiveCounter>
Big numeric callout that counts up to its target on viewport entry.
Driven by a registered @property --pf-count.
<Pipeline>
Multi-stage flow with per-stage status. Lays out horizontally in wide containers, vertically in narrow. Status: live · in-progress · planned · failed · skipped.
Wide container (full page width):
- ● 01discoverfind candidate task
- ● 02catalogcommit + describe
- ● 03shipCI publishes
- ◐ 04useteam invokes
Narrow container (~340px):
- ● 01discoverfind candidate task
- ● 02catalogcommit + describe
- ● 03shipCI publishes
- ◐ 04useteam invokes
Mixed statuses (full width):
- ● 01normalizedetect language + clean
- ● 02validate12 rule docs
- ✕ 03render3 target formats
- ◐ 04translateEN → UK/PT/ES
- ○ 05publishGWS docs/drive
<BeforeAfter>
Two-column comparison: the system's state before vs after a change shipped. Stacks vertically in narrow containers.
Wide container:
- each writer wrote their own prompt
- no shared review of agent output
- no published catalogue of skills
- each new request meant a new ad-hoc workflow
- 14 catalogued skills, single shared catalogue
- CI publishes the catalogue + tests on every push
- anyone invokes any skill via their own OAuth
- meta-skill scaffolds new skills in <30 minutes
Narrow container:
- writers wrote own prompts
- no shared review
- no published catalogue
- 14 catalogued skills
- CI publishes on push
- meta-skill scaffolds new
<DecisionTable>
N options × M criteria grid with one option marked chosen. Verdict
tokens (yes, no, partial)
colour-code automatically.
| criterion | Gemini Flash chosen | GPT-4o mini | Llama 3.1 70B (self-hosted) |
|---|---|---|---|
| cost / 1k items | cheap | partial | no |
| latency (p95) | <1.5s | <2s | >4s |
| structured output | yes | yes | partial |
| fallback path | GPT-4o mini | Gemini Flash | — |
| ops surface | none (api) | none (api) | self-host |
With no chosen option (review-in-progress):
| criterion | monorepo | polyrepo | git submodule |
|---|---|---|---|
| shared tooling | yes | no | partial |
| CI fan-out cost | linear | parallel | linear |
| PR review surface | wide | narrow | narrow |
<StabilityArc>
Half-circle dial showing the green-run ratio, plus a sparkline of
the same runs. Arc sweeps in on viewport entry by transitioning
a registered @property --pf-arc-end.
Wide container:
Narrow container:
High-stress example (flaky build):
<Provenance>
The site's per-page authorship stamp — the v2 "Site As Its Own
Provenance" primitive. Auto-injects build time and git short
hash; the caller passes whichever optional fields apply
(lastEdited, sourcedFrom,
stack, contact, scope).
Currently shipped to the home and every case page; the inline
variant is exposed for future end-of-section essay use.
Full variant (page footer · home-page shape):
Full variant (case-page shape · with last-edited, sourced-from, and disclosure scope):
Inline variant (end-of-section · for future essay use):
<MarginNote>
Polyphonic annotation block from the v2 set. Voices come from
a small closed set — past-max,
future-max, hermes,
devils-advocate, crossref — each
with its own colour tint and label. Renders inline as a styled
callout in this showcase. In essay pages with a reserved
margin column (.has-margin-notes) the aside gets
pushed out into the margin via CSS Anchor Positioning, where
supported, falling back to inline.
Five voices, inline-callout fallback (no margin column on this showcase):
The site is intentionally built in public [future-max] , with provenance stamps on every surface and its own telemetry panel rendering in the bottom-right corner. [hermes] The metaphor running through it — solar system, sun, orbits — could read as cute [devil's-advocate] if the case bodies didn't carry their weight. They do. [past-max] The whole register is metamodern — earnest without naïve, structured without rigid. [crossref]
<Telemetry>
The site's self-observability panel. Renders as a small fixed panel in the bottom-right corner of every standalone page, showing route, build time, commit, and a live count of primitive instances. Click to expand the full detail. MVP scope: static fields + DOM count. Runtime metrics (render time, bytes loaded, LCP / CLS) are deferred to a follow-up.
Look at the bottom-right of this very page — that panel is
the <Telemetry /> primitive, live. Click
the chip to expand. Same instance lives on the home, the
cases index, every case page, and the primitives showcase.
<MiniTool>
Generic interactive demo container. Provides chrome — title, setup line, input+output area, optional reset button, "runs locally" footnote — and lets the author drop in raw form markup plus a small script. Container-query: form inputs stack at <480px and switch to a responsive grid above. In-browser AI is out of scope for this primitive (rejected per the bleeding-edge roadmap) — every MiniTool runs deterministic JS in microseconds.
Wide container (form lays out as grid):
Agent run economics
Plug numbers into the four inputs; outputs recompute on every keystroke. Compares monthly bill against time saved at a chosen human hourly rate.
runs locally · 0 network calls · deterministic
Narrow container (form stacks):
Same tool, narrow
At <480px the form columns collapse to a single stack — inputs are still usable on a phone.
runs locally · 0 network calls · deterministic
Range-driven, single-output (no reset, no footnote override):
Prompt-budget slider
Pull the slider to see how many context tokens a given system prompt + N few-shot examples eats before the conversation even starts.
<TerminalCast> · shell mode
Sticky terminal window paired with a column of scene blocks.
As each scene crosses the viewport centerline the terminal
swaps to that scene's scenario; the previous one fast-forwards
to its end-state (≤700ms) before the next begins. Reverse
scrolling always replays from scratch — chaotic-navigation
friendly. Shell-mode line vocabulary: prompt · output ·
comment · tool · success · error. Placeholder
scenarios drawn from the swarm-workspace case so the
mechanic is reviewable before real case scenarios land.
Scroll through the three scenes below — the terminal stays pinned:
Installing a new app
Standing up something I've never run before is the hardest part of running a homelab — choosing the right image, finding the right port, remembering how the compose file should look, deciding which volumes to mount. The agent's catalogue carries defaults for the apps I'm likely to want; the rest is mechanical.
In the terminal beside this paragraph it does the four steps in order: pulls the image from the local registry, writes the compose fragment, brings the container up, returns the URL it's bound to. Each step is logged.
Two minutes from "I'd like that thing" to a working instance — and a ledger of what changed, so a week later I never have to wonder which container holds which volume or which port maps to which host.
Adding a contact to the PBX
The phone book is what every shared home tool gets wrong. Adding a name and a number sounds trivial until there are three handsets, one PBX, and a partner who'd like to call her aunt without remembering the country code or which of the three places to update.
The agent touches the PBX directly through its REST API, tags the contact for the right group, and the next inbound ring shows the new name. No web UI to log into, no CSV export-import, no "did you save it on the other phone too?".
The PBX has its own admin interface, but it's three nested menus deep and slower than typing the request. Convenience compounds — once any small workflow becomes a one-liner, the next adjacent one is much more likely to follow.
Updating the stack
Stack updates are where most homelabs go quiet. The maintainer doesn't quite trust them, so they don't run them, so the next one is scarier, so they don't run that one either. Six months later a CVE forces the issue and the upgrade-path is two years long.
The agent won't pull a new tag without scanning extensions for compatibility against the new version first, taking a fresh snapshot of the underlying database, and running a health check after the container restarts. Rollback is one command, and it's right there in the success line.
Once that ritual is reliable, updates become the most boring part of the week — which is exactly what you want from a long-running stack you depend on.
<TerminalCast> · ai mode
Same primitive, AI-CLI register. Persistent intro
block at the top (program · version · key hints · blurb ·
loaded context files), then each scenario is one user→AI
exchange: a bordered user-input box typed in
place, followed by a streamed assistant response with rich
formatting. New line kinds: thinking (braille
spinner that resolves to a checkmark), tool-call,
assistant (paragraph), quote,
list-item, code (fenced block with
optional lang chip). success and
error are shared with shell mode. A
status footer at the bottom shows cwd · usage ·
model; a small footnote sits below the terminal.
Scroll through the three AI scenes below:
The agent — a local AI assistant
Before any work happens, there's the greeting. The agent
loads two files of context on every session —
AGENTS.md describes what it can do, and
agent.config.json tells it which models,
paths, and credentials are available on this machine.
Everything below this paragraph is one continuous session: the intro you're looking at right now stays pinned, and as you scroll the agent will pick up a task, run it to completion, then the next task starts. Token count grows live in the status bar.
Two real exchanges below — one cross-system investigation, one drafting task. Same agent, two very different muscles, one continuous transcript.
Cross-system investigation
Refund mismatches between the payments side and the CRM are the everyday friction of a multi-system business. The interesting work isn't fixing them once you find them — it's recognising them quickly and explaining what likely caused each one to a human who needs to decide what to do next.
The terminal beside this paragraph shows the agent doing exactly that: pulling both records, comparing them, naming the gap, and ranking the plausible root causes in order of likelihood. The quoted line carries the raw evidence so the operator can verify the claim without leaving the session.
Notice that the answer ends in a question, not a command. The agent suggests two paths — patch directly, or open a ticket — and lets the operator decide. Authority stays with the human; the agent stays a sharp pair of eyes.
Drafting a weekly digest
Reading every release in a fast-moving field is the easy part — any RSS aggregator does that. The interesting work is picking the twelve that matter to a specific audience and writing them up in your voice, which is the load-bearing middle step most aggregators skip entirely.
The agent filters by relevance against a small in-repo
list of topics, picks the keepers, and streams a draft
into the writing folder ready for review.
mdx straight in, no copy-paste round-trip —
the draft lands in the same git repo as everything else.
By the time you've finished a cup of coffee, the next
week's digest is sitting in /writing/
waiting for a final read. Publish it as-is, or open it
in the editor and reshape — either way, the worst part
of the loop is done.