Contributing docs
How to set up the docs site locally, write a new page, and avoid the patterns that make documentation feel AI-generated.
The docs site lives in a separate repository from the framework. Content is MDX under content collections, layout is plain Astro 6 with no Starlight, and search is Pagefind. Lychee checks every link in CI.
Contributions land in two flavors. Hand-authored pages — Build, Concepts, Operate, Agents, Resources — are MDX you edit directly. Generated pages — SDK reference, CLI reference, examples — are emitted by Python scripts under site/scripts/python/; you do not edit the MDX, you edit the source code in flux-src/ or the annotation files that augment the generator output.
Repo layout
flux-docs/
├── site/ # the Astro app
│ ├── src/
│ │ ├── content/
│ │ │ ├── docs/ # all MDX content, one folder per top-level section
│ │ │ │ ├── get-started/
│ │ │ │ ├── build/
│ │ │ │ ├── agents/
│ │ │ │ ├── concepts/
│ │ │ │ ├── operate/
│ │ │ │ ├── reference/
│ │ │ │ ├── examples/
│ │ │ │ ├── deployment/
│ │ │ │ ├── integrations/
│ │ │ │ └── resources/
│ │ │ └── _annotations/ # editorial overlays for generated pages
│ │ ├── components/ # Astro components (Tabs, Admonition, Code)
│ │ ├── layouts/
│ │ └── styles/
│ ├── scripts/
│ │ └── python/ # generators for SDK / CLI / Examples
│ │ ├── generate_sdk_ref.py
│ │ ├── generate_cli_ref.py
│ │ ├── generate_examples.py
│ │ └── examples-order.yml # editorial ordering for example pages
│ └── package.json
├── flux-src/ # the Flux framework, checked out as a sibling
├── docs/ # the project's own design and roadmap docs
└── bin/ # bash helpers (setup, regen-check)
flux-src/ is the framework checkout the generators read from. It is set up via bin/setup-flux-src.sh; treat it as read-only when editing docs.
Local development
# One-time: clone alongside flux-src
git clone git@github.com:<your-fork>/flux-docs.git
cd flux-docs
bash bin/setup-flux-src.sh # clones flux into ../flux-src and creates a venv
# Daily workflow
cd site
npm install
npm run dev # local dev server on http://localhost:4321
Node 22.12 or newer is required (engines.node in site/package.json). The dev server has hot reload on MDX changes and shows broken links inline.
Regenerating from flux-src/:
npm run regen # regenerate SDK + CLI + examples in one shot
npm run regen:sdk # SDK reference only
npm run regen:cli # CLI reference only
npm run regen:examples # examples only
npm run regen:check # verify generators produce a clean diff
Run npm run regen after you pull a new flux-src/ or after the framework changes a signature you care about.
Frontmatter
Every page needs four frontmatter fields. The shape is:
---
title: Defining workflows
description: One sentence under 200 characters, used in search and meta tags.
sidebar:
order: 1
diataxis: how-to
---
title— the page title; rendered as the H1.description— one sentence used by Pagefind, llms.txt, and the meta description tag.sidebar.order— numeric ordering within the section. Sibling pages withorder: 1, 2, 3, ….diataxis—tutorial,how-to,reference, orexplanation. Drives sidebar grouping and the llms.txt classification.
The section’s _meta.yml carries the section label and order:
label: Build
order: 2
Adding a new page
- Pick the section folder under
site/src/content/docs/<section>/. - Create
<slug>.mdxor<subsection>/<slug>.mdx. - Set the frontmatter (above).
- Write the page. Use components from
src/components/for code tabs, admonitions, and callouts. - Cross-link to neighboring pages. Lychee in CI verifies every link.
- Run
npm run devand check the page renders cleanly.
For a new section, add a folder, an _meta.yml, and an index.mdx. Match the style of site/src/content/docs/resources/index.mdx — short prose introducing each subsection with inline links.
Style guide essentials
Voice: terse, technical, no marketing. The reader is an engineer with limited time who needs the answer or the example fast.
- No marketing language. “Powerful”, “seamless”, “leverage”, “robust”, “comprehensive”, “cutting-edge”, “best-in-class” — strip them all.
- No filler openings. “Let’s dive in”, “In this guide”, “Welcome to”. Open with the thing the page is about.
- No rule-of-three openers. “Fast, reliable, scalable” is an AI tell. Pick the one claim the page supports and write it.
- No em-dash overuse. Em-dashes are fine sparingly. When every paragraph has one, the page reads as AI-generated.
- No inline-header bullets. Bullets that start with a bolded phrase followed by a colon (“Setup: Run…”) are an AI pattern. Either write the bullet as a sentence or promote the bolded phrase to a subheading.
- No “the right primitive when”. That phrasing pattern — “X is the right primitive when Y” — is overused by models trained on docs. Just say “use X when Y”.
- No vague attribution. “Studies show”, “experts agree”, “many users have found” without a citation. Either cite or cut.
- Show, do not tell. Every claim that has a code example should have it on the page. Code samples must be runnable against current Flux (
flux-core0.56.0 at time of writing); broken code is worse than no code.
The patterns above come from review of phases 1 through 10 of this site. They are tells reviewers look for during PR review.
Code samples
Code samples render through Shiki with Python as the primary language. Use the Tabs component when an operation has both a Python SDK form and a CLI form:
import Tabs from '@components/Tabs.astro'
import TabItem from '@components/TabItem.astro'
<Tabs>
<TabItem label="Python">
```python
hello_world.run("World")
```
</TabItem>
<TabItem label="CLI">
```bash
flux workflow run hello_world '"World"'
```
</TabItem>
</Tabs>
Multi-language tabs (Python / TypeScript / Go) are scaffolded for the future; today only Python is populated. Do not write speculative TypeScript or Go samples — leave the tab off.
Generated content
Three sections are emitted by scripts:
- SDK reference (
reference/sdk/) — generated fromflux-src/flux/__init__.pyand decorated functions byscripts/python/generate_sdk_ref.py. Do not edit the MDX directly. - CLI reference (
reference/cli/) — generated from the Click command tree byscripts/python/generate_cli_ref.py. - Examples (
examples/) — generated fromflux-src/examples/*.pybyscripts/python/generate_examples.py.
To change generated content, you have two paths:
- Edit the source in
flux-src/— fix the docstring, rename the argument, rewrite the example. This is the right fix for most issues. After your framework PR merges, re-runnpm run regenhere. - Add an annotation — drop a YAML or MDX file under
site/src/content/_annotations/mirroring the generated page’s path. The generator merges annotations on top of its output, so editorial framing (intro paragraphs, related-pages lists, “why this matters” sidebars) lives in annotations without modifying the source.
The annotation system was introduced in Phase 2 to keep editorial prose out of framework docstrings. See the existing files under _annotations/ for the shape.
Direct edits to generated MDX files will not survive the next npm run regen. CI runs npm run regen:check and fails the PR if the generator output diverges from what is committed.
Cross-links and broken-link policy
Every link to another page goes through the rendered route, not the file path:
See [Defining workflows](/build/workflows/defining-workflows) for the full surface.
Lychee runs in CI on every PR and on cron against the deployed site. Broken internal links fail the build; broken external links open an issue. When a section is not yet shipped, add the link anyway with the future route — lychee has an exclude list for forward references (see lychee.toml). Phase shipping then removes the exclude.
Pull request workflow
1. Branch off main git checkout -b docs/<short-name>
2. Make the change one logical change per PR
3. Run regen if relevant npm run regen
4. Verify with dev server npm run dev, check the page renders
5. Run the link checker npm run build (runs lychee offline)
6. Commit Co-Authored-By: lines are allowed here
7. Open the PR describe the why, scope, and any version-pin
8. Respond to review commit, push, then reply
What reviewers look for:
- Frontmatter is complete (
title,description,sidebar.order,diataxis). - The page is technically correct against the current Flux version. State the version explicitly when a behavior is version-specific.
- The voice matches the rest of the site — no marketing, no em-dash carpets, no rule-of-three openers.
- Cross-links are valid and bidirectional where it makes sense.
- Generated content was not edited directly; annotations were used instead.
- Code samples are runnable. If a sample needs an API key, the page says so.
Where to ask
- GitHub Issues on
flux-docs— for typos, broken links, or larger missing-content reports. - GitHub Discussions — for “should this be a separate page?” or “what is the right home for this content?” — see Support and community.
Small fixes — typos, broken links, a clearer sentence — do not need an issue first. Open the PR.