Fern docs authoring
Write and edit documentation on a Fern site. SKILL.md is the index: follow the
principles below, then read the references/ file that matches the
task before writing. Don't work from this page alone when a reference exists.
Scope: this skill governs Fern docs content only — MDX pages, navigation,
docs.yml and related config, snippets, changelog entries, custom components,
and landing pages. It does not govern repo governance or tooling files that
happen to live in the same repo, such as CLAUDE.md, AGENTS.md,
STYLE-GUIDE.md, and contributor guides. Never apply the principles below —
"one canonical home," "prefer editing over creating," consolidation — to those
files. Leave them alone unless the user explicitly asks you to edit them.
Fern resources
Fern's configuration evolves. Look things up rather than guessing.
Routing
| Task |
Read |
| Writing or editing a changelog entry |
references/changelog.md |
| Setting up a product switcher, adding a product, or refactoring nav into products |
references/products.md |
| Moving, renaming, or deleting a page, or any edit that changes a published URL |
references/redirects.md |
| Restricting pages or content by role (RBAC), or wiring docs into an auth method (password, SSO, JWT, OAuth) |
references/authentication.md |
| Editing the same content across multiple pages, or adding generic/boilerplate content (e.g. "contact support") |
references/snippets.md |
| Translating pages into another language, adding a language, or updating existing translations (multi-language Fern repo) |
references/translations.md |
Core principles
- Defer to the repo's own conventions. When a docs repo has an established
pattern, voice, or structure — a
CLAUDE.md, a style guide, or just the
consistent practice of surrounding pages — follow it over the guidance here.
This skill is the default, not an override.
- Write what the reader needs to succeed — no more. Every sentence earns its place.
- Prefer editing over creating. Search the repo for a page that already
covers the topic and update it instead of adding a duplicate.
- Make minimal, precise edits. Don't rewrite a page when a paragraph fix will do.
- Push back when something seems wrong. Explain why rather than complying silently.
- Ask when unclear. Don't fill gaps with assumptions.
- Never fabricate. If you don't know a config key or behavior, look it up
(MCP server or docs) or say so. Don't invent frontmatter or YAML fields.
- Cross-reference. When you mention a concept documented elsewhere, link to it
so readers can find their way.
- Preserve URLs when they change. Any edit that moves, renames, or deletes a
page — or changes a slug, section, or product — can change a published URL.
When it does, set up redirects
from the old path (see
references/redirects.md) so inbound links and search
rankings survive.
Links
Internal links are URL paths derived from this repo's own docs.yml and page
frontmatter — not file paths on disk or relative paths. Nearly every edit
touches a link, so get this right every time.
A page URL is <base-path>/<product-slug>/<rest>:
- Base path — the prefix in your docs URL (e.g.
/learn, /docs; may be empty).
- Product slug — the product's
slug in fern/docs.yml. Omitted for a
product with no slug: (such as a default single Home product).
<rest> — found by step 1 or step 2 below.
To find <rest>:
- Open the target page and check its frontmatter for
slug:. A frontmatter
slug is absolute within the product: it is <rest> on its own, and it
replaces the entire section/folder hierarchy. The section's slug does not
appear. Do not walk the navigation.
- Otherwise, walk
docs.yml within the product, from section through any
folders to the page. Each level contributes one slug:
- Its explicit
slug: if set.
- Otherwise auto-derived from the display name: lowercased, spaces to
hyphens, special characters stripped (so
v3 (Latest) becomes
v-3-latest). Auto-derivation isn't always obvious — verify, don't assume.
- In folder-based navigation, a page's slug comes from its filename, not
a display name (
quick-start.mdx to quick-start).
- Omit any level with
skip-slug: true — it contributes no segment.
Example — page ./pages/ai/overview.mdx under section "AI features", in product
docs, base path /learn:
- with frontmatter
slug: ai-ai → /learn/docs/ai-ai (the ai-features
section slug is dropped)
- with no frontmatter slug →
/learn/docs/ai-features/overview (section
auto-slug ai-features + page auto-slug overview)
Section slugs frequently differ from folder names, so never guess the URL from
the directory layout. If you can't resolve a path from docs.yml and the page's
frontmatter, say so rather than guessing.
Anchors append #heading, and only resolve for real ##/### Markdown
headings — not for JSX title props like <Step title>, <Tab title>,
<Accordion title>, or <Card title>.
Not internal links (leave as-is): external https:// URLs, image paths
(./images/...), snippet includes (<Markdown src="/snippets/..." />), and
same-page anchors (#section).
Cross-referencing
When you document new functionality — a new page, or new behavior on an existing
one — related pages usually need a pointer to it, or the new content is hard to
find from where readers actually start. This applies to small edits too, not
just new pages.
One canonical home. The full explanation lives on one page; every other
page that touches the topic links to it instead of restating it. If you're
copying more than a sentence or two onto another page, it belongs on the
canonical page.
Find the targets. Grep the docs for the feature name and one or two related
keywords, then read each hit and decide whether a pointer is warranted:
grep -rln "<feature>\|<keyword>" fern --include="*.mdx"
Common targets: pages for behavior the feature affects, adjacent feature pages,
and overview or landing pages.
Use the lightest form that works: an inline link inside an existing
sentence, then a <Note> for a secondary aside, then a new ## section, then
a new page. Inline links and Notes add no maintenance surface; new pages and
sections do.
Phrase inline links naturally — never "See [page]." Put the link on a noun
phrase already in the sentence, not a tacked-on pointer sentence. Don't wrap a
lone link in a <Tip> whose only job is to host it.
- Good: "Each request counts against your rate limit, which resets hourly."
- Bad: "Requests are rate limited. See the rate limits reference for details."
- Bad: a standalone
<Tip> containing only "For more, see rate limits."
Frame by function, not plumbing. Contrast what each feature does ("X
decides A; Y decides B"), not that they share a config key or sit in the same
directory. If the only thing linking two features is the same YAML key, it's
not worth a cross-reference.
1---2name: fern-docs3description: Author and edit Fern documentation: MDX pages, navigation, docs.yml config, custom components, landing pages, and changelog entries. Use when working in a Fern docs repo (a fern/ directory with docs.yml). Routes to a detailed reference per task.4---56# Fern docs authoring78Write and edit documentation on a Fern site. `SKILL.md` is the index: follow the9principles below, then read the `references/` file that matches the10task before writing. Don't work from this page alone when a reference exists.1112**Scope: this skill governs Fern docs content only** — MDX pages, navigation,13`docs.yml` and related config, snippets, changelog entries, custom components,14and landing pages. It does **not** govern repo governance or tooling files that15happen to live in the same repo, such as `CLAUDE.md`, `AGENTS.md`,16`STYLE-GUIDE.md`, and contributor guides. Never apply the principles below —17"one canonical home," "prefer editing over creating," consolidation — to those18files. Leave them alone unless the user explicitly asks you to edit them.1920## Fern resources2122Fern's configuration evolves. Look things up rather than guessing.2324- **Docs:** https://buildwithfern.com/learn/docs/getting-started/overview.md25 (append `.md` to any docs URL for clean markdown to fetch)26- **Page index:** https://buildwithfern.com/learn/llms.txt27- **MCP server** — connect your agent to Fern's live docs and query it for any28 syntax or behavior you're unsure of. The endpoint works with any MCP client;29 for Claude Code:3031 ```bash32 claude mcp add --transport http fern https://buildwithfern.com/learn/_mcp/server33 ```3435## Routing3637| Task | Read |38|------|------|39| Writing or editing a changelog entry | `references/changelog.md` |40| Setting up a product switcher, adding a product, or refactoring nav into products | `references/products.md` |41| Moving, renaming, or deleting a page, or any edit that changes a published URL | `references/redirects.md` |42| Restricting pages or content by role (RBAC), or wiring docs into an auth method (password, SSO, JWT, OAuth) | `references/authentication.md` |43| Editing the same content across multiple pages, or adding generic/boilerplate content (e.g. "contact support") | `references/snippets.md` |44| Translating pages into another language, adding a language, or updating existing translations (multi-language Fern repo) | `references/translations.md` |4546## Core principles4748- **Defer to the repo's own conventions.** When a docs repo has an established49 pattern, voice, or structure — a `CLAUDE.md`, a style guide, or just the50 consistent practice of surrounding pages — follow it over the guidance here.51 This skill is the default, not an override.52- **Write what the reader needs to succeed — no more.** Every sentence earns its place.53- **Prefer editing over creating.** Search the repo for a page that already54 covers the topic and update it instead of adding a duplicate.55- **Make minimal, precise edits.** Don't rewrite a page when a paragraph fix will do.56- **Push back when something seems wrong.** Explain why rather than complying silently.57- **Ask when unclear.** Don't fill gaps with assumptions.58- **Never fabricate.** If you don't know a config key or behavior, look it up59 (MCP server or docs) or say so. Don't invent frontmatter or YAML fields.60- **Cross-reference.** When you mention a concept documented elsewhere, link to it61 so readers can find their way.62- **Preserve URLs when they change.** Any edit that moves, renames, or deletes a63 page — or changes a slug, section, or product — can change a published URL.64 When it does, set up [redirects](https://buildwithfern.com/learn/docs/seo/redirects.md)65 from the old path (see `references/redirects.md`) so inbound links and search66 rankings survive.6768## Links6970Internal links are URL paths derived from **this repo's own `docs.yml` and page71frontmatter** — not file paths on disk or relative paths. Nearly every edit72touches a link, so get this right every time.7374A page URL is `<base-path>/<product-slug>/<rest>`:7576- **Base path** — the prefix in your docs URL (e.g. `/learn`, `/docs`; may be empty).77- **Product slug** — the product's `slug` in `fern/docs.yml`. Omitted for a78 product with no `slug:` (such as a default single Home product).79- **`<rest>`** — found by step 1 or step 2 below.8081To find `<rest>`:82831. **Open the target page and check its frontmatter for `slug:`.** A frontmatter84 slug is **absolute within the product**: it *is* `<rest>` on its own, and it85 replaces the entire section/folder hierarchy. The section's slug does not86 appear. Do not walk the navigation.872. **Otherwise, walk `docs.yml`** within the product, from section through any88 folders to the page. Each level contributes one slug:89 - Its explicit `slug:` if set.90 - Otherwise auto-derived from the display name: lowercased, spaces to91 hyphens, special characters stripped (so `v3 (Latest)` becomes92 `v-3-latest`). Auto-derivation isn't always obvious — verify, don't assume.93 - In folder-based navigation, a page's slug comes from its **filename**, not94 a display name (`quick-start.mdx` to `quick-start`).95 - **Omit any level with `skip-slug: true`** — it contributes no segment.9697Example — page `./pages/ai/overview.mdx` under section "AI features", in product98`docs`, base path `/learn`:99100- with frontmatter `slug: ai-ai` → `/learn/docs/ai-ai` (the `ai-features`101 section slug is dropped)102- with no frontmatter slug → `/learn/docs/ai-features/overview` (section103 auto-slug `ai-features` + page auto-slug `overview`)104105Section slugs frequently differ from folder names, so never guess the URL from106the directory layout. If you can't resolve a path from `docs.yml` and the page's107frontmatter, say so rather than guessing.108109**Anchors** append `#heading`, and only resolve for real `##`/`###` Markdown110headings — not for JSX title props like `<Step title>`, `<Tab title>`,111`<Accordion title>`, or `<Card title>`.112113**Not internal links** (leave as-is): external `https://` URLs, image paths114(`./images/...`), snippet includes (`<Markdown src="/snippets/..." />`), and115same-page anchors (`#section`).116117## Cross-referencing118119When you document new functionality — a new page, or new behavior on an existing120one — related pages usually need a pointer to it, or the new content is hard to121find from where readers actually start. This applies to small edits too, not122just new pages.123124- **One canonical home.** The full explanation lives on one page; every other125 page that touches the topic links to it instead of restating it. If you're126 copying more than a sentence or two onto another page, it belongs on the127 canonical page.128- **Find the targets.** Grep the docs for the feature name and one or two related129 keywords, then read each hit and decide whether a pointer is warranted:130131 ```bash132 grep -rln "<feature>\|<keyword>" fern --include="*.mdx"133 ```134135 Common targets: pages for behavior the feature affects, adjacent feature pages,136 and overview or landing pages.137- **Use the lightest form that works:** an inline link inside an existing138 sentence, then a `<Note>` for a secondary aside, then a new `##` section, then139 a new page. Inline links and Notes add no maintenance surface; new pages and140 sections do.141- **Phrase inline links naturally — never "See [page]."** Put the link on a noun142 phrase already in the sentence, not a tacked-on pointer sentence. Don't wrap a143 lone link in a `<Tip>` whose only job is to host it.144 - Good: "Each request counts against your [rate limit](...), which resets hourly."145 - Bad: "Requests are rate limited. See the [rate limits reference](...) for details."146 - Bad: a standalone `<Tip>` containing only "For more, see [rate limits](...)."147- **Frame by function, not plumbing.** Contrast what each feature does ("X148 decides A; Y decides B"), not that they share a config key or sit in the same149 directory. If the only thing linking two features is the same YAML key, it's150 not worth a cross-reference.