# Getting started

---

# What is Trail

_Trail / Getting started_

> Trail is the static site builder behind Peios Learn — a single Rust binary that turns a directory tree of markdown into a searchable, themed documentation site, with the structure coming from the filesystem rather than a config file.

**Trail** is a static site generator for documentation. You give it a directory of markdown files arranged into named folders; it gives you a complete website — every page rendered, cross-linked, indexed for search, mirrored as markdown for machines, and bundled into printable single-page views.

This site is built with it. Everything you are reading, including this page, comes out of one `trail build`.

## The one idea: the tree is the site

Trail has no table-of-contents file, no `sidebar.json`, no list of pages to keep in sync with the pages themselves. **The directory tree is the navigation.** A folder named `2--writing.topic` is a topic called "Writing" that sorts second; the `.md` files inside it are its articles, in the order their own numeric prefixes give them.

```text
learn/
├── trail.toml                        # the site
└── trail.product/                    # a product
    ├── trail.toml
    ├── 1--getting-started.topic/     # a topic, sorted first
    │   ├── 100--what-is-trail.md     # an article, sorted first
    │   └── 200--quick-start.md
    └── 2--structuring-a-site.topic/
        └── 100--products.md
```

Add a file, and the page exists, appears in the sidebar, joins the search index, and gets a markdown mirror. Rename a folder, and the section moves. Nothing else has to be told.

The trade is that names carry meaning. `100--quick-start.md` is not a decorative filename: `100` is the sort key and `quick-start` is the URL segment. [Directory and file names](/trail/reference/directory-names.md) is the exhaustive grammar; [Anatomy of a site](/trail/getting-started/anatomy-of-a-site.md) is the guided tour.

## Strict by default

The second principle is that **mistakes are build failures, not silent surprises**. A documentation site that quietly drops a page is worse than one that refuses to build.

- A key that `trail.toml` does not define is an error, not an ignored line.
- A file trail does not recognise — a stray `notes.txt` in a topic, a `README.md` without an order prefix — is an error, not a file left out of the site.
- A `~link` whose target no longer exists fails the build. Every broken link in the site is reported at once, so one run tells you the whole story.
- An ambiguous `~link` — one matching two pages — always fails, even under `--allow-dangling-links`. Trail will not guess which page you meant.
- A frontmatter `updated:` that is not an ISO date, a colour that is not `#rrggbb`, a `.link` alias pointing at another alias: all errors.

The escape hatches are deliberate and few. `--allow-dangling-links` downgrades missing targets to warnings while you are mid-refactor; that is the whole list.

## One binary, no runtime

Trail is a single Rust binary with everything compiled in: the templates, the stylesheet, the fonts and their licences, the search engine, the syntax highlighter, the diagram renderer. There is no theme directory to install beside it, no Node toolchain, no `npm install` step, and nothing to fetch at build time.

The output is equally plain. `dist/` is a directory of static files — HTML, CSS, WOFF2, JSON, a WASM search core — that any static host will serve as-is. There is no server component and no build step at request time.

## What one build does

```text
trail.toml + the tree
  → load          parse every trail.toml and every frontmatter block, validate names
  → resolve       .link aliases, ~link targets, inline-reference phrases, images
  → render        one HTML page per article, product, anthology and book cover
  → export        .md mirrors, /print bundles, llms.txt, site.json, sitemap, robots
  → index         the Pagefind search bundle, built from the rendered pages
  → prune         delete anything in dist/ this build did not write
```

Loading is where nearly all the errors live: by the time rendering starts, the site model is known to be well-formed. Pruning is why `dist/` belongs entirely to trail — a page you deleted from the source disappears from the output on the next successful build, along with superseded search index fragments and stale images.

Builds are fast enough not to think about. This site — over twelve hundred pages — builds from scratch in a little over three seconds.

## What a site is made of

Four kinds of thing, from the outside in:

| | What it is |
|---|---|
| **Site** | One `trail.toml` at the root, the front page, and the products. |
| **Product** | A documented thing (`trail.product/`) with its own colour, monogram and landing page. |
| **Grouping** | How a product's pages are organised: [anthologies](/trail/structuring-a-site/anthologies-and-shelves.md), [topics](/trail/structuring-a-site/topics-and-folders.md), [books](/trail/structuring-a-site/books.md) and shelves. |
| **Article** | One `.md` file: YAML frontmatter, then markdown. |

The distinction that matters most is **topic versus book**. A topic is a set of articles you can read in any order — a how-to section, a concept section. A book is a formal, ordered document — a specification, a reference manual — with a cover page, dotted section numbers (`2.1.3`), chapters that nest arbitrarily deep, and lettered appendices. They render differently because they are read differently.

## What trail gives readers

Beyond the pages themselves, every build produces:

- **Search** — a ⌘K modal over a [Pagefind](https://pagefind.app) index, loaded lazily so pages carry no search cost until someone searches. Results carry the query through to the page, which highlights every match.
- **Three-state theming** — light, dark, or follow the system, remembered per reader. Syntax highlighting, diagrams and images all follow it.
- **Print and machine views** — every topic, book, anthology and product is also one long page at `/print`, one markdown file at `/print.md`, and every individual page is mirrored at its own URL with `.md` appended.
- **The reading furniture** — a scroll-spying "On this page" list, copy buttons on code blocks, heading permalinks, adjustable text size, previous/next links, a mobile drawer, and a back-to-top button.

[The reading experience](/trail/building/the-reading-experience.md) covers all of it; [The output surface](/trail/building/the-output-surface.md) covers exactly what lands in `dist/`.

## What trail is not

- **Not a general-purpose SSG.** There is no plugin system, no shortcode API, no way to add a page type. The templates are compiled in and are not user-replaceable; [theming](/trail/building/theming.md) happens through CSS custom properties and an optional stylesheet.
- **Not versioned.** One build produces one version of the site. Hosting several versions means several builds at several paths.
- **Not incremental.** Every build renders every page. It is fast enough that this has never mattered.
- **Not a subpath host.** Sites are served from the root of a domain; internal links are root-relative.

## Where to start

If you want a working site in five minutes, go to the [Quick start](/trail/getting-started/quick-start.md).

If you want to understand the layout before writing anything, read [Anatomy of a site](/trail/getting-started/anatomy-of-a-site.md), then the [Structuring a site](/trail/structuring-a-site/products.md) section in order.

If you are writing pages in a site that already exists, [Writing](/trail/writing/articles-and-frontmatter.md) is the section you want — frontmatter, links, images, code blocks and the rest.

---

# Quick start

_Trail / Getting started_

> Build a documentation site from an empty directory — a root trail.toml, one product, one topic, one article — then serve it with live reload and watch it grow.

This page takes you from an empty directory to a served, searchable documentation site in about five minutes. You will write four files, run `trail build`, look at what it produced, then switch to `trail serve` and add a second page while it is running.

## Prerequisites

- **A `trail` binary.** Trail is a single Rust binary; build it from its source directory with `cargo build --release` and the result is `target/release/trail`. Put it on your `PATH`, or call it by path — the examples below assume `trail` is on your `PATH`.
- **Nothing else.** The templates, stylesheet, fonts, syntax highlighter, diagram renderer and search engine are all compiled into the binary.

## Create the site

A trail site is a directory with a `trail.toml` in it. Make one:

```console
$ mkdir acme-docs && cd acme-docs
```

```toml
# acme-docs/trail.toml
sitename = "Acme Docs"
title = "Documentation for Acme"
description = "Guides and reference for the Acme toolchain."
footer = "Acme — docs."
```

Those four keys are the only required ones. `sitename` is the wordmark in the header (its last word is accented); `title` and `description` are the front page's headline and standfirst, and feed the site's `<meta>` tags. Everything else — the accent colour, the base URL, header links, a favicon — is optional and covered in [Configuring the site](/trail/building/configuring-the-site.md).

> [!NOTE]
> The site root may contain **only** `trail.toml`, `*.product` directories, the build output directory, and any files named by the config (a favicon, a custom stylesheet). Anything else is a build error. This is deliberate: a stray file in the root is far more likely to be a mistake than a plan.

## Add a product

Every page belongs to a **product** — a documented thing with its own landing page, colour and monogram. Products are directories named `<slug>.product`:

```console
$ mkdir -p docs.product
```

```toml
# acme-docs/docs.product/trail.toml
title = "Acme CLI"
monogram = "ac"
color = "#3b82f6"
description = "The command-line interface to Acme."
```

All four keys are required. The directory name gives the URL (`/docs`) and the slug you link by; `title` is what readers see. The `monogram` is the two-or-so characters shown on the product's tile on the front page, and `color` tints the product's cards, sidebar and headings.

## Add a topic and an article

A **topic** is a set of articles read in any order. Topics are directories named `<order>--<slug>.topic`:

```console
$ mkdir -p docs.product/1--guides.topic
```

```markdown
<!-- acme-docs/docs.product/1--guides.topic/100--hello.md -->
---
title: Hello
type: how-to
description: The first page.
---

Hello from **Acme**.
```

Three things are going on in that filename and that frontmatter block:

- **`1--guides.topic`** — the `1` sorts this topic among its siblings and never appears in a URL; `guides` is the URL segment; `.topic` is the kind. With no `trail.toml` of its own the topic's title is derived from the slug ("Guides").
- **`100--hello.md`** — same grammar for articles. Numbering in hundreds is a convention, not a rule: it leaves room to insert `150--` later without renumbering.
- **`title:` and `type:`** are the two required frontmatter keys. `description:` is optional but worth writing — it becomes the page's meta description and its social-preview text.

## Build it

```console
$ trail build
```

```text
built 6 pages (1 products) → ./dist
```

Six pages from one article, because trail writes more than the pages you authored:

```console
$ find dist -type f -not -path 'dist/assets/*' -not -path 'dist/pagefind/*'
```

```text
dist/index.html                     the front page
dist/404.html                       the not-found page
dist/docs/index.html                the product landing page
dist/docs/guides/hello/index.html   your article
dist/docs/print/index.html          all of Acme CLI on one page
dist/docs/guides/print/index.html   all of Guides on one page
dist/docs.md                        the product, as markdown
dist/docs/guides/hello.md           your article, as markdown
dist/docs/print.md                  all of Acme CLI, as one markdown file
dist/docs/guides/print.md           all of Guides, as one markdown file
dist/llms.txt                       the site's map for language models
dist/site.json                      the site's structure, machine-readable
dist/robots.txt
```

Plus `dist/assets/` (the stylesheet and fonts) and `dist/pagefind/` (the search index and its WASM core). Note that there is no page at `/docs/guides` — a topic has no page of its own. It shows up as a card on the product page, and links to it land on its first article.

`dist/` belongs to trail: at the end of every successful build it deletes anything in there that the build did not write.

## Serve it

```console
$ trail serve
```

```text
serving ./dist at http://127.0.0.1:8724 (watching . for changes)
```

`trail serve` builds the site, serves it, and watches the source tree. Save a file and the browser reloads itself; break something and the error prints in the terminal while the last good output keeps being served.

Open the site and try it: press <kbd>⌘K</kbd> (or <kbd>Ctrl K</kbd>) to search, and use the theme button in the header to switch between light, dark and system.

## Add a second page

Leave the server running and add another article beside the first:

```markdown
<!-- acme-docs/docs.product/1--guides.topic/200--installing.md -->
---
title: Installing
type: how-to
description: How to install Acme.
related:
  - docs/guides/hello
---

See [Hello](~docs/guides/hello) first.
```

Two new things:

- **`~docs/guides/hello`** is a page reference, not a URL. The first segment names a product; the rest matches the end of a page's path. Move or rename the target and the link still resolves as long as its slug is unchanged; delete it and the build fails rather than shipping a dead link. See [Links and references](/trail/writing/links-and-references.md).
- **`related:`** takes the same references (without the `~`) and renders a "Related content" list at the foot of the page.

Save, and the page appears in the sidebar next to Hello.

## Where to go next

- [Anatomy of a site](/trail/getting-started/anatomy-of-a-site.md) — the whole tree, level by level, with a real example.
- [Products](/trail/structuring-a-site/products.md) — the structuring section in order: products, anthologies, topics, books.
- [Articles and frontmatter](/trail/writing/articles-and-frontmatter.md) — every frontmatter key and what it does.
- [Configuring the site](/trail/building/configuring-the-site.md) — the base URL, accent colour, navigation links, edit links and the rest of `trail.toml`.

---

# Anatomy of a site

_Trail / Getting started_

> The whole tree, level by level — how directory and file names become URLs, ordering and titles, which trail.toml lives where, and what may legally sit at each level.

A trail site is a directory tree in which every name means something. This page walks that tree from the root down, and explains the naming grammar all of it shares. [Directory and file names](/trail/reference/directory-names.md) is the same material as an exhaustive table; [Structuring a site](/trail/structuring-a-site/products.md) covers each kind of container in depth.

## The whole shape

```text
learn/                                  the site root
├── trail.toml                           the site config — required
├── dist/                                the build output — trail's to manage
│
├── peios.product/                       a product  →  /peios
│   ├── trail.toml                       required: title, monogram, color, description
│   ├── 1--security-fundamentals.antho/  an anthology  →  /peios/security-fundamentals
│   │   ├── trail.toml                   required: title, description
│   │   ├── 1--identity.topic/           a topic  →  /peios/security-fundamentals/identity
│   │   │   ├── trail.toml               optional: title, inline_ref
│   │   │   ├── 100--sids.md             an article  →  …/identity/sids
│   │   │   ├── 200--principals.md
│   │   │   ├── 300--tokens/             a subfolder  →  …/identity/tokens/…
│   │   │   │   ├── trail.toml           optional
│   │   │   │   └── 100--issuing.md      →  …/identity/tokens/issuing
│   │   │   └── diagram.svg              an image, published beside its article
│   │   └── 2--pgss.book/                a book  →  /peios/security-fundamentals/pgss
│   │       ├── trail.toml               required: title, description; optional: short
│   │       ├── 1--scope.md              §1  →  …/pgss/scope
│   │       ├── 2--model/                a chapter, §2
│   │       │   ├── trail.toml           optional
│   │       │   └── 1--objects.md        §2.1
│   │       └── a1--glossary.md          Appendix A
│   └── 2--tooling.shelf/                a shelf — a heading, not a URL segment
│       └── 1--pekit.topic/              →  /peios/pekit   (the shelf adds nothing)
│
└── pekit.product/                       another product  →  /pekit
```

Everything below the root is optional. A site with one product, one topic and one article is a complete site; this site's `trail.product` is exactly that shape, four levels shallower than `peios.product`.

## The naming grammar

Three name shapes appear throughout the tree.

| Shape | Example | Where |
|---|---|---|
| `<slug>.product` | `pekit.product` | Only at the site root. |
| `<order>--<slug>.<kind>` | `2--writing.topic` | Anthologies, topics, books, shelves. |
| `<order>--<slug>` | `300--tokens`, `2--model` | Topic subfolders and book chapters — no suffix. |
| `<order>--<slug>.md` | `100--sids.md` | Articles. |
| `<order>--<slug>.link` | `3--faq.link` | Aliases; see [Link aliases](/trail/structuring-a-site/link-aliases.md). |

The parts:

- **`<order>`** is a non-negative integer used only for sorting among siblings. It never appears in a URL or a title. Gaps are fine and normal — numbering articles `100`, `200`, `300` leaves room to insert. Two siblings sharing an order is an error, because the resulting page order would depend on nothing you can see.
- **`<slug>`** is lowercase kebab-case: ASCII lowercase letters, digits and hyphens, not starting or ending with a hyphen. It becomes the URL segment, and it is what you write in a `~link`.
- **`<kind>`** is `antho`, `topic`, `book` or `shelf`.

Inside books, an order may also be written `a<N>--` (`a1--glossary.md`). Those are **appendices**: lettered `A`, `B`, `C` instead of numbered, and sorted after every numbered sibling at their level. See [Books](/trail/structuring-a-site/books.md).

## URLs

A page's URL is its product slug followed by the slug of every container between the product and the page — with two exceptions.

```text
peios.product/1--security-fundamentals.antho/1--identity.topic/100--sids.md
  →  /peios/security-fundamentals/identity/sids
```

The exceptions:

- **A shelf contributes no segment.** It is a heading on its parent's page, nothing more. A topic inside `2--tooling.shelf/` lives at `/peios/<topic>`, exactly as if the shelf were not there.
- **Order prefixes contribute nothing.** `1--identity.topic` gives the segment `identity`.

Which containers have a page of their own is worth knowing, because it decides what you can link to:

| | Has a page | Links to it land on |
|---|---|---|
| Site | `/` | — |
| Product | `/pekit` | its own landing page |
| Anthology | `/peios/security-fundamentals` | its own landing page |
| Book | `/peios/…/pgss` (the cover) | the cover |
| Article | its own URL | itself |
| Topic | no page | *(topics are not link targets)* |
| Topic subfolder | no page | *(not a link target, except from a `.link`)* |
| Book chapter | no page | *(not a link target)* |
| Shelf | no page | *(not a link target)* |

Topics, subfolders and chapters are real structure — they appear in sidebars, cards and contents lists, and links from those surfaces open their first article — but they have no page you can address, so a `~link` cannot point at one. Point at the article you actually mean.

## Titles

Titles come from three places, in order of precedence:

1. **An article's `title:` frontmatter**, which is required.
2. **A container's `trail.toml`**, where the `title` key is required for products, anthologies and books, and optional for topics, subfolders, chapters and shelves.
3. **The slug**, hyphens to spaces and each word capitalised: `the-two-gates` becomes "The Two Gates".

The derived form is good enough surprisingly often; write a `trail.toml` when it is not — acronyms and casing it cannot guess ("Peiso", "The Console"), or when the container needs `inline_ref` phrases.

## What may sit where

Trail rejects anything it does not recognise, so it is worth knowing what each level tolerates.

| Directory | May contain |
|---|---|
| The site root | `trail.toml`, `*.product/`, the output directory, files named by the config |
| A product | `trail.toml`, `.antho/`, `.topic/`, `.book/`, `.shelf/` |
| An anthology | `trail.toml`, `.antho/`, `.topic/`, `.book/`, `.shelf/` |
| A shelf | `trail.toml`, the same as its parent minus shelves — a shelf never holds a shelf |
| A topic | `trail.toml`, `.md` articles, `<order>--<slug>/` subfolders, `.link` files, images |
| A topic subfolder | `trail.toml`, `.md` articles, `.link` files, images |
| A book | `trail.toml`, `.md` articles, `<order>--<slug>/` chapters, `.link` files, images |
| A book chapter | `trail.toml`, `.md` articles, `<order>--<slug>/` chapters, `.link` files, images |

Only the article-holding levels take files: `.md` articles, `.link` aliases and images may sit in a topic, a subfolder, a book or a chapter, and nowhere else. A product, anthology or shelf directory holds `trail.toml` and subdirectories, full stop.

Images sit beside the articles that use them and are published at the URL of the directory they were found in; see [Images](/trail/writing/images.md).

Two slugs are reserved: `print` (every container publishes a `/print` page) may not be an article slug, and `assets` and `pagefind` may not be product slugs.

## Ordering

Siblings sort by their `<order>` prefix, ascending. Within a book, appendix entries (`a<N>--`) sort after every numbered entry at the same level, and they are lettered rather than numbered.

Products are the exception: they have no order prefix. They sort by the root config's `featured` list first, in that list's order, then everything else by title.

## Where to go next

- [Products](/trail/structuring-a-site/products.md) — the product level in depth, and when to add another one.
- [Anthologies and shelves](/trail/structuring-a-site/anthologies-and-shelves.md) — grouping a large product.
- [Topics and folders](/trail/structuring-a-site/topics-and-folders.md) — the everyday container.
- [Books](/trail/structuring-a-site/books.md) — numbered, ordered documents with chapters and appendices.
