Skip to content

Instantly share code, notes, and snippets.

@simbo1905
Created October 25, 2026 06:55
Show Gist options
  • Select an option

  • Save simbo1905/b0ec3f07ad72db9a860dc2472a189605 to your computer and use it in GitHub Desktop.

Select an option

Save simbo1905/b0ec3f07ad72db9a860dc2472a189605 to your computer and use it in GitHub Desktop.
Add a documentation site with sections and pages to any repo via the gh CLI

Add a documentation site with sections and pages to any repo via the gh CLI

A paste-to-an-agent runbook for giving a GitHub repo (that has no site yet) a clean documentation site: markdown pages under docs/src/, grouped into a table of contents, built automatically and published at https://OWNER.github.io/REPO/. Replace OWNER, REPO and AUTHOR throughout.

1. Pages live in docs/src/

One markdown file per page. index.md is the overview every visitor lands on; each further file is one section of the site:

docs/
  zensical.toml     # the table of contents + site settings
  docs              # the build script (below)
  src/
    index.md        # Overview
    topic-one.md    # Section: Topic One
    topic-two.md    # Section: Topic Two

2. The table of contents: docs/zensical.toml

[project]
docs_dir = "src"
site_name = "REPO"
site_description = "One line on what the project is."
site_author = "AUTHOR"

nav = [
  { "Overview" = "index.md" },
  { "Topic One" = "topic-one.md" },
  { "Topic Two" = "topic-two.md" },
]

site_url = "https://OWNER.github.io/REPO/"
repo_url = "https://github.com/OWNER/REPO"
repo_name = "OWNER/REPO"

copyright = """
Copyright © YEAR AUTHOR
"""

[project.markdown_extensions.pymdownx.superfences]
custom_fences = [
  { name = "mermaid", class = "mermaid", format = "pymdownx.superfences.fence_code_format" }
]
  • The nav list is the site's chapter structure, top to bottom; every entry needs a matching file in docs/src/.
  • A page is published at /<file-slug>/ - topic-one.md becomes https://OWNER.github.io/REPO/topic-one/.
  • To add a section later: drop the file in docs/src/, add one nav line, push.
  • Pages are plain markdown; code blocks, tables and mermaid diagrams work out of the box.

3. The build script: docs/docs

A uv script - no virtualenv, no install step anywhere:

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12"
# dependencies = ["zensical"]
# ///

import subprocess
from pathlib import Path

doc_dir = Path(__file__).resolve().parent

subprocess.run(["zensical", "build"], cwd=doc_dir, check=True)

Build locally any time with uv run --script docs/docs; output lands in docs/site/ (gitignore it).

4. The deploy workflow: .github/workflows/docs.yml

name: Documentation

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: pages
  cancel-in-progress: true

jobs:
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
        with:
          python-version: "3.13"
      - uses: actions/configure-pages@v6
      - name: Build documentation
        run: uv run --script docs/docs
      - uses: actions/upload-pages-artifact@v5
        with:
          path: docs/site
      - name: Deploy documentation
        id: deployment
        uses: actions/deploy-pages@v5

5. Commit and push

git checkout main
printf 'docs/site/\n' >> .gitignore
git add docs .github .gitignore
git commit -m "docs: documentation site"
git push origin main

6. Enable Pages in workflow mode

Enable Pages in ONE call, directly in workflow build mode:

gh api -X POST repos/OWNER/REPO/pages -F build_type=workflow
gh api repos/OWNER/REPO/pages --jq .build_type    # must print: workflow

Caution: do not create Pages with a branch source - that enables legacy build mode, where GitHub's Jekyll renders the branch root (the README) instead of the workflow's artifact, and the site shows no chapter pages. If Pages was ever enabled on the repo before, switch it over:

gh api -X PUT repos/OWNER/REPO/pages -F build_type=workflow

7. Deploy and verify

gh workflow run docs.yml --ref main
gh run watch $(gh run list --workflow=docs.yml --limit 1 --json databaseId --jq '.[0].databaseId') --exit-status

Then check the live site:

SITE_URL=$(gh api repos/OWNER/REPO/pages --jq .html_url)
curl -s "$SITE_URL" | grep -oE 'generator" content="[^"]*'   # zensical-x.y.z, not Jekyll
curl -s "$SITE_URL" | grep -oE '<a href="\./[a-z-]+/"'       # the chapter links
curl -s -o /dev/null -w '%{http_code}\n' "$SITE_URL"topic-one/   # a section page: 200

If the generator says Jekyll or a section page 404s, Pages is in legacy mode: run the PUT in step 6, then gh workflow run docs.yml --ref main again. From now on every push to main rebuilds and republishes the site automatically.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment