--- name: add-docs-page description: Add, move, rename, or delete a page on the LangChain docs site. Covers choosing the source directory, writing frontmatter, placing the entry in src/docs.json navigation, adding redirects, and verifying with the lint and broken-link gates. Use when asked to add a new doc or page, move or rename a page, put something in the nav, or add a redirect. license: MIT metadata: author: langchain version: "1.0" --- # 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: ```yaml --- 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. ## 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: ```bash uv run docs mv src/langsmith/old-name.mdx src/langsmith/new-name.mdx --dry-run ``` Drop `--dry-run` once the preview looks right. Then add the redirect to the `redirects` array in `src/docs.json`: ```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: ```bash ls build/snippets/python/langsmith/.mdx build/snippets/javascript/langsmith/.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: ```bash 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. `` and `` 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: ```bash make lint_prose FILES="src/path/to/page.mdx" make build 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: ```bash PYTHONPATH="$(pwd)" .venv/bin/python -m pipeline build ``` `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: ```bash 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. ## Checklist - [ ] File in the directory the source-directory table names, not `build/`. - [ ] Frontmatter present, `description` free of markdown. - [ ] `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 lint_prose` clean, `make broken-links-with-anchors` shows no new `⎿` lines. - [ ] `docs-review` run on the changed files, findings addressed.