---
title: Output
description: Find what a build writes: the page tree, copied files, callouts, diagrams, the pager, styling names, machine files, redirect stubs, and failed replacements.
slug: /reference/output
order: 1
visibility: public
redirects_from: [/output]
---

# Output

This page lists what a build writes: the page tree, the copied files, the page head, the callouts, diagrams, and pager, and the styling names. It also covers the machine files, the 404 page, and the redirect stubs. It says what a failed replacement leaves behind, and it lists every name in the generated HTML and the stylesheet.

## The tree

The build writes each page to `<slug>/index.html` inside the output folder, the root page as `index.html`. Pages share `docs.css` and, when the build was given `--stylesheet`, `site.css`. Each page includes the full navigation with the current page marked. On a window wider than 800 pixels, the navigation stays in view while the article scrolls. Where it is taller than the window, it scrolls on its own, and its scrollbar shows only while the pointer or the focus is in it.

The stylesheet, navigation, and redirect links are relative, so the tree works under any base path on a static server. Each page or redirect link ends in a folder slash, such as `../guides/`, and the server returns that folder's `index.html`. A browser that opens the tree from disk shows the folder instead, so only the first page opened from disk displays correctly. The tool does not rewrite the links a shell supplies, so the shell's author must keep them correct.

Every other file in the source folder, an image or a download for example, is copied byte for byte to the same path in the tree. A file in a folder whose name begins with a dot, or whose own name begins with one, is not copied. Nor is a file that only hidden pages reference, unless the build passes `--include-hidden`. A page's images and file links are rewritten to the copied file's address relative to the page. [Images and other files](/reference/page-source/#images-and-other-files) gives the rules.

The root names `docs.css`, `site.css`, `docs.json`, `llms.txt`, `llms-full.txt`, `sitemap.xml`, `404.html`, and `mermaid.min.js` are reserved for the build's own files, so no page and no copied file can take one.

A built tree has this shape.

```text
site/
  index.html
  index.md
  docs.css
  site.css          where --stylesheet named one
  docs.json
  llms.txt
  llms-full.txt
  sitemap.xml       where --origin named one
  404.html
  mermaid.min.js    where a page draws a diagram
  getting-started/
    index.html
    index.md
  guides/
    diagram.png       a copied file, at its source path
    code-blocks/
      index.html
      index.md
  old-slug/
    index.html        a redirect stub
```

Each page carries one short inline script. It places the copy control on code blocks, a button with two icons at each block's right, which copies the block's text as authored. On a page that draws a diagram, it also starts Mermaid from the tree's own `mermaid.min.js`, which that page alone loads ([Diagrams](#diagrams)). Nothing else runs in the browser.

## The page head

Each page's head names the page and the corpus it belongs to. The `<title>` element holds the page's title, a spaced em dash, and the [home page](/concepts/glossary/#home-page)'s title, such as `Add a page — Turn Zero Docs`. The home page's title already names the corpus, so the home page carries its title once. In a corpus without a home page, each page carries its own title alone. The navigation, the index, and the manifest keep the page's own title.

The head also carries the share tags that a chat app or a social site reads when someone shares a link to the page:

| Tag | Value |
| --- | --- |
| `<meta name="description">` | The page's description. |
| `<link rel="canonical">` | The origin given with `--origin`, followed by the page's [route](/concepts/glossary/#route), such as `https://example.com/docs/guides/add-a-page/`. Present only with `--origin`. |
| `og:title`, `twitter:title` | The same text as the `<title>` element. |
| `og:description`, `twitter:description` | The page's description. Absent where the description is empty. |
| `og:url` | The same address as the canonical link. Present only with `--origin`. |

The canonical link, `og:url`, and the [sitemap](#the-sitemap) are the only absolute addresses the tool writes. Give the origin of the site that search engines should list. Then a tree served at more than one address names the same page as canonical in every copy. The share tags that every page has in common, such as the site's name, its share image, and the card form, belong to your site: put them in the head of your [shell](/guides/style-the-site/).

## Publication and recovery

The build checks the source and the output folder before it writes anything. It generates the whole site in a temporary staging folder beside the output folder, named `.tzdocs-stage-*`. A validation, rendering, or staging-write failure leaves the previous output unchanged.

After generation succeeds, the build replaces the output folder in these steps:

1. It renames an existing output folder into a `.tzdocs-backup-*` folder beside it.
2. It renames the generated tree to the output path.
3. If that rename fails, it renames the previous output back. If that fails too, the error message says where the previous output remains, inside the backup folder. Do not delete that folder before you recover the output from it.
4. After a successful replacement, it removes the backup. If that cleanup fails, the error message says that the new site is published and gives the remaining backup folder.

After a nonzero exit, read the message: the output may have changed. [Refusals and findings](/reference/refusals/#publication-failures) gives the messages.

The replacement is not atomic. A crash or a concurrent change to the file system during it can require manual restoration or cleanup. Run one build at a time into a given output folder, and deploy only after you inspect a successful result. A missing or unreadable source file can produce a Node.js error rather than a formatted finding.

## Callouts, diagrams, and the pager

### Callouts

A block quote that opens with one of the five callout markers ([Page source](/reference/page-source/#callouts)) becomes a `div` classed `docs-callout`. Its `data-callout` attribute holds the type, such as `note`. Its first child is a `p` classed `docs-callout-title` holding the title, such as Note, and the rest of the quote follows.

```html
<div class="docs-callout" data-callout="warning">
<p class="docs-callout-title">Warning</p>
<p>The build replaces the whole output folder.</p>
</div>
```

### Diagrams

Where Mermaid is installed and the build does not pass `--diagrams-as-code`, a `mermaid` fence becomes a `div` classed `docs-diagram`. It holds the diagram's source, escaped, with its line breaks kept. The build copies Mermaid's browser file, byte for byte, to `mermaid.min.js` at the tree root. Each page holding a diagram loads it with one deferred `script` tag in its head.

Once the page has loaded, its inline script draws each diagram as an SVG image. Under a dark `prefers-color-scheme` it uses Mermaid's dark theme. The `div` is not a `pre`, so a diagram has no copy control.

Otherwise the fence renders as a code block in the language `mermaid`, no page loads a script file, and the tree holds no `mermaid.min.js`. Which file the build found, and its version, are inputs of the build like the source files.

### Next and previous

With `--next-previous`, each page's last element in the `docs-main` column is the pager. It is a `nav` classed `docs-pager`, labelled `aria-label="Previous and next pages"`. It holds a link to the previous page and a link to the next one, in the navigation order the manifest and the whole text follow. The first page has no previous link and the last page no next link.

```html
<nav class="docs-pager" aria-label="Previous and next pages">
<a class="docs-pager-prev" rel="prev" href="../"><span>Previous</span>Home</a>
<a class="docs-pager-next" rel="next" href="../guides/add-a-page/"><span>Next</span>Add a page</a>
</nav>
```

The links are classed `docs-pager-prev` and `docs-pager-next` and carry `rel="prev"` and `rel="next"`. A section in the navigation that opens and closes is no page, so the pager never links one, and neither does it link a hidden page. Without the flag, no page carries the pager.

## The styling surface

`docs.css` is the tool's own stylesheet, complete in itself: the layout, the typography, the navigation, the code blocks, the callouts, the diagrams, the pager, and twenty-five color properties. On a narrow screen, the page stays within the screen's width: a long word in the text wraps, a file path in inline code included, and a wide table scrolls sideways inside itself. A site restyles the tree with a site stylesheet or with a shell's own stylesheet, and both target the names below. [Style the site](/guides/style-the-site/) is the guide for the stylesheet and for the shell.

### The colors

The twenty-five custom properties are colors, declared on the `.docs-shell` element. Each has a light default and, for all but the code block's own and token properties, a dark default under the viewer's `prefers-color-scheme`. A site redefines them on that element. A value declared on `:root`, `html`, or `body` is inherited and loses to the tool's own declaration.

| Property | Role |
| --- | --- |
| `--docs-bg` | page background |
| `--docs-text` | body text |
| `--docs-muted` | secondary text, section names, captions |
| `--docs-nav-text` | navigation links |
| `--docs-link` | links, the current page, the emphasized line's bar |
| `--docs-border` | rules and table borders |
| `--docs-code-bg` | inline code background |
| `--docs-pre-bg` | code block background |
| `--docs-pre-text` | code block text |
| `--docs-quote` | block quotes |
| `--docs-tok-comment` | code tokens: comments and quotes |
| `--docs-tok-keyword` | code tokens: keywords, literals, selector tags, template tags, doc tags |
| `--docs-tok-string` | code tokens: strings, regular expressions, additions |
| `--docs-tok-number` | code tokens: numbers, symbols, bullets |
| `--docs-tok-title` | code tokens: function and class names, sections, tag names, selectors |
| `--docs-tok-attr` | code tokens: attributes, variables, properties |
| `--docs-tok-type` | code tokens: types, built-ins, pseudo selectors |
| `--docs-tok-meta` | code tokens: meta lines and their keywords |
| `--docs-tok-deletion` | code tokens: deletions in a diff |
| `--docs-code-hl` | the emphasized line's band |
| `--docs-callout-note` | a Note callout's bar and title |
| `--docs-callout-tip` | a Tip callout's bar and title |
| `--docs-callout-important` | an Important callout's bar and title |
| `--docs-callout-warning` | a Warning callout's bar and title |
| `--docs-callout-caution` | a Caution callout's bar and title |

The code block keeps one dark background under both schemes, so its own and the token properties are declared once and their light and dark defaults are the same. The example below is a complete restyle, and the tool's own test suite builds with this exact text:

```css
.docs-shell {
  --docs-bg: #0b1020;
  --docs-text: #e6edf6;
  --docs-link: #7cc4ff;
  --docs-pre-bg: #05080f;
}
.docs-main pre code .docs-line-hl {
  background: rgba(124, 196, 255, 0.12);
}
```

### The selectors and the names

A site rule that uses the tool's own selector wins, because the site's stylesheet comes later. A rule of lower specificity than the tool's does not win, whatever the link order. The parts, with the selector to write and the names the markup uses:

| Part | Selector to write | Names |
| --- | --- | --- |
| the wrapper | `.docs-shell` | `docs-shell` |
| the navigation | `.docs-nav`, `.docs-nav a`, `.docs-nav a[aria-current="page"]` | `docs-nav`, `aria-current="page"`, `aria-label="Documentation"` |
| a section's name, which opens and closes it | `.docs-nav-section`, `.docs-nav details[open] > .docs-nav-section::after` | `docs-nav-section` |
| the article column | `.docs-main`, `.docs-main h1`, `.docs-main h2`, `.docs-main h3`, `.docs-main p`, `.docs-main a`, `.docs-main code`, `.docs-main table`, `.docs-main blockquote` | `docs-main` |
| a heading's anchor link | `.docs-main .docs-anchor`, `.docs-main :hover > .docs-anchor`, `.docs-main .docs-anchor:focus-visible`, `.docs-main .docs-anchor:hover` | `docs-anchor` |
| the page's Markdown link | `.docs-main .docs-source` | `docs-source` |
| a code block | `.docs-main .docs-code`, `.docs-main .docs-code figcaption`, `.docs-main pre`, `.docs-main pre code` | `docs-code`, `data-language`, the `language-*` class |
| a line, an emphasized line | `.docs-main pre code .docs-line`, `.docs-main pre code .docs-line-hl` | `docs-line`, `docs-line-hl` |
| the copy control | `.docs-main pre .docs-copy`, `.docs-main pre .docs-copy:hover` | `docs-copy`, `docs-copy-icon`, `docs-copied-icon`, `data-copied` |
| a callout | `.docs-main .docs-callout`, `.docs-main .docs-callout-title`, `.docs-main .docs-callout[data-callout="note"]`, `.docs-main .docs-callout[data-callout="note"] .docs-callout-title`, and the same two for `tip`, `important`, `warning`, and `caution` | `docs-callout`, `docs-callout-title`, `data-callout` |
| a diagram, a drawn diagram | `.docs-main .docs-diagram`, `.docs-main .docs-diagram[data-processed]` | `docs-diagram`, `data-processed` |
| the pager | `.docs-main .docs-pager`, `.docs-main .docs-pager a`, `.docs-main .docs-pager-next` | `docs-pager`, `docs-pager-prev`, `docs-pager-next`, `aria-label="Previous and next pages"`, `rel="prev"`, `rel="next"` |
| the default layout's body | `.tzdoc-page` | `tzdoc-page` |

The markup is the same on every page:

- The `docs-shell` wrapper contains the `docs-nav` navigation and the `docs-main` article column.
- The navigation is a `nav` element containing a `ul` of `li` elements. Each `li` contains an `a`, or, for a section with other entries, a `details` element. Its `summary` is classed `docs-nav-section` and contains the section's title, and its `ul` lists the entries. The `details` element is `open` on the pages the section contains and closed elsewhere, and the summary's `::after` draws the chevron.
- Every heading the page's Markdown renders ends with an `a` classed `docs-anchor`, reading `#`, with the accessible name Link to this section, that links to the heading's own anchor.
- The anchor link is hidden until a reader points at its heading or moves keyboard focus to the link. It keeps its place after the heading's text while hidden, so the heading does not shift when it appears.
- Beneath the first first-level heading of the page's content, or at its top where it has none, a `p` classed `docs-source` links to `index.md`, the Markdown source the build writes beside the page.
- A code block is a `figure` classed `docs-code`. It has `data-language` where the fence gives a language, and a `figcaption` where a title was given.
- Inside the figure are a `pre` and a `code` element, classed `language-*` where the fence gives a language, with one `docs-line` span per line.
- The copy control is a `button` classed `docs-copy`, which the page's one script places inside each `pre`. It contains two icons and has a `data-copied` state.
- A callout, a diagram, and the pager have the markup [Callouts, diagrams, and the pager](#callouts-diagrams-and-the-pager) gives.

The token classes, such as `hljs-keyword` and `hljs-string`, are the highlighter's class names at its pinned version. The highlighter adds a second class after some of them, such as `function_`. A site colors tokens through the token properties rather than by class.

A copied stylesheet's own relative references, such as `url(...)`, resolve from the tree root. The body rules (the margin reset, the font stack, and the color scheme) target the default layout's body class, `tzdoc-page`, and never a shell's body. A site's own base typography is therefore untouched.

## Machine files

Every build writes four files for scripts and AI agents. Start with `llms.txt`, the index: one line per page with its title, route, and description. Read `docs.json` to find headings and sections, then read only the relevant Markdown copies. Read `llms-full.txt` when the whole corpus is needed.

### The index

`llms.txt` at the tree root contains, in this order:

- a first-level heading with the home page's title;
- a block quote with the home page's description, where it has one;
- a `Start here` heading listing the home page and the root's own pages;
- one heading per top-level section, listing the pages that `--full-text-exclude` does not leave out, and no heading for a section whose every page is excluded;
- a final `Optional` heading listing the pages that `--full-text-exclude` left out of the whole text.

Every page line has the form `- [title](route): description`, without the colon and the description where the description is empty. For a corpus without a home page, the index's first-level heading is `Documentation`. The index reserves the `Start here` and `Optional` headings for itself ([Source-level refusals](/reference/refusals/#source-level-refusals)).

The index of a corpus built with `--base /docs` has this form.

```text
# Turn Zero Docs

> One command turns a folder of Markdown files into a static documentation site.

## Start here

- [Turn Zero Docs](/docs/): One command turns a folder of Markdown files into a static documentation site.

## Getting started

- [Getting started](/docs/getting-started/): Install the published tzdocs package, check a folder of Markdown, and build the site.

## Optional
```

### The manifest

`docs.json` at the tree root lists every page in navigation order:

| Member | Contains |
| --- | --- |
| `base` | The base path. |
| `version` | The corpus version, present only where `--corpus-version` gave one. |
| `pages[].route` | The page's route. |
| `pages[].title` | The page's title. |
| `pages[].description` | The page's description. |
| `pages[].section` | The section word: the word the page's `section` key declares, or else the page's first path segment, its own slug word at the root, and `home` for the home page. |
| `pages[].in_full_text` | Whether the page is in the whole text. |
| `pages[].headings` | Each heading's `depth`, `text`, and `anchor`. |
| `moved[].from` | A route a page's `redirects_from` names, under the base path. The list is empty where no page moved. |
| `moved[].to` | The route of the page that names it. |

The manifest has this form.

```json
{
  "base": "/docs",
  "version": "0.2.0",
  "pages": [
    {
      "route": "/docs/",
      "title": "Turn Zero Docs",
      "description": "One command turns a folder of Markdown files into a static documentation site.",
      "section": "home",
      "in_full_text": true,
      "headings": [
        { "depth": 1, "text": "Turn Zero Docs", "anchor": "turn-zero-docs" },
        { "depth": 2, "text": "Start here", "anchor": "start-here" }
      ]
    }
  ],
  "moved": [
    { "from": "/docs/output/", "to": "/docs/reference/output/" }
  ]
}
```

### The Markdown copy

`<slug>/index.md` beside every page contains the page's source Markdown, front matter included, line endings normalized. An agent that needs the source text rather than the rendered HTML reads this file.

### The whole text

`llms-full.txt` at the tree root contains every page's source, joined in navigation order. Each page's source follows an HTML comment giving its route under the base path. The pages under the slug prefix given to `--full-text-exclude` are left out. They stay pages, with their Markdown copies and their manifest rows, and appear under the index's `Optional` heading.

Each entry has this form.

```text
<!-- /docs/ -->
---
title: Turn Zero Docs
...
```

The tool writes the index, the manifest, and the whole text at the tree root and nowhere else. It does not write an `llms.txt` at the site's root. Where several documentation trees share one site, the site's owner writes the root index that lists them.

Which pages the four files include follows the page's `visibility` and the `--include-hidden` flag ([Add a page](/guides/add-a-page/), step 4).

### The sitemap

With `--origin`, the build also writes `sitemap.xml` at the tree root, for search engines. It lists one `<loc>` per built page, in navigation order: the origin followed by the page's route under the base path. It lists no redirect stub and carries no `lastmod` date, since the output carries no timestamp. Without `--origin` the build writes no sitemap, because a sitemap must give absolute addresses.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url><loc>https://example.com/docs/</loc></url>
<url><loc>https://example.com/docs/getting-started/</loc></url>
</urlset>
```

## The 404 page

Every build writes `404.html` at the tree root, the name GitHub Pages, Netlify, and Cloudflare Pages show for an address that matches no file. It holds the heading Page not found, one sentence, and a link to the home page, and it carries `<meta name="robots" content="noindex">`. Under `--shell` it renders into the shell.

A host serves the page at any depth, so its stylesheet links and its home link begin with the base path, such as `/docs/docs.css`. They are the only root-relative paths the tool writes. The page carries no navigation, no pager, and no Markdown link, and it is no page of the corpus: the machine files and the sitemap do not list it. [Publish the site](/guides/publish-the-site/) is the guide.

## Redirect stubs

Each `redirects_from` entry produces `<old-slug>/index.html`, a minimal page that refreshes to the new slug by a relative path. With `--origin`, a stub also carries a canonical link to the new page's address. Stubs have no navigation and no shell, and no page entry in the machine files. `docs.json` lists each one under `moved`, so a script or an AI tool reading the manifest reaches the new page without reading a stub.

## Reproducible builds

Building with identical sources, supplied files, options, Mermaid file, and tool version produces byte-identical output:

- directory listings are sorted before they are read;
- written paths use one separator on every platform;
- input line endings are normalized at read;
- heading anchors follow the tool's own anchor rule, duplicates suffixed `-2`, `-3`, and so on;
- code tokens depend only on the block's text, its language, and the pinned highlighter version;
- no timestamp is written anywhere.

A diff between two such builds shows content changes and nothing else. A change to the tool, its renderer, its highlighter, or the build options can also change the output.
