- name
- dynamo-docs
- description
- Adds, updates, moves, or removes content on the Dynamo Fern docs site — standard docs pages, catalog-driven recipe and feature-benchmark pages, examples, recipes, and translations — keeping everything in line with the documentation style guide. Use for any change under docs/, recipes/, or examples/ (new page, edit, tab or section move, rename, removal, recipe/benchmark page, .zh-CN translation, version cut), when deciding which docs tab a page belongs in (Kubernetes Guide vs CLI Guide vs Reference vs Use Cases), and whenever content needs its frontmatter, headings, links, callouts, or terminology fixed.
- license
- Apache-2.0
- metadata
- {"author":"NVIDIA","tags":["dynamo","docs","fern","style-guide"]}
# Dynamo Docs Maintenance
<!--
SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: CC-BY-4.0
-->
Unified skill for adding, updating, moving, and removing content on the Dynamo Fern documentation
site, in line with the project's authoring guides.
Two authoring guides govern this work; read whichever applies before writing:
- [`docs/fern/pages/community/contributing/documentation/documentation-style-guide.md`](../../../docs/fern/pages/community/contributing/documentation/documentation-style-guide.md) — the standard for **every** page: frontmatter, headings, prose, terminology, links, callouts. The must-fix subset is distilled in [Style Guide Is the Standard](#style-guide-is-the-standard) and [Content Rules](#content-rules) below.
- [`docs/fern/pages/recipes/_catalog/README.md`](../../../docs/fern/pages/recipes/_catalog/README.md) — the standard for **recipe and feature-benchmark pages** (the catalog contract, the `.mdx` page blueprint, and the pure-CSS target picker). See [Add a Recipe or Feature Benchmark Page](#add-a-recipe-or-feature-benchmark-page).
## Branch Rule
**ALL edits happen on `main` (or a feature branch based on `main`).**
The `docs-website` branch is CI-managed and must **never** be edited by hand.
## Style Guide Is the Standard
Every page under `docs/` (and the READMEs under `examples/` and `recipes/`) follows the
[Documentation Style Guide](../../../docs/fern/pages/community/contributing/documentation/documentation-style-guide.md)
(`docs/fern/pages/community/contributing/documentation/documentation-style-guide.md`). Read it before
writing content. The `Docs Lint` job (`docs/fern/scripts/docs_lint.py`) enforces a **must-fix** subset on every
PR — get these right or the checks fail:
- **SPDX header** on every file, copyright range `2025-2026`. Fern pages put the two `#` lines
*inside* the `---` frontmatter; plain READMEs use an HTML-comment block.
- **Frontmatter with at least one metadata key** (`title`/`subtitle`/`sidebar-title`) and **no body
`# H1`**. Fern renders the page H1 from the nav `page:` value, so a body `# H1` produces a
duplicate title — and a bare `#` SPDX line left in the body also renders as an H1. Start the body
at `##`.
- **A nav entry** in `docs/fern/index.yml`, under the right tab, for every new page — a page not in
the nav is unreachable.
- **Links**: relative path *with extension* within `docs/` (`[Routing](router-concepts.md)`);
absolute `https://github.com/ai-dynamo/dynamo/blob/main/<path>` URL for targets outside `docs/`
(examples, recipes, source; `/tree/main/` for a directory). No `../` path that escapes `docs/`, and
never a hardcoded `https://docs.nvidia.com/...` link to a page in this repo. Link text names the
destination, never "click here".
- **No internal or sensitive references**: NVBug/JIRA/Linear IDs, internal hostnames, secrets,
`TODO`/`FIXME`.
Everything else in the style guide (page types, heading case, terminology, list and code-fence
formatting, the pre-merge checklist) is guidance — the high-value rules are distilled in
[Content Rules](#content-rules) below; apply them and deviate only with a reason.
## Content Rules
Apply these on every page so the result reads like a person wrote it and passes review without a
round-trip to the style guide. These are defaults; deviate with a reason.
- **Page type (Diátaxis).** Each page serves one need — *tutorial* (a tab's `getting-started/`),
*how-to* (a tab's feature or operations directory), *reference* (`pages/reference/`, for
flags/APIs/config), or *explanation* (`pages/developer-guide/`). Don't blend a how-to into a flag
reference; split and cross-link.
- **Headings.** Title Case for short label / noun-phrase headings ("Routing Behavior"); sentence
case for full-phrase headings ("Choosing a checkpoint flow"). Be consistent within a page. No end
punctuation. Logical `##` → `###` hierarchy, no skipped levels. Renaming a heading breaks inbound
`#anchor` links — rename deliberately.
- **Terminology, exact casing.** Backends: **vLLM**, **SGLang**, **TensorRT-LLM** (or **TRT-LLM**) —
never "vllm", "Sglang", "TensorRT LLM". **NVIDIA Dynamo** on first mention, then **Dynamo**; **KV
router**, **NIXL**, **GPU**; **Kubernetes**, not "k8s", in prose. Expand acronyms on first use
("Time To First Token (TTFT)"). Use one word per concept.
- **Inclusive terms.** "denylist"/"allowlist", not "blacklist"/"whitelist"; "primary"/"replica", not
"master"/"slave".
- **Cut marketing and bombast.** Remove "seamless, robust, powerful, blazing-fast, cutting-edge,
effortless, unlock, leverage, delve, comprehensive, rich ecosystem, world-class, game-changing".
Cut filler ("it's important to note", "simply", "just", "in order to") and difficulty words
("easy", "easily"). Start sentences with a verb; active voice; present tense; second-person
imperative. Name the flag/default/command, not "configure the appropriate settings". Avoid the
em-dash-aside tic.
- **Procedures.** Condition before instruction ("To enable KV-aware routing, set `--router-mode
kv`", not the reverse). One action per numbered step.
- **Links.** Follow the must-fix Links rule in
[Style Guide Is the Standard](#style-guide-is-the-standard) (relative + extension inside `docs/`,
absolute GitHub URL outside, no `../` escape, no `docs.nvidia.com` self-link).
- **Code fences** always tag a language (`bash`, not `sh`); no `$`/`#` prompt prefixes; put output in
its own `text` block. Wrap flags, paths, and `DYN_*` env vars in backticks in prose.
- **Lifecycle.** Mark preview features **Experimental.** and legacy ones **Deprecated.** (with a
`> [!WARNING]`); note availability for new features ("Available since v0.X").
## Operations
Pick your operation:
- Standard `.md` doc page → [Add a Page](#add-a-page)
- Rendered recipe / feature-benchmark page (`.mdx` + catalog triple) → [Add a Recipe or Feature Benchmark Page](#add-a-recipe-or-feature-benchmark-page)
- Code under `examples/` or `recipes/` → [Add an Example or Recipe (code)](#add-an-example-or-recipe-code)
- Edit, move, or remove existing content → [Update a Page](#update-a-page), [Remove a Page](#remove-a-page) (recipes: [Move, defer, or remove a recipe](#move-defer-or-remove-a-recipe))
- Chinese translation or version cut → [Translations and Versioned Navs](#translations-and-versioned-navs)
### Add a Page
1. **Pick the tab, then the sibling.** Choose the tab from
[Navigation](#navigation-tabs-and-sections) — this is the decision that matters, because fixing it
later costs a move plus a redirect. Then open `docs/fern/index.yml`, find the existing page closest
in topic to yours *within that tab*, and join **that** section, putting your file in that sibling's
subdirectory. Page *type* narrows the field (tutorial → the tab's `getting-started/`, how-to → a
feature or operations directory, reference → `pages/reference/`, explanation →
`pages/developer-guide/`), but the nearest existing page is the tie-breaker — read the file, don't
guess from section names. Note the tab, the section, the subdirectory, a kebab-case filename, and
the page title.
2. Create `docs/fern/pages/<tab-dir>/<subdirectory>/<filename>.md` (use `.mdx` if the page needs Fern
components). Frontmatter carries the SPDX header plus at least one metadata key; the body starts
at `##` with a short intro — **no body `# H1`**:
```markdown
---
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
title: <Page Title>
subtitle: <One-line description of the page>
---
Short intro paragraph stating what the page covers.
## <First section>
```
3. Add a nav entry in `docs/fern/index.yml` under the section you chose in step 1 — a `- page:` in that
section's `contents:`, 2-space indent, `path:` relative to `docs/fern/` so it always starts with
`pages/` (see [Navigation](#navigation-tabs-and-sections) for the grammar):
```yaml
- page: <Page Title>
path: pages/<tab-dir>/<subdirectory>/<filename>.md
```
### Update a Page
1. Locate by file path, page title, or keyword search (`grep -rn` in `docs/fern/pages/`).
2. **Content only** -- edit the markdown file directly; keep it within the style guide.
3. **Title/label change** -- update the frontmatter (`title`/`sidebar-title`) and the `- page:` name
in `docs/fern/index.yml`.
4. **Section or tab move** -- `git mv` the file when the directory changes, move the nav entry to the
new section (and tab), and update every incoming link.
> [!IMPORTANT]
> A page's URL joins the slug of every nav level that contributes one — tab, then section (sections
> nest), then the page. Each slug comes from the nav **label**, not the file path, unless an explicit
> `slug:` overrides it or that level carries `skip-slug: true`. A skipped tab still leaves its
> sections in the URL: `pages/developer-guide/advanced-customizations/building-from-source.md` serves
> at `/dynamo/dev/advanced-customizations/building-from-source`. So **renaming a label changes the URL
> even when the file doesn't move**, and moving a file between directories changes nothing unless its
> label, section, or tab changes. Add a redirect **only when the URL actually changes** — a file-only
> `git mv` that leaves the tab, section, label, and explicit `slug:` alone needs none, and adding one
> yields a self-redirect or a slug that doesn't exist. When the URL does change, add a
> **dev-scoped** redirect to the `redirects:` list in `docs/fern/docs.yml`: `/dynamo/dev/<old>` →
> `/dynamo/dev/<new>`. Editing `docs/fern/index.yml` regenerates only the `dev` nav, so do **not** redirect
> the unversioned (`/dynamo/<old>`) or `/dynamo/latest/<old>` forms — those serve **Latest**, a frozen
> release snapshot that `main` edits don't touch, and a redirect there would break a working URL. See
> [Redirects and the version model](#redirects-and-the-version-model).
### Remove a Page
Removing a page is destructive and breaks live URLs. Confirm with the user before step 2, and show
them the incoming links and redirects you found in steps 1 and 2.
1. Find incoming links: `grep -rn "<filename>" docs/`.
2. Find redirects that already point at the page: grep its published URL in `docs/fern/docs.yml` as
a `destination:`. Each hit has to be retargeted, or it starts serving a 404.
3. Remove the file, matching its real extension — pages are `.md` or `.mdx`:
`git rm docs/fern/pages/<tab-dir>/<subdirectory>/<filename>.<ext>`.
4. Remove the `- page:` block from `docs/fern/index.yml`. If it was the last page in a section, remove the
whole `- section:` block.
5. Fix or remove every incoming link found in step 1, retarget every redirect found in step 2, and add
a `docs/fern/docs.yml` redirect for the page's own URL if it had a stable one.
### Add a Recipe or Feature Benchmark Page
Recipe and feature-benchmark pages are **catalog-driven** and use `.mdx` (they embed a pure-CSS
target picker). Authoritative guide:
[`docs/fern/pages/recipes/_catalog/README.md`](../../../docs/fern/pages/recipes/_catalog/README.md).
Each page is a triple — page + catalog entry + nav:
1. **Write the `.mdx`** at `docs/fern/pages/recipes/model-recipes/<slug>.mdx` (or `docs/fern/pages/recipes/feature-benchmarks/<slug>.mdx`). Frontmatter
carries SPDX + `title` + one-sentence `subtitle`; body starts with a short intro, then the target
picker — multi-target pages use the radio picker, single-target pages use the **static** form
(exact classes under [Target picker](#target-picker) below) — then the fixed section order:
`## Prerequisites` → `## Deploy` → `## Smoke Test` → `## Benchmark` → `## Expected Performance`
(omit if no numbers) → `## Compare All Targets` (multi-target only) → `## Related Feature
Benchmarks` → `## Notes` → `## Source`. **MDX rule:** blank line after `<div ...>` and before
`</div>`; keep code fences at column 0.
2. **Add a catalog entry** — one file at `docs/fern/pages/recipes/_catalog/recipes/<id>.yaml` (or
`docs/fern/pages/recipes/feature-benchmarks/_catalog/benchmarks/<id>.yaml`), SPDX header, exactly one object. **Read the
sibling `schema.json` first for the exact field set** (`docs/fern/pages/recipes/_catalog/schema.json` for
recipes, `docs/fern/pages/recipes/feature-benchmarks/_catalog/schema.json` for benchmarks — they are **different** schemas) —
each is `additionalProperties: false`, so an invented or misspelled key fails validation; don't
guess the shape. A **recipe** entry requires `id`,
`title`, `provider`, `model`, `status`, `targets`, `maintainer`, and each `targets[]` item
requires `id`, `recommended`, `hardware`, `runtime`, `topology`, `techniques`, `workload`,
`deploy`, `expected_performance`. Internal `id:` **must equal the filename**; active entries carry
`page:`, deferred ones carry `deferred_reason` and omit `page:`. Add the `<id>` to the matching
`_catalog/index.yaml` (`recipes:` for active, `deferred_recipes:` for deferred). A recipe's
`provider:` must be a key in `_catalog/providers.yaml`; add a new model maker there first.
3. **Navigation**: for a **recipe**, run `python3 docs/fern/scripts/gen_recipe_nav.py` (the
`gen-recipe-nav` pre-commit hook does it for you). It generates the Model Recipes sidebar in
GitHubで見る