SuperAPI AI Directory

add-docs-page

Writing & research

View repository

Updated 11-04 22:08

About this skill

Add or move a docs page

A page is not finished when the MDX file exists. It also needs a navigation entry, and a move or deletion needs a redirect. CI enforces both.

Read AGENTS.md for the navigation map, the style guide, and the frontmatter rules. This skill covers the procedure around them and does not repeat them.

Step 1. Choose the source directory

Use the "Source directory summary" table in AGENTS.md to go from subject to directory. Two traps:

  • Directory names do not match navigation names. src/langsmith/fleet/ appears as "No-code agents"; src/langsmith/managed-deep-agents*.mdx appears under Build, not under a LangSmith menu.
  • Lifecycle menus mix products. Build draws from both src/oss/ and src/langsmith/; Test, Deploy, and Monitor all draw from src/langsmith/.

Never write to build/. It is Mintlify output, regenerated by make build.

Step 2. Write the page

Required frontmatter:

---
title: Clear, concise page title
description: SEO summary with no markdown, no links, and no backticks
---

For OSS pages that differ by language, use :::python and :::js fences in one file rather than writing two files. The build pipeline emits both versions.

Before writing a JSX tag you have not seen in src/, look it up on Mintlify components or with the docs-mintlify MCP server. A plausible name is not evidence: <Important> and <ItemTable> both reached main and rendered as nothing.

Take every fact on the page from the product source, not from memory, a sibling docs page, or the request that asked for the page. This covers behavior, defaults, field names, version minimums, and examples. Use the verify-against-source skill to find the repository that owns each claim. Never fabricate a value to fill a gap. Leave the claim out, and list what you could not confirm in the pull request body and in your reply to the requester.

Step 3. Add the navigation entry

Navigation lives in src/docs.json under navigation.products. There are two products: products[0] is AGENT DEVELOPMENT LIFECYCLE (Home, Build, Test, Deploy, Monitor) and products[1] is PRODUCTS AND SETUP (LangSmith setup, LLM Gateway, No-code agents, Engine, Deep Agents Code).

Each menu item is addressed by its item key, then nests one of two ways:

  • menu[].tabs[].pages[] for most menu items.
  • menu[].dropdowns[].tabs[].pages[] for Build, which has Python and TypeScript dropdowns.

A pages array holds page-path strings and {"group": ..., "pages": [...]} objects, nested to any depth.

Three rules:

  1. A language-versioned OSS page needs two entries. Build page paths carry the language segment (oss/python/deepagents/overview and oss/javascript/deepagents/overview), so one new page means one entry in the Python dropdown and one in the TypeScript dropdown. Omitting the TypeScript entry is the most common miss.
  2. Page paths omit the src/ prefix and the file extension. src/langsmith/sandboxes.mdx is "langsmith/sandboxes".
  3. A new group leads with an index page: "pages": ["group/index", "group/page"].

Integration pages are the exception. Add them to the component's index.mdx instead, and touch docs.json only when creating a brand-new component group.

Step 4. Add redirects for a move, rename, or deletion

For a move or rename of a file that was already on main, run the repo's mover first. It rewrites cross-references across the corpus, which hand-editing misses: every link to the page in every form (/oss/langchain/x, /oss/python/langchain/x, href="..."), plus the src/docs.json nav entries and redirect destinations that name it:

uv run docs mv src/langsmith/old-name.mdx src/langsmith/new-name.mdx --dry-run

Read any Left ... links unchanged warning in the output. It marks links the mover could not rewrite safely, such as an unversioned /oss/integrations/... link that also reaches the other language's page. Fix those by hand.

Drop --dry-run once the preview looks right. The mover does not add a redirect, so add one to the redirects array in src/docs.json:

{ "source": "/langsmith/old-name", "destination": "/langsmith/new-name" }

Redirect paths are site paths and start with /. A language-versioned page needs a redirect per language, plus one for the unversioned path if the old URL had one.

scripts/check_removed_pages_redirects.py runs in CI and fails the PR when a page leaves the navigation and its source file is gone with no redirect. The same script fails when docs.json names a page whose file does not exist, so a typo in a page path is caught there rather than at build time.

Step 4b. Two traps that fail silently

Extract a snippet once a block appears on three pages

AGENTS.md covers how to add a snippet. The rule for when: the same block repeated on three or more pages becomes one file under src/snippets/. A status callout duplicated across a page family means the wording change that retires it is an edit to every page in the family, and one will be missed.

Verify a new snippet reaches the build. The pipeline rewrites snippet imports to language-specific paths, so /snippets/langsmith/x.mdx becomes /snippets/python/langsmith/x.mdx in the output, and a missing target renders as nothing at all rather than as an error:

ls build/snippets/python/langsmith/<name>.mdx build/snippets/javascript/langsmith/<name>.mdx

Editing a heading moves its anchor

A heading's slug is derived from its text, so rewording one silently breaks every #anchor link pointing at it, including links from other pages and entries in src/docs.json. Grep before editing:

grep -rn 'use-with-the-langsmith-gateway' src/ --include=*.mdx --include=*.json

Changing only capitalization is safe, because slugs are lowercased. Changing a word is not, and needs either a reworded inbound link or a redirect. <Step> and <Accordion> accept an explicit id, which is how to keep a landing spot that is no longer a heading.

Step 5. Verify

Run all three, in this order:

make lint_prose FILES="src/path/to/page.mdx"
make check-mdx
make broken-links-with-anchors

When make build fails with Required uv version >=0.9.26 does not match the running version, the local uv has drifted from the one pyproject.toml expects. Run the pipeline directly rather than working around the build:

PYTHONPATH="$(pwd)" .venv/bin/python -m pipeline build

A fresh git worktree has no .venv, and the same version check blocks uv sync from creating one. Point at the main checkout's interpreter instead; PYTHONPATH still loads the pipeline code from the worktree:

PYTHONPATH="$(pwd)" <main-checkout>/.venv/bin/python -m pipeline build

A fresh worktree's .mise.toml is also untrusted, so the first commit fails at the Vale hook with Config files in <dir>/.mise.toml are not trusted. Run mise trust once in the worktree. The docs-edit skill covers the permanent fix.

make broken-links-with-anchors depends on build, so it fails the same way. Its link-check half runs on its own once the build output exists:

cd build && mint broken-links --check-anchors | tee /tmp/bl.txt
cd .. && python3 scripts/filter_mint_broken_links.py --check-anchors --input /tmp/bl.txt

Read make broken-links-with-anchors output by skipping to the ⎿ lines. Those are the only real failures. A bare filename with no indented lines beneath it is an OpenAPI-generated page that exists at deploy time but not locally.

Fix every Vale finding. CI blocks on lint_prose, and its most common failure is a spaced em dash (word — word must be word—word).

Step 6. Review the prose

Once the edit is complete and before committing, invoke the docs-review skill on the files this pass changed. It runs in working-tree mode, so it needs no checkout, and it covers the style-guide rules Vale cannot see: passive voice, filler, product versus common noun capitalization, structure conventions, and link text.

Run it on finished edits only. A review of a half-written section produces findings that go stale as soon as writing resumes.

Skip this step for a change too small to have prose in it, such as a pure docs.json reorder or a redirect-only fix.

Step 7. Open the pull request

Commit, push, and open the PR however you usually do. If the change belongs on an existing PR, use docs-edit instead. Two rules apply to the PR description:

  • Linear: When the work has a Linear issue, link it with Closes [DOC-N](<linear url>) or Refs [DOC-N](<linear url>) as appropriate. sync-linear-issue-from-pr.yml only syncs status for docs-release-watch PRs labeled release-watch-agent, so a human PR does not move the issue.
  • AI disclosure: End the description with one plain sentence, such as Prepared with Claude Code. Do not add a 🤖 Generated with [Claude Code](...) badge or any similar badge. check-pr-ai-attribution fails a PR that carries one, because the squash merge copies it into the commit on main.

Checklist

  • File in the directory the source-directory table names, not build/.
  • Frontmatter present, description free of markdown.
  • Every claim checked against product source; unconfirmed claims cut and listed in the PR body.
  • src/docs.json entry in the right product, menu item, tab, and group.
  • Both language entries added if the page is language-versioned.
  • Index page first if a new group was created.
  • Redirect added for every moved, renamed, or deleted path.
  • Inbound #anchor links checked before any heading was reworded.
  • A block now on three or more pages extracted to src/snippets/, and its built python/ and javascript/ targets confirmed to exist.
  • make check-mdx clean.
  • make lint_prose clean, make broken-links-with-anchors shows no new ⎿ lines.
  • docs-review run on the changed files, findings addressed.
  • PR description references the Linear issue, if any, and has no AI badge.