nemo-gym-docs
$
npx mdskill add NVIDIA/skills/nemo-gym-docsMaintain NeMo Gym Fern docs by editing pages under fern/.
- Handles adding, updating, moving, or removing documentation pages.
- Integrates with Fern CLI and npm scripts for site generation.
- Mirrors changes between latest and v0.2 version trees automatically.
- Delivers updated documentation directly to the deployed Fern site.
SKILL.md
.github/skills/nemo-gym-docsView on GitHub ↗
---
name: nemo-gym-docs
description: >
Maintain the NeMo Gym Fern docs site — add, update, move, or remove pages
under fern/. Use for any documentation change. Triggered by: "edit docs",
"add doc page", "update docs", "rename page", "fix broken link", "add
redirect", "preview docs", "publish docs", any request that touches `fern/`.
---
# NeMo Gym Docs Maintenance
Unified skill for adding, updating, moving, and removing pages on the NeMo Gym Fern documentation site.
## Scope Rule
**ALL docs edits happen under `fern/`.** The legacy `docs/` directory is the original Sphinx source — do not add new pages there. Release notes, migration guides, and every new page belong under `fern/`.
**Two-version mirror.** Gym maintains two real version trees in parallel: `fern/versions/latest/` and `fern/versions/v0.2/`. Unless the user says otherwise, **every change to `latest` must be mirrored to `v0.2`** (and vice versa for back-ports). The PM is particular about fidelity between versions; do not let them drift.
## Layout at a Glance
```
fern/
├── fern.config.json # Org + Fern CLI version (currently 4.80.3)
├── package.json # `npm run dev|check|generate` — wraps `npx -y fern-api@latest`
├── docs.yml # Site config: instances, versions, tabs, redirects, libraries
├── versions/
│ ├── _nav_order.yml # Cross-version nav ordering
│ ├── latest.yml # Nav tree for current train
│ ├── latest/pages/ # MDX content for current train
│ ├── v0.2.yml # Nav tree for the 0.2 train
│ └── v0.2/pages/ # MDX content for the 0.2 train
├── components/ # Custom TSX (CTAButtons, NavButton, CustomFooter)
├── assets/ # Images, SVGs, favicon
├── main.css # Global theme overrides (NVIDIA green, badge spacing, etc.)
└── product-docs/ # GENERATED library reference (gitignored)
```
```
File system Published URL
────────────────────────────────────────────────── ──────────────────────────────────
fern/versions/latest/pages/get-started/quickstart.mdx docs.nvidia.com/nemo/gym/latest/get-started/quickstart
fern/versions/v0.2/pages/get-started/quickstart.mdx docs.nvidia.com/nemo/gym/v0.2/get-started/quickstart
```
## Operations
### Add a Page
1. Gather: page title, target section, filename (kebab-case `.mdx`), subdirectory under `fern/versions/latest/pages/`.
2. Create `fern/versions/latest/pages/<subdirectory>/<filename>.mdx`:
```mdx
---
title: "<Page Title>"
description: "One-line SEO description (or empty string)"
position: 3
---
# <Page Title>
<content>
```
3. If the parent folder is mounted in `latest.yml` with `title-source: frontmatter`, the page is auto-discovered — no nav edit needed. Otherwise add a `- page:` entry under the right `section:` in `fern/versions/latest.yml`.
4. **Mirror to `v0.2`**: copy the MDX to `fern/versions/v0.2/pages/<subdirectory>/<filename>.mdx` and update any `/latest/...` links in its body to `/v0.2/...`. Update `v0.2.yml` if a manual nav entry was needed.
### Update a Page
1. Locate by path, title, or keyword (`grep -rn` in `fern/versions/latest/pages/`).
2. **Content only** — edit the MDX directly, then mirror the same edit to the `v0.2` copy.
3. **Title change** — update the frontmatter `title:` and (if the parent uses `title-source: frontmatter`) nothing else; otherwise update the nav `- page:` entry too.
4. **Section move** — `git mv` the file, update its `path:` in the nav, fix all incoming links, mirror to `v0.2`.
5. **Slug change** — folders use the page filename for the slug. Renaming the file changes the URL; add a redirect in `fern/docs.yml` so the old URL keeps working.
### Remove a Page
1. Find incoming links: `grep -rn "<filename>" fern/versions/latest/pages fern/versions/v0.2/pages --include="*.mdx"`.
2. `git rm` the file from both `latest/` and `v0.2/`.
3. Remove the matching `- page:` block from `latest.yml` and `v0.2.yml` if it was a manual entry.
4. Fix or remove all incoming links.
5. Add a redirect in `fern/docs.yml` if the URL was public.
### Back-port to an Older Version
When `latest` and `v0.2` diverge intentionally (e.g. an API only exists in `latest`), do not mirror — but call out the divergence in the PR description so the PM can confirm.
### Worked Example: Adding a Page
Request: *"Add a how-to for collecting rollouts under Get Started."*
1. Create `fern/versions/latest/pages/get-started/rollout-collection.mdx`:
```mdx
---
title: "Collect Rollouts"
description: "Run the agent against your dataset and write results to JSONL"
position: 4
---
# Collect Rollouts
<content>
```
2. The `get-started` folder in `latest.yml` uses `title-source: frontmatter`, so the page appears automatically. `position: 4` controls ordering.
3. Mirror to `fern/versions/v0.2/pages/get-started/rollout-collection.mdx`. Replace any `/latest/...` links in the body with `/v0.2/...`.
4. `cd fern && npm run check && npm run dev`, verify both `/latest/get-started/rollout-collection` and `/v0.2/get-started/rollout-collection` render.
### Worked Example: Renaming a Slug (with Redirect)
Request: *"Rename `/latest/get-started/setup` to `/latest/get-started/detailed-setup`."*
1. `git mv fern/versions/latest/pages/get-started/setup.mdx fern/versions/latest/pages/get-started/detailed-setup.mdx`.
2. Mirror the rename to `v0.2`.
3. Add redirects in `fern/docs.yml`:
```yaml
redirects:
- source: "/latest/get-started/setup"
destination: "/latest/get-started/detailed-setup"
- source: "/v0.2/get-started/setup"
destination: "/v0.2/get-started/detailed-setup"
```
4. `grep -rn "/get-started/setup" fern/versions/` and update any incoming links in both versions.
---
## Content Guidelines
NeMo Gym uses **Fern-native MDX components directly**. Do not use GitHub `> [!NOTE]` syntax — it will not render.
| Purpose | Component |
|---|---|
| Neutral aside | `<Note>...</Note>` |
| Helpful tip | `<Tip>...</Tip>` |
| Informational callout | `<Info>...</Info>` |
| Warning | `<Warning>...</Warning>` |
| Error / danger | `<Error>...</Error>` |
| Card grid on index pages | `<Cards>` with `<Card title="..." href="...">` children |
| Status/scope tag inside a Card | `<Badge minimal outlined>tag</Badge>` (see below) |
Images live in `fern/assets/` (shared) or under a version's `pages/` (version-scoped). Reference with root-relative paths.
### Cards and Badges (PM is particular about fidelity)
Every `<Card>` on an index page should carry the same scope/status badges that the original Sphinx docs in `docs/` had. Mapping:
| Original `{bdg-*}` | Fern equivalent |
|---|---|
| `{bdg-primary}` | `<Badge intent="success" minimal outlined>...</Badge>` |
| `{bdg-warning}` | `<Badge intent="warning" minimal outlined>...</Badge>` |
| `{bdg-secondary}` | `<Badge minimal outlined>...</Badge>` (no intent) |
Valid intents: `success`, `note`, `tip`, `warning`, `error`, `info`, `launch`, `check`. Place badges as the last line inside the `<Card>`, separated by a blank line from the body text. The CSS in `main.css` (`.fern-card .fern-docs-badge`) handles vertical spacing from the description and horizontal spacing between adjacent badges — do not add inline `style=` props.
```mdx
<Cards>
<Card title="Quickstart" href="/latest/get-started/quickstart">
Install, start servers, and collect your first rollouts in one page.
<Badge intent="success" minimal outlined>start here</Badge> <Badge minimal outlined>5 min</Badge>
</Card>
</Cards>
```
When adding or editing a Card, **check the original `docs/<same-path>/index.md` for the badges that were on the corresponding `:::{grid-item-card}` directive** and reproduce them. Dropping badges silently is a regression.
## Frontmatter Fields
```yaml
---
title: "<Page Title>" # required — used for nav and <h1>
description: "" # required (may be empty string) — SEO
position: 1 # optional — orders auto-discovered pages within a folder
---
```
The MDX body should still open with `# <Page Title>` matching the frontmatter title. Folders using `title-source: frontmatter` in the version YAML pull the nav label from `title:`.
## Validate
First-time setup: authenticate the CLI against the `nvidia` Fern org via Google SSO (one-time, browser flow):
```bash
npx -y fern-api@latest login # opens browser → sign in with your @nvidia.com Google account
```
Run from `fern/` (no install step — scripts shell out to `npx -y fern-api@latest`):
```bash
npm run check # `fern check` — YAML + frontmatter validation
npm run dev # `fern docs dev` — localhost:3000 hot-reload preview
```
`fern check` must pass before commit. The dev server's broken-link warnings for cross-version links like `/latest/about` are **false positives** — Fern's local validator does not resolve the version slug from `docs.yml` against `latest.yml`. The published site renders them correctly.
To regenerate the autodoc library reference (gitignored under `product-docs/`):
```bash
npm run generate:library # `fern docs md generate`
```
## Commit & Preview
```bash
git add fern/
git commit -s -m "docs: <add|update|remove> <page-title>"
```
PRs that touch `fern/**` get an automatic Fern preview URL posted as a comment by `.github/workflows/fern-docs-preview-comment.yml`. No manual step needed.
```
┌─ fern-docs-ci.yml → fern check
PR (touches fern/) ─┼─ fern-docs-preview-build.yml → upload fern/ artifact (no secrets)
└─ fern-docs-preview-comment.yml → 🌿 preview URL comment
Push to main (touches docs/** or fern/**) → publish-fern-docs.yml → docs.nvidia.com/nemo/gym
Tag push (docs/v*) → publish-fern-docs.yml → docs.nvidia.com/nemo/gym
Manual dispatch → publish-fern-docs.yml → docs.nvidia.com/nemo/gym
```
The preview-comment + publish jobs require the `DOCS_FERN_TOKEN` repository or organization secret (from `fern token`).
## Publishing to Production
Production publishes on three triggers (see `.github/workflows/publish-fern-docs.yml`):
1. **Push to `main`** when `docs/**` or `fern/**` changes — continuous staging.
2. **Tag push** matching `docs/v*` — versioned release.
3. **Manual dispatch** from the Actions tab.
Tag format must be `docs/v<MAJOR>.<MINOR>.<PATCH>`. Do not push a tag unless the user asks.
```bash
git tag docs/v0.3.0
git push origin docs/v0.3.0
```
URL → version mapping:
```
docs.nvidia.com/nemo/gym/latest/... → latest train
docs.nvidia.com/nemo/gym/v0.2/... → 0.2 train
```
## Cutting a New Version Train
When the user ships a new version (e.g. `v0.3`):
1. Copy `fern/versions/latest/pages/` → `fern/versions/v0.3/pages/` (frozen snapshot of the previous "latest").
2. Copy `fern/versions/latest.yml` → `fern/versions/v0.3.yml` and rewrite all `./latest/` path prefixes to `./v0.3/`.
3. Replace `/latest/` link prefixes in the new `v0.3/pages/` body MDX with `/v0.3/`.
4. Add the version to `fern/docs.yml` `versions:` list with `slug: v0.3` and `availability: stable`. Keep the `latest` entry pointing at `versions/latest.yml`.
5. `latest/pages/` continues forward as the current dev train.
6. Tag `docs/v0.3.0` and push to publish.
## Debugging
| Symptom | Fix |
|---|---|
| `fern check` YAML error | 2-space indent; `- page:` inside `contents:`; `path:` is relative to the version YAML file |
| Page 404 in preview | `slug:` missing/duplicated in the same section; or `position:` collision in an auto-discovered folder |
| Broken-link warning for `/latest/...` cross-version link | False positive in `fern docs dev`; works on published site |
| `JSX expressions must have one parent element` | Wrap multi-element MDX content in `<>...</>` or a `<div>` |
| Old Sphinx URL breaks | Add a `redirects:` entry in `fern/docs.yml` |
| Library reference missing | `npm run generate:library` in `fern/` |
| Broken image | Path is relative to the MDX file; check `fern/assets/` exists |
| Card badges have no spacing | Don't add inline styles — `main.css` `.fern-card .fern-docs-badge` rules handle it; if missing, restore from the badge spacing commit |
| `latest` and `v0.2` show different content for the same page | Mirror the change you made to `latest` over to `v0.2` (or call out the intentional divergence in the PR) |
## Key References
| File | Purpose |
|---|---|
| `fern/docs.yml` | Site config, versions, redirects, libraries |
| `fern/versions/latest.yml` | Nav tree for the latest train |
| `fern/versions/v0.2.yml` | Nav tree for the 0.2 train |
| `fern/versions/_nav_order.yml` | Cross-version nav ordering |
| `fern/versions/<ver>/pages/` | MDX content for a version |
| `fern/components/` | Custom TSX (CTAButtons, NavButton, CustomFooter) |
| `fern/assets/` | Shared images, SVGs, favicon |
| `fern/main.css` | Global theme overrides — NVIDIA green, card/badge spacing |
| `fern/package.json` | `npm run check|dev|generate|generate:library` — each wraps `npx -y fern-api@latest` |
| `.github/workflows/fern-docs-*.yml` | CI: check, preview build, preview comment |
| `.github/workflows/publish-fern-docs.yml` | CI: publish to docs.nvidia.com/nemo/gym |
| `docs/` | Legacy Sphinx source (read-only reference for badge fidelity) |
---