- mu is piabrota's company chart, not an umbrella, and the README header is centred. - products/ holds pirsig, alerts, ihero, gramatico, nix-os, dojo, rax and agents. The yggdrasil and asgard submodules go; our forks of them stay in the index. - PIABROTA.md follows the org as it is now: 24 public repos. - The logo is the eye that piabrota.art shows. む is drawn in pure Nix, with nix-os' pen, and checked by the flake. - .claude/skills/adr-verbatim is copied unchanged from davidondrej/cloudroom, under Apache-2.0, with credit in NOTICE.md. - The map shows the eight products, and the portfolio figure goes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
16 KiB
title, status, date, related
| title | status | date | related | |
|---|---|---|---|---|
| Documentation standard | accepted | 2026-10-12 |
|
Documentation standard
piabrota, its products, and every product they build use one documentation template. The factories document themselves the way they document what they make. Agents learn one map, and Odin's routing and docs checks work the same everywhere.
1. Umbrella template
A node is one of three kinds: company charts or umbrellas (for example, mu, or a company that
the Asgard realm kickstarted), product umbrellas (for example, yggdrasil, a client gallery) and
leaves. Company
umbrellas use 1-company/ (charter, roadmap, legal, readiness) instead of 1-product/, and hold the
standards their products inherit. Every umbrella otherwise uses this layout:
docs/
README.md landing page: what this is, and a map of the folders
1-product/ DIRECTION (human-approved)
charter.md vision, mission, principles, north star, boundaries
users.md, roadmap.md
design/ design docs, dated
legal/ products: privacy, terms, data map, deletion process
2-engineering/ HANDOVER AND BUILD
system/ the living spec: how the system works today
specs/ specs (RFC-like), dated, not edited after acceptance
changes/ change proposals with spec deltas
archive/ merged proposals
plans/ implementation plans and tasks
3-using/ for users and operators (Diátaxis)
tutorials/ how-to/ reference/ explanation/
operations/ runbooks: install, upgrade, deploy, restore, rotate keys, incidents
4-ways-of-working/ process: SDD, this standard, contributing, agent conventions
5-research/ research briefs, curated sources
6-journal/ challenges, solutions, measured results (the sagas)
7-branding/ everything identity flows from
story/ naming, mythology, narrative
identity/ palette, typography, design tokens: the design language
logo/ logo, wordmark, favicon and app icons (trademark licence)
concepts/ proposals and explorations kept for the record
voice/ tone, vocabulary, messaging pillars, copywriting rules
prompts/ image-generation and copy prompts
archify/ plot sources (see diagrams.md)
img/ the plots, drawn by archify
mockups/ mockups, as OpenPencil files
Raw sources that shouldn't be published, such as AI-generated rasters, stay out of the repo; only final vectors and exports are committed.
The numeric prefixes order the rendered navigation. 3-using/ follows Diátaxis:
tutorials teach, how-to guides solve a task, reference describes, explanation gives the why.
2. Leaf template
README.md what the repo is, how to run it, where the docs are
AGENTS.md about 100 lines: a map into docs/, never a manual
docs/
architecture.md this repo's part of the system
how-to/ repo-specific tasks
reference/ e.g. generated API docs from openapi.yaml
Direction, journal and branding live in the umbrella above the leaf.
3. Required and optional sections
| Section | Company umbrella | Product umbrella | Leaf |
|---|---|---|---|
README.md |
required | required | required |
1-company/charter.md, roadmap.md |
required | — | — |
1-company/readiness/ |
required (readiness assessments, from the Asgard realm's checklist) | — | — |
1-company/legal/ |
required before going public (licence, contribution terms, trademarks) | — | — |
1-product/charter.md, roadmap.md, design/ |
— | required | — |
1-product/legal/ |
— | optional while in development; required before deploy-prod |
— |
2-engineering/* |
— | required | — |
3-using/ |
— | required once there are users | how-to/, reference/ |
3-using/operations/ |
— | required before deploy-prod |
— |
4-ways-of-working/ |
required (the standards) | inherits from the company; may add rules | — |
5-research/ |
optional | optional | — |
6-journal/ |
required | optional (build in public) | — |
7-branding/ |
required | optional (product sub-brand); required before a product's public launch if it has its own brand | — |
AGENTS.md, docs/architecture.md |
— | — | required |
Give each folder that has no content yet a short README.md that says what belongs there.
4. How products differ
1-product/holds the product's charter (from the tier 0 kickstart), users and competitors.1-product/legal/holds the privacy policy, terms, data map (every place personal data lives: database rows, object storage originals and derivatives, zips, preview databases, backups) and the deletion process. A product that stores people's photos or emails handles personal data. Without a data map, a deletion request is guesswork, and a forgotten backup or preview branch can still hold the data. Reviewers raise a finding when a feature stores a new kind of personal data and doesn't update the data map.7-branding/is an input to the build. Implementers readvoice/for interface copy andidentity/for design tokens (the palette and type become the Tailwind theme).- The journal is optional. When you learn a lesson about the factory on a private product, record it in the operator's private instance first. Only anonymised summaries reach the public factory journal.
5. Conventions
-
Front matter on every doc:
--- title: <title> status: draft | accepted | implemented | superseded date: YYYY-MM-DD related: [relative links] style: <style id> # optional; see writing-styles.md ---Journal entries use their own front matter (see
6-journal/README.md). -
File names: dated for decisions and records (
YYYY-MM-DD-<slug>.md: design docs, specs, change proposals, plans, journal); undated for living docs. -
Decisions inside any doc:
**Decided YYYY-MM-DD:** <decision>. -
Links: relative within a repo; absolute URLs across repos.
-
Generated files (
REPOS.mdwiring blocks, doc↔code, decisions indexes) say so at the top and have a--checkmode that fails when they're stale. -
Writing style: every document has a style (legal, spec, procedure, marketing and others), set per section with overrides per folder or document. See writing styles. Everywhere: short sentences, active voice, concrete examples, no undefined jargon.
-
Plots and mockups: every plot is drawn with archify, and every mockup with OpenPencil. See diagrams.
6. Docs are checked like code
Every realm's check ladder has a docs rung. It checks:
- front matter present and valid;
- file naming and required sections per node type (§3);
- no broken links;
- prose rules for the document's style, checked by Vale (writing styles §4);
- a strict site build (once the renderer integration is in place).
As marola puts it, writing a doc is a deploy.
7. Rendering
- Renderer: Zensical, the successor to Material for MkDocs from the same
team. It reads
mkdocs.yml. Material for MkDocs is in maintenance mode, with security fixes only until about November 2026. - Stay renderer-agnostic: plain Markdown, front matter and images. Don't use renderer-specific syntax in the docs themselves. Then switching renderers means a new config file, not rewritten docs.
- Aggregation: each umbrella's site includes its children's docs at their pinned SHAs, recursively
down the tree (marola's
prepare-docs.shpattern). The site shows what has actually been validated. - Known gaps: Zensical doesn't yet have every Material plugin (redirects, blog, RSS, social cards). When the blog arrives, choose between Zensical's blog support (if it exists by then) and a separate site.
8. Public repos
The journal's scrubbing rules apply to every doc in a public repo: no secrets, no private product names or code, no client data, no raw transcripts or ledger excerpts from private runs.
9. Repository setup
Every repo on the list in scripts/check-repos.sh must pass it. It
checks:
- the repo settings: public, squash merges only, no wiki, and issues on for the factories
(
yggdrasil,asgard) and off for every other repo; - secret scanning with push protection, and private vulnerability reporting;
- the
protect-mainruleset; reuse lint;- the
AGENTS.mdstructure; - the pinned
gitleakspre-commit hook; - that the pr-bot can reach the repo;
- that no tracked file names the operator who runs the check (
operator, invariant 9): their login, their home folder's name, or a user account inscripts/orgs/local/. Docs give paths relative to the folder that holds the clones side by side, or through$HOME, and fixtures use the org. The records of past work that the script lists keep their paths as written.
Run one check with --check <name>, or name repos to check only those.
- Hidden repos are the one exception.
huldraholds the hidden benchmark suite. It is private, and the pr-bot must never be installed on it, so agents can't read it. The pr-bot is installed on selected repos only, andcheck-repos.sh'sbotcheck fails if the pr-bot can reach a hidden repo. - The founder creates repos with
scripts/new-repo.sh --org <org> [--private] [--ci <piece>,...] <repo> "<description>"…, using one token: fine-grained, short-lived, owned by the org, repository access "All repositories", with Administration, Contents and Workflows read and write. A real run confirmed this token on 2026-10-18; a token limited to selected repositories is untested. It runs every check first: if any named repo already exists, or a piece or the config is wrong, nothing is created. Each new repo gets a first commit with aREADME.md, whose first paragraph is the description, the licence files and the base CI, then the setup below, so agents only ever see a protected repo. If a step fails after a repo is created, the script names the repo and says it is not protected. Then the founder adds each public repo to the pr-bot's installation, as the script's output says.--privatemakes a hidden repo, which is never added. Another org copiesscripts/orgs/piabrota.jsontoscripts/orgs/<org>.jsonand changes the values (the keys). An operator's own account works the same way with"owner": "user". Its config lives inscripts/orgs/local/, which git ignores, and is never committed (the differences). - Each step also runs alone, with the same
--org.create-repo.shcreates empty repos.add-licences.shandadd-ci.shwrite the licence files and the base CI into a folder, and never overwrite a file. These three take--check, which runs every check and changes nothing.setup-repo.sh --org <org> <repo>applies the setup below to an existing repo. It is safe to run twice and fixes drift, such as an extra ruleset rule.create-repo.shandsetup-repo.shneed the same token asnew-repo.sh. - The base CI is pre-commit.
add-ci.shwrites.pre-commit-config.yamlfrom pinned pieces, and.github/workflows/lint.yml, which runs the hooks on every file and gitleaks over the history.gitleaksalways runs. The config'scilist, or--ci, adds pieces:reuse,markdown,shell,actionsandyaml(the pieces). The convention:lint.ymlhas the required joblint, andci.yml, the repo's own tests, has the required jobtest.setup-repo.shrequires the check of each of these workflows that the repo has. The org's Actions allowlist must hold both oflint.yml's actions,actions/checkoutandactions/setup-python, at the SHAs it pins, orlintnever starts; a pin bump updates the allowlist too. - Existing repos get the same base CI. An agent prepares each repo's
base-cibranch in a fresh clone underrollout/, beside themucheckout.add-ci.sh --upgradereplaces the old gitleaks-only config, and formatting-only fixes make the hooks pass;scripts/md-same-text.shproves each Markdown fix changes no text. Then the founder runsscripts/rollout-ci.sh --org <org> push <repo>…. It pushes the branch, because the pr-bot can't push workflows, and opens the PR as the pr-bot. Running it again after a rebase updates the branch and reuses the PR. Ifbase-cimoved on GitHub since the last push, it refuses that repo and prints both SHAs: the agent folds the move in and acknowledges it withgit update-ref refs/rollout-ci/base-ci <GitHub's SHA>, then the founder runs push again. After the merge, push does nothing, and the founder runsrollout-ci.sh --org <org> protect <repo>…, which runssetup-repo.sh, solintbecomes required. It skips and names any repo whosemaindoesn't holdlint.ymlyet. Both modes are safe to run twice and need the same token asnew-repo.sh. - A realm repo holds three more things. Its own
ci.yml, with the required jobtest, which runs the realm's tests with the template tests set to fail, not skip (helheim-go has one template test that still skips in CI, until its backlog item B-057 lands). Aci.ymlin each template (jobtest), on the stack's pinned images. And a readiness assessment against the realm readiness checklist, filed in the Yggdrasil repo. Thesharedcheck ofcheck-repos.shfails when a realm's copy of a shared file, such asdevcontainer/checks/docs.sh, differs fromhelheim-go's. - A lint config bends only for a reason. When a linter and the house style disagree, ask whether the house style gets real value from its own way. If yes, the linter bends: the shared config gets a setting, or a repo excludes files that aren't docs or config, such as test inputs, in its own file, with a comment that gives the reason. If no, the files change to the linter's default. Nothing is excluded from gitleaks or reuse. The bends and their reasons.
- Agents never create repos or change their settings. They reach GitHub only as
piabrota-pr-bot, throughscripts/as-bot.sh, which can't; run the checks withscripts/as-bot.sh --read all scripts/check-repos.sh. - Agents scaffold a new Rust component with
scripts/scaffold-component.sh <repo> "<job>" <clone>, in a clone of a new repo, on top of the first commit thatnew-repo.shmade. It adds the files fromscripts/templates/rust-component/, rendered byminijinja-cli, appends its sections to the README that commit holds, keeps the pre-commit config as it is, and leaves the architecture doc's responsibilities for a person to write. The result goes through a PR. - Reusable tooling lives here until it has a better home. Any script that could run again goes
in
scripts/, with a test inscripts/tests/. When it should move, the Yggdrasil v0 plan's "Carried beyond v0" table says where and when. The repo scripts move into Yggdrasil'sgithubremote, behind a hard approval point (change2026-10-12-remote-creates-repos), and the scaffold moves into Odin'sinit.