diff --git a/.github/workflows/docs-lint.yml b/.github/workflows/docs-lint.yml index ce7f12ec2..e48e8bb67 100644 --- a/.github/workflows/docs-lint.yml +++ b/.github/workflows/docs-lint.yml @@ -1,8 +1,10 @@ -# Lints the documentation source in docs/**: markdownlint for style -# and lychee (offline) to verify that every relative Markdown link -# resolves to a real file. Portable relative links are what the Hugo -# module mount on docs.docker.com resolves, so broken ones would break -# the downstream build (see docs-upstream.yml). +# Lints the documentation source in docs/**: markdownlint for style, +# lychee (offline) to verify that every relative Markdown link resolves +# to a real file, and a semantic check of the generated /llms.txt +# (https://llmstxt.org/) against its data/nav.yml source of truth. +# Portable relative links are what the Hugo module mount on +# docs.docker.com resolves, so broken ones would break the downstream +# build (see docs-upstream.yml). name: docs-lint permissions: @@ -19,11 +21,18 @@ on: - ".github/workflows/docs-lint.yml" - "docs/**" - "scripts/docs-check-canonical.sh" + - "scripts/docs-check-llms-txt.sh" pull_request: paths: - ".github/workflows/docs-lint.yml" - "docs/**" - "scripts/docs-check-canonical.sh" + - "scripts/docs-check-llms-txt.sh" + +env: + # Kept in sync with docs-deploy.yml / docs-a11y.yml so every docs + # workflow builds with the same Hugo release. + HUGO_VERSION: 0.163.0 jobs: markdownlint: @@ -67,3 +76,22 @@ jobs: --exclude-path docs/index.md --exclude-path docs/404.md "docs/**/*.md" fail: true + + llms-txt-check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Install Hugo + run: | + curl -fsSL "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz" \ + | sudo tar -xz -C /usr/local/bin hugo + hugo version + + # llms.txt is generated at build time from data/nav.yml (STYLE.md + # "llms.txt"); a broken groups[].items traversal or similar template + # regression can silently drop entries while the build stays green, + # so this asserts the built output's content, not just build success. + - name: Check llms.txt + run: ./scripts/docs-check-llms-txt.sh diff --git a/docs/STYLE.md b/docs/STYLE.md index 617986cfb..9e863439c 100644 --- a/docs/STYLE.md +++ b/docs/STYLE.md @@ -93,6 +93,23 @@ scaffolding a new page from an existing one. The homepage, `404.md` and section `_index.md` files are not mirrored pages and don't set one. +## llms.txt + +`/llms.txt` is generated at build time from `data/nav.yml` (see +`layouts/home.llms.txt`): adding a page to the nav automatically adds +it to llms.txt, and pages absent from `nav.yml` never appear there. +Every nav entry must resolve to a real page with a non-empty +`description:` in its front matter (whitespace-only counts as empty) +— the build fails with an `errorf` naming the offending title/url +otherwise, since the spec's `- [title](url): note` shape requires a +note. CI (`docs-lint` / `scripts/docs-check-llms-txt.sh`) additionally +rebuilds the site and asserts the generated `llms.txt` matches +`nav.yml`'s sections, titles, order, count **and per-entry URL** +(each rendered link must match the nav url at the same position, not +just share the site's base URL), catching regressions (e.g. a broken +`groups[].items` traversal, or every entry rendering the same link) +that a successful build alone would not. + ## Availability badges When a page documents a feature that is merged on `main` but not yet diff --git a/docs/hugo.yaml b/docs/hugo.yaml index c70e37883..160ee64f7 100644 --- a/docs/hugo.yaml +++ b/docs/hugo.yaml @@ -15,6 +15,19 @@ title: Docker Agent # emitted at /404.html, which is where GitHub Pages looks for it. disableKinds: [section, taxonomy, term, rss, sitemap, "404"] +# llms.txt (https://llmstxt.org/): a plain-text output format attached to +# the home page only. Without the explicit `outputs.home` entry below the +# format is defined but never rendered, since home currently emits HTML only. +outputFormats: + llms: + mediaType: text/plain + baseName: llms + isPlainText: true + permalinkable: false + +outputs: + home: [html, llms] + params: tagline: Run AI agents like containers. description: Run AI agents from a YAML file. Define them once, share them through any OCI registry, and run them anywhere — by Docker. diff --git a/docs/layouts/_partials/footer.html b/docs/layouts/_partials/footer.html index d819dd5f6..9b6873ce2 100644 --- a/docs/layouts/_partials/footer.html +++ b/docs/layouts/_partials/footer.html @@ -25,6 +25,7 @@