Guide
Getting started
Add the documentation site to a repository in three commands, check it, preview it and commit it.
On this page
This page takes a repository with Markdown (or only a README) to a checked documentation site. It ends with the steps that only a maintainer can do in GitHub and DNS, which a pull request cannot.
Before you start
You need Node 22.19.0 or newer (or Bun 1.4 or newer), git, and a clone of the repository whose origin remote points at GitHub. The command infers most values from that remote and from the Avunu project catalog, so run it in the clone, not in a copy of the files.
The three commands
From the repository root:
npx @avunu/docusystem init --from-readme
cd docs-site && npm install
npm run checkinitwrites the shell (see below).--from-readmecopies the repository'sREADME.mdtodocs/README.mdwhendocs/has noREADME.mdorindex.mdyet; it never overwrites and never moves the original.npm installcreatespackage-lock.json. Commit it: CI installs with the lockfile frozen.npm run checkis what CI runs: a strict build, the colour-contrast gate and a crawl of every link. The site is written todocs-site/dist/.
To see the site while you work, run npm run dev in docs-site/. It builds once, serves what would be deployed on 127.0.0.1:3000 the way GitHub Pages will (trailing slashes, 404.html), and rebuilds and reloads the browser when the Markdown, the config, overrides/ or public/ change. Use --port <n> when port 3000 is taken: npm run dev -- --port 3417.
The first check on a repository whose README was written for GitHub usually finds things the site cannot render. Run npm run build -- --lenient first: it lists every document problem as a warning and still builds. Fix them, then run check, which is always strict.
What init does
init works at the repository root or inside the site folder. It never creates docs-site/docs-site, and from any other subfolder it stops and says where to run it.
It infers, in order:
The repository from the
originremote (ssh and https forms are normalized tohttps://github.com/<owner>/<name>).The entry of the Avunu project catalog whose
repomatches. If several match and none is named like the repository, it asks for--slug.From that entry:
slug,name(the catalog title),tagline(the catalog summary),platform(elsegeneral) andlicense. Thedomainis the slug with_written as-, plus.avunu.net.
Everything it chose is printed under "chosen for you". A value it cannot infer is an error that names the option to pass: --name, --tagline, --license. Values already in an existing docusystem.config.json win over inference, so running init again never resets a tagline.
It writes these files (the same list as the overview):
| File | Purpose |
|---|---|
docs-site/docusystem.config.json | The seven identity keys. See the config reference. |
docs-site/package.json | One dependency, @avunu/docusystem, and the scripts dev, build and check. |
docs-site/.gitignore | node_modules/, dist/ and .docusystem/. |
.github/workflows/docs.yml | Checks the site on every pull request that touches the docs. |
.github/workflows/docs-publish.yml | Builds on the default branch and publishes once the site is enabled. |
.github/dependabot.yml | An npm entry for the site folder, plus a github-actions entry if the repository has none. An existing file is appended to, never replaced. |
.github/workflows/dependabot-auto-merge.yml | Only if the repository has one: a small patch to its job condition that keeps pull requests for the docs site and the workflow pin out of auto-merge. |
Both workflows pin the shared workflows to the commit of the tag v<installed version>, found with git ls-remote. If that cannot be resolved (offline, or the tag does not exist) init exits 1 and names --workflow-sha; it never falls back to a tag.
Useful options:
| Option | Effect |
|---|---|
--dry-run | Prints every file and diff, writes nothing. |
--name, --tagline, --slug, --platform, --license | Sets that value instead of inferring it. --tagline and --name are needed for a repository that is not in the catalog. |
--domain <domain> | Sets the domain instead of the slug with _ written as -, plus .avunu.net. |
--site-dir <dir> | Uses another folder than docs-site, relative to the repository root. |
--docs <path> | Sets the Markdown folder, relative to the site folder (default ../docs). |
--no-workflow, --no-dependabot, --no-patch-automerge | Skips that part. |
--force | Overwrites a differing workflow, or rewrites an existing package.json's dependencies to the one package. |
init refuses to overwrite a workflow that differs from its own scaffold (a workflow copied from the earlier starter counts) and refuses a package.json that has a postinstall script or any @jxsuite/* dependency, because that is a sign of the earlier copy-the-template starter. Pass --force once you have read what it would replace. Run docusystem init --help for the whole option list.
A repository that already has a docs-site/ copied from the earlier starter follows Migrating from the earlier starter: init reads the starter's docs.config.json (so the published domain is kept), and lists the starter's files that are still in the folder.
Check the result
In docs-site/:
npx @avunu/docusystem doctorThis runs the maintainer checklist as far as a clone can show it, offline: the config, the workflows, Dependabot, the lockfile and overrides. It also prints the GitHub and DNS settings still to be made, with the exact values for this project. The doctor reference lists every check.
What a maintainer still has to do
Once per repository, none of it possible from a pull request; init and doctor print the same list with your values filled in:
GitHub Pages source: GitHub Actions.
The domain
avunu.netverified for the GitHub organization, once and before any DNS record, so that no other account can claim the subdomain if the site is ever unpublished while its record remains.The custom domain, with Enforce HTTPS once the certificate exists.
DNS: a
CNAMEfrom the domain's first label toavunu.github.io(DNS only until the certificate exists).The repository variable
DOCS_SITE_ENABLEDset totrue.Branch protection on the default branch, because every push to it publishes.
A
docs: https://<domain>line in the project's avunu.net catalog entry.
The details, and why each one is needed, are in Publishing. When a site is retired, delete its CNAME first: see When a site is retired.
Humans keep a few things
The README's link to the documentation.
Formatter and hook exclusions that cover
docs/. A pre-commit hook that stamps a copyright comment above front matter should exclude^docs/: staging repairs the stamp for the site, but GitHub and Obsidian read the unrepaired file and then show the front matter as text.A format check of the whole repository (oxfmt, prettier) over the new files.
initwrites them the way those tools print them and indents the JSON the way the repository's formatter configuration,.editorconfigor rootpackage.jsonasks, but run the check once before the pull request, or ignoredocs-sitein the formatter's configuration. See Hooks rewritedocs/.