On this page
Manage the unified multi-project documentation assembly and deployment
#selfdoc assembly
Manage the unified multi-project documentation assembly and deployment
#assembly init
Create and initialize the assembly GitHub repository with workflow and configuration files. Creates a private GitHub repo, pushes initial files via the Contents API, creates a Cloudflare Pages project if credentials are available, and sets GitHub secrets for deployment authentication.
Effect: mutating · consequential (prompts before running; --approve-consequential skips)
#Grants
| Kind | Name | Reason |
|---|---|---|
| proc_mutate | create-repo | creates a new private GitHub repository under the configured owner; repository creation is not undone by rerunning the command |
| proc_mutate | create-pages-project | creates a Cloudflare Pages project on the configured account, claiming its *.pages.dev subdomain |
| proc_mutate | set-secret | writes Cloudflare deployment credentials into the assembly repository's GitHub Actions secrets |
#assembly push
Dispatch a GitHub Actions workflow to rebuild this project in the documentation assembly. Detects the source repository, resolves the latest git tag as the version reference, and sends a repository dispatch event to the assembly repo with the project slug, version, and commit SHA.
Effect: mutating
#Grants
| Kind | Name | Reason |
|---|---|---|
| proc_mutate | assembly-dispatch | triggers a GitHub Actions workflow on the assembly repository, which rebuilds and republishes the live documentation site |
#assembly status
Show the status of recent assembly build workflow runs on GitHub. Queries the assembly repository for recent workflow runs using the GitHub CLI and displays their status, conclusion, and timing information for monitoring deployment progress.
Effect: read_only
#assembly rebuild
Dispatch rebuild workflows for every project registered in the assembly. Fetches the projects.json manifest from the assembly repository, then sends a separate GitHub Actions repository dispatch event for each registered project to trigger a full documentation rebuild.
Effect: mutating
#Grants
| Kind | Name | Reason |
|---|---|---|
| proc_mutate | assembly-dispatch | triggers a GitHub Actions workflow on the assembly repository, which rebuilds and republishes the live documentation site |
#assembly retire
Retire a project from the unified assembly: remove its [[project]] block from the roster and, in the same commit, delete its whole site subtree, all of its manifests and its membership record, then dispatch a shared-only rebuild so the listing, feed, sitemap and search index stop naming it.
Effect: mutating · consequential (prompts before running; --approve-consequential skips)
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--slug | str | required | Slug of the project to retire; it is removed from the roster and every path it owns in the assembly is deleted |
#Grants
| Kind | Name | Reason |
|---|---|---|
| proc_mutate | assembly-commit | pushes a commit to the assembly repository's deploy branch, which is the content the live documentation site serves |
| proc_mutate | assembly-dispatch | triggers a GitHub Actions workflow on the assembly repository, which rebuilds and republishes the live documentation site |
#assembly redirects
Generate a Cloudflare Pages _redirects file for this project that redirects standalone documentation URLs to the corresponding paths on the unified assembly site. Requires a project slug and assembly base URL as inputs, prints the redirect rules to stdout.
Effect: read_only
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--slug | str | required | Project slug used as the URL path segment in the assembly site structure | ||
--docs-base | str | required | Base URL of the assembly documentation site used for generating redirect targets |
#assembly generate-shared
Generate the shared cross-project elements for the assembled documentation site. Reads per-project manifest JSON files, merges post overlays, and produces a homepage, blog index, navigation JSON, RSS feed, XML sitemap, robots.txt, a site-wide llms.txt linking to each project's own, a root 404 page, a security headers file and the redirect worker in the site output directory.
Effect: mutating
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--site-dir | str | required | Path to the combined site output directory where shared HTML files are written | ||
--manifests-dir | str | required | Path to the directory containing per-project manifest JSON files for the assembly | ||
--docs-base | str | optional | Base URL the Atom feed's entries are written against. Only the feed reads it: every entry there is an absolute URL by protocol. Nothing a reader clicks does -- the generated listing, the blog index and the 404 address the site relative to their own page, so they resolve under any mount. The sitemap does not read it either: it is generated from --canonical-base whatever this says. | ||
--canonical-base | str | required | Absolute canonical base URL of the assembly site, from topology.docs_base (e.g. 'https://docs.smmh.dev'). Required: it is the one hostname that serves content and every other host 301s onto it, it is the base of every sitemap entry, and it targets the rel=canonical links on the homepage and blog index, so it cannot be root-relative like --docs-base. | ||
--legacy-blog-host | str | optional | Hostname of a retired blog subdomain (e.g. 'blog.smmh.dev') to 301 onto the canonical blog URL. Omitted when no such subdomain exists. | ||
--home-slug | str | optional | The roster's home project: the one project served at the site root. Its pages are left out of the generated listing and out of nav, and every site-level directive region it emitted is re-rendered from the current manifests. Omitted means the tree carries no home project (which the deploy path never does -- the roster requires one). |
#assembly integrate
Integrate one dispatched project into the assembly repository checkout and push the result. Builds the cloned source project, replaces its subtree under site/, refreshes its manifest and membership record, regenerates the shared cross-project elements, rebuilds the search index, then commits and pushes with a re-sync retry loop so concurrent deploys converge instead of clobbering each other. This is the whole body of the generated deploy workflow.
Effect: mutating
Dry run: not supported — 'assembly integrate' cannot be previewed: every step after the first reads what the step before it wrote -- the shared generator reads the manifests the graft just copied, the search index reads the pages it just wrote, and the commit reads the tree all of them produced. A recorded run writes none of that, so the preview would stop at the first effect and misrepresent everything after it. To see what an integration would produce, use 'assembly preview'.
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--slug | str | optional | Project slug being integrated; the site subtree is site/ | ||
--version | str | optional | Version of the project being integrated, recorded in projects.json and the commit message | ||
--ref | str | optional | Git ref (tag) the source project was cloned at, recorded in projects.json | ||
--source-repo | str | optional | Source project repository (owner/name), recorded in projects.json | ||
--scope | str | optional | What this dispatch replaces: 'full' (the whole project subtree plus this project's posts), 'posts' (only this project's posts, at the site-level site/blog/ | ||
--canonical-base | str | required | Absolute canonical base URL of the assembly site, from topology.docs_base. Required: it targets the redirect worker and the rel=canonical links. | ||
--legacy-blog-host | str | optional | Hostname of a retired blog subdomain to 301 onto the canonical blog URL. Omitted when no such subdomain exists. | ||
--assembly-dir | str | optional | Path to the assembly repository checkout being updated. Omitted, the current directory is used | ||
--source-dir | str | optional | Path to the cloned source project. Omitted, | ||
--branch | str | optional | Assembly repository branch the deploy commits and pushes to. Omitted, 'main' is used | ||
--attempts | int | optional | How many times to re-sync with the remote and retry the push before failing. Omitted, 3 attempts are made |
#Grants
| Kind | Name | Reason |
|---|---|---|
| proc_mutate | assembly-commit | pushes a commit to the assembly repository's deploy branch, which is the content the live documentation site serves |
#assembly verify
Assert every property a built assembly tree has to have before it is deployed: that the roster, the site subtrees and the manifests name the same projects, that each manifest's pages and posts were actually emitted, that the shared cross-project artifacts exist and parse, that every internal reference, sitemap entry, feed link and cross-project link resolves, that every page has a title and a canonical, and that no unresolved directive or per-project routing file survived. The deploy runs this itself before it pushes; this command is how you run the same assertions by hand against a checkout.
Effect: read_only
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--assembly-dir | str | default: . | Path to the assembly repository checkout to verify | ||
--canonical-base | str | required | Absolute canonical base URL of the assembly site, from topology.docs_base. Required: it is what tells this site's absolute URLs from everybody else's, and without it half the assertions would pass by not looking. |
#assembly preview
Assemble every named local checkout into a preview tree and serve it on loopback. Builds each project with the toolchain running this command, grafts the output exactly as the deploy does -- the home project at the site root, everybody else under their slug -- writes the roster, membership record and manifests the assembly keeps, generates the shared cross-project files and the site chrome, rebuilds the search index, runs the real pre-deploy verification and prints its report, then serves the result with a working 404. Nothing leaves the machine and nothing is published: this is the look-before-you-ship step.
Effect: mutating
Dry run: not supported — 'assembly preview' exists to produce output you look at: a built site tree and a server over it. A recorded run would write no tree, and every step after the build reads what the step before it wrote -- the graft reads the build, the shared generator reads the grafted manifests, the index and the verification read the pages. Run it without --dry-run; it publishes nothing.
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--repo | list[str] (unique) | default: [] | Path to a project checkout to include, served under the slug its selfdoc.json declares. Repeat once per project. The home project is named by --home instead and must not be repeated here. | ||
--home | str | required | Path to the home project's checkout: the one project served at the site root rather than under a slug. Required -- a site needs a front page, and there is no default. | ||
--out | str | required | Directory the preview tree is written to. Required. Refused when it sits inside a git working tree at a path git does not ignore, because a generated site dropped into a checkout is untracked noise in every session sharing it. | ||
--port | int | required | Port to bind on 127.0.0.1. Required and has no default: which port a long-running local server occupies is a decision the caller states rather than inherits. | ||
--canonical-base | str | required | Absolute canonical base URL of the assembly site, from topology.docs_base (e.g. 'https://smmh.dev'). Required, and it is the DEPLOYED base rather than the loopback one: the preview shows the pages with the canonicals, sitemap entries and cross-project links they would ship with, and verifies those. | ||
--legacy-blog-host | str | optional | Hostname of a retired blog subdomain the generated worker 301s onto the canonical blog URL, passed through to the shared generator exactly as the deploy passes it. Omitted when no such subdomain exists. | ||
--build, --no-build | bool | required | Whether to build each checkout before grafting it. Required with no default: --build is the honest preview of what would ship, --no-build re-assembles whatever each checkout already has in docs/_build, which is what a second look after one edit wants and the only way to iterate without rebuilding every project. Choosing is the point -- a preview of a stale build tree is a preview of nothing in particular. | ||
--theme | str | optional | Build every checkout under this theme instead of the one its selfdoc.json declares, for this preview only. Omitted, every project stays on its configured theme, which is what a deploy does. This exists to judge a theme on the real pages: the same site, every project flipped at once, without editing a config anywhere. Validated against the theme registry, and refused with --no-build, because a theme is baked into build output and re-grafting an existing tree cannot restyle it. |
#assembly sync-workflow
Regenerate the assembly repository's deploy workflow from this project's configuration and push it. The deployed workflow is a generated artifact like any other: without this it stays frozen at whatever the template said when 'assembly init' ran. Pushes only when the content actually differs.
Effect: mutating
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--pin-selfdoc | str | optional | selfdoc version the regenerated workflow pins its 'go install' to. Omitted, the running binary's own version is used. The release path states it instead, because the binary a post-release hook finds was built before the version bump and its own version names a release the module proxy cannot serve yet. | ||
--pin-pagefind | str | optional | pagefind version the regenerated workflow pins its toolchain install to. Omitted, PyPI's current release is used: pagefind is a CI-only tool nothing here installs, so there is no local version to read. |
#Grants
| Kind | Name | Reason |
|---|---|---|
| proc_mutate | assembly-commit | pushes a commit to the assembly repository's deploy branch, which is the content the live documentation site serves |