Skip to content

Contributing to these docs

This site is an Astro Starlight project in docs/site/ of the Legion repository. Every push to main publishes it to GitHub Pages, and every pull request that touches it builds it, so a broken page or link fails the pull request before it can merge.

From the repository root, with Bun, Go and Node.js 22.12 or newer installed:

Terminal window
bun install --cwd docs/site
bun run docs:dev # generate the reference pages, then serve the site with live reload
bun run docs:build # generate the reference pages, then build the site into docs/site/dist/

Pages live in docs/site/src/content/docs/, one Markdown (.md) or MDX (.mdx) file per page. The file’s path is its URL: dispatch/inbox.md is published at /legion/dispatch/inbox/.

Path What it holds
index.mdx, how-it-fits.md The Overview: the landing page and how the components fit together.
legion/ Legion, the coordinator and its agents.
dispatch/ Dispatch, issues and the decisions people make there.
broker/ The Secrets Broker.
<section>/reference/ Generated reference pages. Never edit or commit these; see below.

Every page starts with frontmatter:

---
title: The Inbox # the page heading and its sidebar label
description: One sentence saying what the page covers. # used for search results and link previews
sidebar:
order: 2 # optional: lower numbers sort first within the section
label: Inbox # optional: a shorter sidebar label than the title
---

Write the body as if the title were already its first heading: start with ## headings. A diagram is a fenced code block whose language is mermaid; it renders in the page and follows the light or dark theme.

Create the file in the section’s directory. Each section’s sidebar is built from its directory, so the page appears there without any configuration; set sidebar.order to place it. A section’s index.md is its introduction and sorts first (order: 0). A subdirectory becomes a collapsible group in the sidebar.

Every link to another page on this site is root-absolute and starts with the site’s /legion base, because the site is served under /legion/ and nothing adds the base for you:

  • a page linking a sibling in its section: [Documents](/legion/dispatch/documents/);
  • a page linking its section’s generated reference: [Tools](/legion/dispatch/reference/tools/);
  • a section page linking the overview: [How it fits together](/legion/how-it-fits/).

The build checks every internal link and fails on one that leads nowhere, and on a link to a heading that does not exist (/legion/how-it-fits/#no-such-heading). It also fails on a relative link such as ../documents/: the link validator either refuses relative links (its default, errorOnRelativeLinks) or, with that turned off, never checks them, so a broken one would ship.

Reference pages that describe code, such as an HTTP API, a CLI or a tool list, are generated from that code on every build and never committed, so they cannot drift from it. They come from generators, and bun run generate (part of dev and build) runs them under this contract:

  • Name and place. A generator is an executable file directly in docs/site/generators/ named <section>-<name>.ts or <section>-<name>.sh, where <section> is one of the content directories above (legion, dispatch, broker). Subdirectories of generators/ hold shared helpers and are never run. A file directly in generators/ that breaks these rules fails the build.
  • Invocation. It runs from the repository root as <generator> <absolute content dir>, where the content directory is docs/site/src/content/docs. A .ts generator runs through Bun.
  • Binaries. Before any generator runs, docs/site/scripts/build-binaries.sh builds the Go binaries from the same commit and puts them first on the generator’s PATH: legion, envoy-dispatch, envoy-broker, agent-secrets and agent-secrets-helper.
  • Output. It writes its pages, with frontmatter like any other page, under <content dir>/<section>/reference/. That directory is emptied before the generators run and is ignored by git. The sidebar shows it as the section’s Reference group.
  • Failure. A generator that exits non-zero, or exits zero without writing a page, fails the build.

generators/legion-skills.ts is a small example: it lists every skill in skills/ by the name and description in its SKILL.md, as Skills.

The scripts that make screenshots and narrated walkthroughs live in docs/site/media/, and its README says how to run and extend them. Screenshots are taken in CI before every site build and are not committed; videos are committed with their sources. Only their output goes in docs/site/public/media/, which the site publishes as it is. A file at public/media/<path> is published at /legion/media/<path>, so a page embeds a screenshot as ![The Inbox](/legion/media/<path>.png). Media shows example data only: this repository is public, so no real hostname, account, token or private URL appears in a page, image or video.

The secrets broker’s media is made differently. It needs a rig of its own (a broker, its client and an example agent machine) that the shared harness does not boot and CI does not run, so its screenshots are committed too, and its walkthrough has a build of its own: docs/site/media/broker/walkthrough/build.py makes it from the cut in edl.py, not walkthrough.ts. Its terminal casts are recorded live against the rig between its browser sections, since each section acts on what the one before it left. Its browser sections are Playwright’s recordVideo at 1280x720, which build.py renders at 30 fps. The shared pipeline avoids that recorder for its blur; this walkthrough keeps it because the committed footage and the marks the cut is placed at come from it, and changing it needs a new take. It publishes the video, its captions and its poster to public/media/broker/. docs/site/media/broker/walkthrough/README.md says how to record and build it.