Documentation sites with PagePilotThis page explains how our documentation sites are built and why they are built that way. It is background reading, not a set of steps — if you are here to publish a page or wire up a new site, follow the setup guide in the template repository instead. What follows is the thinking behind the setup: what a "documentation site" actually is in this system, how its content is modelled, and what we gain by keeping that content out of the codebase. The problem it solvesMost documentation sites keep every page as a file inside a code repository. It is a familiar setup, and for a small project it works well. As the documentation grows, though, a friction appears: every change to the docs — a corrected sentence, a new page, a re-ordered menu — travels through the same pipeline as a code change. It needs a branch, a review, and a deployment. That has two costs. The people who most often need to change documentation — support, product, technical writers — usually cannot, so a developer is pulled in to make edits that have nothing to do with development. And because each change carries that overhead, small fixes get postponed, and the documentation drifts out of date. The approach described here removes that friction by moving the content of the documentation out of the repository and into PagePilot, while leaving the presentation — the layout, the navigation, the styling — in a small front-end that rarely changes. How a documentation site is put togetherA documentation site in this system is two things working together across a network boundary. A front-end template. A ready-made application that provides the shell of a docs site: the page layout, the top navigation, the sidebar, search, light and dark themes, and the machinery for dropping interactive components into a page. It is built once and shared across products. You clone it, point it at a PagePilot workspace, and largely leave it alone. A PagePilot workspace. This is where the documentation actually lives. It holds the navigation menus and every page of content. The template asks the workspace for a menu and a page whenever a reader loads the site, and renders whatever comes back. Because the two are separate, the same front-end can serve any product's documentation — only the workspace behind it differs — and the documentation can be rewritten from top to bottom without touching, rebuilding, or redeploying the front-end. The content model: menus, pages, and sectionsThree ideas describe everything in a documentation site. They are worth understanding because they are what you work with day to day in PagePilot. MenusA menu is a named, ordered tree that drives navigation. Each documentation site uses two: one for the sidebar, listing every page grouped by topic, and one for the top navigation, listing the main sections. Re-ordering the sidebar, renaming a group, or promoting a page is a matter of editing this tree — the navigation is data, not code. Each entry in a menu simply points at a page by its address — its slug. There is no hidden link between the two beyond that shared piece of text, which keeps the model easy to reason about: if an entry and a page share the same slug, clicking the entry opens the page. PagesA page is one screen of documentation, identified by its slug — the path a reader sees in the address bar. A page belongs to a documentation group, which is how the site knows which pages make up which site, and it is either published or not. Everything else about a page is its content, which is held in sections. SectionsA page is an ordered list of sections, and every section is one of two kinds: internal or external. The order of the list is the order they appear on the page, and a single page can mix the two freely — so an explanation and a working example can sit one after another. Internal sectionsAn internal section is ordinary authored content. You build it in the PagePilot editor from blocks — headings, paragraphs, lists, tables, code samples, images — and PagePilot keeps it in two forms at once. One is the editable version the visual editor opens when someone comes back to change the page. The other is a finished, rendered version that the documentation site actually displays. You never manage those two copies yourself; PagePilot keeps them in step whenever the page is saved. The great majority of a documentation site is internal sections. External sectionsAn external section has no authored content at all. It is a named empty slot — a marker that says "something goes here, and the front-end will supply it." In the PagePilot editor it shows as a locked placeholder with a note that it is managed in code; there is nothing to type into it. Each external section carries just one meaningful thing: a unique identifier, generated when the section is created. That identifier is the contract between the page and the front-end. External sections exist because some things on a documentation page cannot be written ahead of time. They have to run in the reader's browser, against live data, at the moment the page is viewed. A console that sends a real API request and shows the real response. A pricing table that reflects the current plans. A personalised panel. A third-party embed that brings its own scripts. None of that can be expressed as static content, so instead the page leaves a labelled gap and lets the application fill it. ExecutorsAn executor is the component that fills an external section's gap. In an API reference, the typical executor is a small form for one endpoint: it shows a field for each parameter, builds the request as you type, sends it when you submit, and displays the status and response — a "try it" console living inside the documentation. The front-end holds a simple lookup table that maps each external-section identifier to an executor component. When the template renders a page and reaches an external section, it reads the identifier, finds the matching executor in the table, and renders that component in place of the empty slot. If an identifier has no entry in the table, nothing is rendered — the gap simply stays empty, which is harmless. Adding a new interactive piece to the docs is therefore two small moves: place an external section on the page in PagePilot, and add one line to that lookup table pointing its identifier at a component. Why an identifier and not a name. The identifier is an opaque value assigned when the section is created, not something derived from the endpoint or the title. That keeps the link unambiguous even if the page is renamed or the endpoint changes — the front-end always knows exactly which slot an executor belongs to. The one rule that follows: copy the identifier from the editor, don't invent one. The division of labour is the point. The content team owns the slot — where on the page the interactive piece sits, and the prose around it. The engineering team owns the contents — what the executor actually does. Neither has to wait on the other. How content becomes a page a reader seesWhen someone opens a documentation page, the template fetches the relevant menu and the page for that address, then renders the page's sections in order. Authored sections are shown as formatted content, kept visually isolated so the documentation's styling and the site's own styling cannot interfere with each other. Interactive sections are replaced by their component. The sidebar and the search index are both built from the same menus, so they can never fall out of step. And because a page's content is fetched each time it is viewed rather than baked in ahead of time, an edit made in PagePilot is visible on the site immediately, with no build or deployment. Why the content lives outside the codebaseKeeping documentation content in a CMS rather than in the repository is a deliberate trade. What it buys:
What it costs is a second system to understand and a network hop at request time. In practice the content model is small enough to learn in an afternoon, and the request is a cached lookup, so neither cost is heavy against the benefit of documentation that keeps pace with the product. What this means for different people
How it relates to the API referenceA common use is an API reference. There the setup is partly automated: a script reads an OpenAPI or Swagger description of the API and, from it, creates a page for each endpoint and the menu entries that link to them. Each endpoint page can carry an interactive section — a small console that sends a real request — so readers can try an endpoint on the same page that documents it. The content model is exactly the same as any other documentation site; only the way the pages are first created differs. That script can be run by a coding assistant. The template repository's setup guide is written so that an assistant — Claude, Cursor, Copilot — can carry out the whole provisioning process: read the spec, create the pages and menus, and wire up the executors. It is the quickest route from an API description to a working, browsable reference. What you provide to set a site upWhether the provisioning script is run by a person or by a coding assistant, it needs a few pieces of information. These are the only things asked of you — everything else is worked out from the API description or set to a sensible default and confirmed with you first.
The workspace id and the service token both come from your own PagePilot account. Nobody can issue them for you, and an id from an example will not work — it has to be yours. Handling the service token safelyThe token grants write access to your workspace, so it needs the same care as any other secret.
If you hand this to a coding assistant: give it the API link and your workspace id in the chat, but provide the service token through an environment variable it reads at run time — don't paste the token into the conversation or let it be written into any file. Where to go next• The template repository — the front-end, and the setup guide for wiring it to a workspace or an API spec: github.com/FAB-Builder/swagger-documentation-template • A live example built with it: cx-docs.fabbuilder.com • PagePilot — where the menus and pages are edited: pagepilot.fabbuilder.com |