Astro docs site
The executable-stories-astro integration turns your test output into a full
Starlight site — generated scenarios and your
hand-authored docs side by side, with sidebar navigation, status badges, Mermaid
diagrams, and search. It is live: a content loader watches your run JSON, so
a fresh test run hot-reloads the open page. Nothing is written to disk — your
tests stay the source of truth.
This guide scaffolds a new site. Already have an Astro site? See Add to an existing Astro site. Collating runs from many repositories? See the multi-repo docs hub guide.
Getting started
Section titled “Getting started”npx --package executable-stories-formatters executable-stories init-astro my-docscd my-docs && pnpm installThis scaffolds a thin, ready-to-run Starlight project. The docs framework itself
ships in the executable-stories-astro package, so the scaffold is just ~8
user-owned files — chiefly one config file you edit.
Then emit the run JSON your reporter must write (see below), run your tests in
watch mode in one terminal, and astro dev in another:
pnpm dev # http://localhost:4321 — /stories, /explorer, and your docsEditing a test re-runs it and the Stories pages update with no reload.
One config drives everything
Section titled “One config drives everything”Everything lives in executable-stories.config.mjs, imported by both
astro.config.mjs and src/content.config.ts:
import { defineExecutableStories } from 'executable-stories-astro';
export default defineExecutableStories({ source: '../reports/raw-run.json', // or `sources: [...]` for several suites include: { tags: ['security'] }, // which scenarios to show (optional) groupBy: 'tag', // feature | tag | source | status | none docs: [{ path: 'src/content/docs/runbooks', label: 'Runbooks', base: 'runbooks' }], // historyFile: '../reports/history.json', // CLI --history-file store for journey trends theme: { preset: 'terminal', tokens: { pass: '#16a34a' } },});| Field | What it does |
|---|---|
source / sources |
One run JSON, or several named suites (combined in one site, groupable by suite). |
include / exclude |
Select scenarios by tags, status, or features. |
groupBy |
How the index/Explorer categorise scenarios. |
docs |
Authored markdown folders to surface in the nav. |
views |
Persona views: filtered, re-grouped indexes at their own URLs (e.g. /for/product). See Tagging for your audience. |
journeysBase / injectJourneys |
Where the journey walkthroughs mount (default /journeys; derived from journey:<id>:<n> tags). |
statesBase / injectStates |
Where the UI-state catalog mounts (default /states; derived from state:<name> tags, viewport variants side by side). |
driftBase / injectDrift |
Multi-source status comparison (default /drift; injected automatically with at least two sources). |
historyFile |
Store maintained by CLI --history-file; enables recent-run stability on journey pages. |
collection |
Collection name the loader feeds (default stories). |
routeBase / explorerBase |
Where the pages mount (default /stories, /explorer). |
agentEndpoints |
Inject /llms.txt and per-story Markdown twins at <routeBase>/<slug>.md (default true). |
theme |
preset (default/terminal/minimal/vibrant), accent shorthand, and per-token tokens overrides. Restyles the story content; the Starlight shell keeps its own theme. |
See the full reference in the executable-stories-astro README.
What you get
Section titled “What you get”/stories— an index of every scenario, categorised bygroupBy, each linking to a detail page with its Given/When/Then steps and docs. Styled out of the box; no CSS to wire./explorer— a searchable, filterable Scenario Explorer (by text, status, and tag)./journeys— ordered multi-scenario walkthroughs derived fromjourney:<id>:<n>tags, each rendered as full scenario cards (storyboards included) under one aggregate status. Embed one in MDX with<StoryJourney id="..." />./states— a thumbnail grid of the states the product verifiably has, fromstate:<name>tags;viewport:*variants render side by side. Non-UI scenarios appear with data-card thumbnails from theirstory.state()snapshots./drift— with two or more sources, compares each scenario’s status side by side and floats disagreements or missing scenarios first.- Auto-built nav — spread
storiesSidebar(config)into your Starlightsidebarand the Stories/Explorer links and your docs groups appear without hand-wiring. The nav stays fresh in dev: when a test run adds, renames, or removes scenarios, the integration triggers a dev-server restart so the sidebar rebuilds (status-only changes hot-reload without a restart). - Live trajectory — the shipped
<Trajectory />component shows “passed N → M since you started” across a watch session. - Agent endpoints —
/llms.txtindexes every scenario, and each story page has a plain-Markdown twin at/stories/<slug>.md, so the deployed site is consumable by agents andcurl, not just browsers. Disable withagentEndpoints: false. - Design context —
story.link()entries pointing at Figma, Zeplin, Sketch, or Abstract (or deliberately labelledDesign ...) appear on story and journey pages. The same link remains in the scenario’s normal docs.
If the CLI persists history, reuse that store in the site:
executable-stories format reports/raw-run.json --format html \ --history-file reports/history.jsonexport default defineExecutableStories({ source: '../reports/raw-run.json', historyFile: '../reports/history.json',});Journey history is aggregated by run: any failed member fails the journey run. The badge uses the same stable/unstable/flaky classification as the HTML report.
Persona views
Section titled “Persona views”views mounts audience lenses over the same scenarios — /for/product,
/for/design, /for/support — each a filtered, re-grouped index driven by
the tags your tests already carry:
views: [ { base: '/for/product', include: { tags: ['audience:stakeholder'] }, groupBy: 'tag' }, { base: '/for/design', include: { tags: ['storyboard'] } },],Each view appears in the sidebar under “Audiences” and renders the same
interactive index as /stories, filtered to its audience. The tag vocabulary
and per-persona recipes live in
Tagging for your audience.
Embedding scenarios in your own pages
Section titled “Embedding scenarios in your own pages”Authored MDX pages can pull scenarios in as live evidence, rendered from the same collection as the story pages — so an embed can never drift from the latest run:
import StoryScenario from 'executable-stories-astro/components/StoryScenario.astro';import StoryStatus from 'executable-stories-astro/components/StoryStatus.astro';
We cap discounts at 30% — enforced end-to-end(currently <StoryStatus id="checkout--caps-the-discount-at-30-percent" />):
<StoryScenario id="checkout--caps-the-discount-at-30-percent" /><StoryScenario/> renders the full scenario card (steps, status, failure
output, attached docs); <StoryStatus/> is an inline linked status pill. Both
accept the stable scenario id (copy it from the Explorer), the URL slug, or the
exact title, and render a visible callout when the id no longer matches — an
embed never silently disappears. This pairs with <VerifiedBy/> (frontmatter
verifiedBy: refs → a live pass/fail badge) for page-level verification.
Bringing in existing docs
Section titled “Bringing in existing docs”Hand-authored docs live under src/content/docs. The scaffold loads them with
authoredDocsLoader, a drop-in for Starlight’s docsLoader() that makes plain,
GitHub-style markdown work without edits:
- Auto-title from each file’s first
# H1(so frontmatter-free files import cleanly — the one field Starlight requires). - Cross-link rewriting so relative
./other.mdlinks resolve to routes instead of 404ing.
Point a docs source’s path at a folder outside the site and set base to
mount an external docs folder (e.g. another package’s docs/) under a URL prefix.
Emitting the run JSON
Section titled “Emitting the run JSON”The loader reads the raw run JSON, which your reporter writes only when you
set rawRunPath:
new StoryReporter({ formats: ['html'], rawRunPath: 'reports/raw-run.json' })Point the config’s source at that path.
Deploying
Section titled “Deploying”The scaffolded site is a standard Astro project — build it and deploy dist/:
pnpm buildRun your tests and regenerate the run JSON in CI before astro build so the
deployed site reflects the latest results. Works with Vercel, Netlify, GitHub
Pages, Cloudflare Pages, or any static host.
CLI reference
Section titled “CLI reference”init-astro
Section titled “init-astro”npx --package executable-stories-formatters executable-stories init-astro [directory]| Option | Default | Description |
|---|---|---|
directory |
story-docs |
Where to create the site |
--force |
false |
Overwrite if the directory exists |
--update |
false |
Merge any new template deps (the framework updates via pnpm update executable-stories-astro) |
Migrating from
build-docs? It generated Markdown intosrc/content/docs/stories/and has been removed in favour of the live integration, which renders stories from the run JSON with no generation step. Scaffold withinit-astroand runastro dev. (format --format astro-markdownstill exists for a one-off single-page Markdown export.)