Root page
How
llms.txt and shared chrome find the page published at each language root: the home page, or a doc-rooted site’s docs section pageSelection rule
_partials/td/root-page.html returns a site’s root page: it
takes a Site and returns the page at logical path /docs when the URL of its
html output format equals the home page’s, otherwise the home. Consumers share
the result through partialCached, which caches per site.
Consumers
llms.txtdiscovery: therel="describedby"link in every page head, the in-body agent directive, the Markdown versions’llms.txtlink, and the Docsy-private_root-llms-txt-pathshortcode all need the language’sllms.txtURL, which exists when the root page has anLLMSoutput (Discovery).- The
llms.txttemplate (all.llms.txt):- The home-page link targets the language’s root page; the
Site localeslist links each language’s root page. - The description is the root page’s, falling back to the home page’s.
- The documentation index is a separate
/docslookup.
- The home-page link targets the language’s root page; the
- Shared chrome: in the
sharedchrome build mode, the navbar and footer are kept on one donor page per language, the root page, and restored from it elsewhere. The chrome applies the definition without the lookup: a page is the donor when itshtmlURL equals the home page’s. The placeholders carrydata-chrome-donor, the home page’shtmlURL, where the client fetches the chrome; the navbar’s also carriesdata-canonical-path, the page’s ownhtmlURL, which keys the client’s active-state restore. The left-nav has a donor rule of its own (donor pages).
Why this rule
- Absolute logical path,
site.GetPage "/docs": a bare"docs"would be wrong. When there is no/docssection, aSitelookup falls back to a site-wide lookup by name, which fails the build on two pages nameddocs(page reference "docs" is ambiguous) and silently returns the one such page otherwise (#2875). - The URL comparison keeps an ordinary
/docs/section from being taken for the root. - The
htmloutput URL, not the URL of the format being rendered: the cached result serves every render pass, and a permalinkable format can render before HTML. - The home page’s
htmlURL as the reference: Hugo computes it under every URL setting (baseURLpaths, language prefixes, multihost, site-wideuglyURLs, the site matrix’s version dimension), which no configuration-derived root reproduces in full.
The docs name is the doc-rooted recipe’s own: the recipe
redefines that section’s permalinks, and the llms.txt documentation index
lists its subsections. Two alternatives that avoided the name were set aside:
- Scanning
site.Sectionsfor a section at the home’s URL depends on Hugo’s listing rules: a section page withbuild.list: neverpublishes but is not listed. - A configuration switch would duplicate what
permalinksalready states.
Covered cases
The table records supported behavior; the Evidence column names the fixture
test (tests/fixture-site/) exercising the row. Chrome consequences assume
shared mode.
| Case | Root page and consequences | Evidence |
|---|---|---|
Ordinary site (home renders, docs under /docs/) | The home. llms.txt at /llms.txt when LLMS is among the home outputs; the home is the donor page. | llms-directive, chrome-render |
| Doc-rooted site | The docs section page, published at the home’s URL. Publishes llms.txt when its outputs include LLMS; it is the donor page. | llms-doc-rooted, chrome-doc-rooted |
No /docs section, pages named docs elsewhere (one or many) | The home; the build succeeds, and llms.txt has no documentation index. | root-page |
| Multilingual project | One root page per language (/, /fr/), each able to publish its own llms.txt and each its own donor page; defaultContentLanguageInSubdir only moves the URLs. | root-page, chrome-doc-rooted |
docs section page without a translated _index file | Hugo’s auto-created section is still the root when published there; its outputs come from configuration or cascade, not from a file. | root-page |
baseURL with a subpath | Both compared URLs include the subpath, so the selection is unchanged. | root-page |
| Several output formats (HTML, Markdown, print, RSS, LLMS) | Selection is unchanged whatever format renders first or carries rel=canonical (the rule compares html URLs). The donor is the root page’s HTML render; its print render gets a placeholder like any other page. | root-page, llms-doc-rooted, chrome-doc-rooted (print), chrome-render (permalinkable print) |
Site-wide uglyURLs | Both compared URLs end in index.html, so the selection is unchanged; the donor is named as /index.html. | root-page |
Doc-rooted home with LLMS configured | The home publishes no file; root-level llms.txt and discovery require LLMS on the docs section page. | llms-doc-rooted |
Root page without LLMS | No describedby link, directive, or Markdown link, even when another section publishes an llms.txt; the shortcode fails the build when invoked. | llms-directive, llms-doc-rooted |
LLMS on a non-root section | Its llms.txt is the site overview, not a section index; discovery still depends on the root page’s LLMS output. | llms-doc-rooted |
Limits
The design leaves these unresolved:
- A section other than
docsremapped to the site root: the lookup keeps the home, sollms.txtdiscovery follows the home, while the chrome’s self-test makes that section the donor; Hugo need not warn (a link-only home leaves no duplicate output). - Two pages publishing the same root URL: a path conflict of the site’s own.
- A doc-rooted language without a
/docssection: it has no root page, sollms.txtlists the language at an unpublished URL, and the site root that shared chrome names as donor serves nothing. - A doc-rooted home whose output formats (site
outputs.home, or its own front matter) don’t start withHTML: a link-only page keeps only its first configured format, so the home has nohtmlURL to compare with; the home stays the root page, no render is the donor, and the placeholders name an empty donor (the client fetches the page itself once);llms.txtdiscovery follows the home’s kept formats, present only whenLLMSis among them. The same holds forbuild.render: neverand an emptyoutputs.home, wherellms.txt’s home and locale links are empty too (thedocssection page still publishes itsllms.txt). Hugo’soutputsconvention isHTMLfirst. - A
docssection page whoseoutputsleave outHTML: it is neither selected nor a donor. uglyURLsset for thedocssection only (uglyURLs: { docs: true }): the section page publishes at/index.htmlwhile the home page, in no section, keeps/, so the URLs differ and the home stays the root page, with no discovery and no donor.HTMLmarkednotAlternative: the donor page’s other renders then carry the chrome too (the current-render test is “HTMLis not among the alternatives”); the placeholders still name the site root, so the restore works.- A paginated root page: each
/page/N/continuation renders the chrome too. The theme’s own layouts paginate only the blog list.