--- name: rst-to-myst description: Convert Ray documentation pages from reStructuredText (.rst) to MyST Markdown (.md). Use when migrating existing files under doc/source/ to MyST, finishing a partial MyST migration of a directory, or when asked to convert/migrate a doc page to markdown. Covers the RST-to-MyST directive mapping, label and cross-reference preservation, sphinx-design tabs/dropdowns, doctest/testcode handling, the doc/BUILD.bazel doctest exclusions, and the build and doctest verification needed to land a clean docs PR. user-invocable: true argument-hint: --- # Convert RST to MyST Markdown MyST Markdown is the standard for new Ray doc pages — `doc/.claude/CLAUDE.md` declares it, and a lint check rejects newly-added `.rst`. This skill converts an **existing** `.rst` page (or a batch) to MyST `.md` **faithfully**: format only, preserving the rendered HTML and any test coverage. The Ray docs build with `fail_on_warning: true` (`.readthedocs.yaml`), so a sloppy conversion doesn't render wrong — it **fails the build**. Most of this skill is about the handful of constructs that break the build or silently drop test coverage if mishandled. --- ## When to use this skill **Use when:** - Migrating one or more existing `doc/source/**/*.rst` files to MyST `.md`. - Finishing a partial MyST migration of a directory. **Not for:** - Authoring a brand-new page — just write `.md` directly (no conversion needed). - Editing `.rst` content you're not converting (edits to existing `.rst` aren't lint-flagged). - Notebooks (`.ipynb`) — different workflow. - Bundling unrelated content rewrites — keep the diff a pure format conversion (see Golden rule). --- ## Golden rule: faithful conversion Convert the **format**, not the content. The rendered HTML should be byte-equivalent to the pre-conversion page, **except** for deliberate, called-out light cleanup (a dead link, a stale version ref). No restructuring, no rewording of sound content, no heading-level "fixes." Why: the decisive regression check compares the PR's Read the Docs preview against `/en/master` (per `doc/.claude/CLAUDE.md`). A faithful conversion makes that diff empty and the PR trivially reviewable. Capitalization nits ("github"→"GitHub"), heading-case changes, and rewraps all add noise and invite scope debates — leave them unless explicitly asked. **Faithful does not mean byte-copying links.** A few RST link forms render fine in RST but are *wrong* in MyST and fail `fail_on_warning` (see Hard rule 2). Translate them; don't transcribe them. --- ## Procedure ### 1. Read the source(s) and the two style models Read every `.rst` you're converting **in full**. Also read the canonical MyST examples in the same tree for house style: `doc/source/ray-contribute/docs.md` and `doc/source/ray-contribute/agent-development.md` (frontmatter, `(label)=`, `{contents}`, admonition and image conventions). ### 2. Pre-flight — verify every reference resolves *before* converting A stale `literalinclude` path, autodoc symbol, or `{ref}` target turns into a build failure under `fail_on_warning`. Confirm each up front: - **Labels this file defines** — `grep -nE '^\.\. _.*:' file.rst`. You must preserve **every** one (Hard rule 1). Note them. - **External callers of those labels** — `grep -rn '' doc/source python rllib`. Confirms they're load-bearing (and that you must not rename them). - **`literalinclude` targets** — the file exists; `:lines:`/`:start-after:`/`:end-before:` markers still resolve. - **autodoc targets** — every `.. autofunction::`/`.. autoclass::` symbol imports. - **Who references THIS file** — grep the **bare filename** across all of `doc/`, e.g. `grep -rn 'getting-involved' doc/source`. Do **not** grep only the `dir/stem.rst` path: siblings link relatively (`[text](./getting-involved.rst)`, `(getting-involved.rst)`), and those break silently when you rename the file. Classify each hit (see "Reference updates"); most are no-ops, but `doc/BUILD.bazel`, `{include}`, and any relative `.rst` link from another page are not. ### 3. Convert using the mapping Apply the table below construct-by-construct. Preserve prose line-wrapping verbatim (keeps the diff line-aligned). Then apply the Hard rules and Construct notes. ### 4. Update references that actually need it Most don't (see checklist). The ones that do go **in the same PR** as the file they track. ### 5. Verify Static checks → build (RtD) → doctest (if the file is doctest-tested) → regression vs `/en/master`. See "Verification". ### 6. Ship `git rm` the `.rst`, add the `.md`. Commit, push, PR. For the OSS PR conventions (branch base, DCO sign-off, no internal ticket keys, etc.) follow the project's docs-PR workflow. --- ## The mapping | RST | MyST Markdown | |---|---| | `.. meta::` / `:description:` | YAML frontmatter `myst:\n html_meta:\n description: "…"` | | `.. _label:` above a heading | `(label)=` on its own line, blank line, then the heading | | `====` / `----` underline | `#` / `##` … — **level by order of appearance, see Hard rule 3** | | `` ``literal`` `` (double backtick) | `` `code` `` (single backtick) | | `` `text` `` (single backtick) | `` `code` `` — faithful, since `default_role = "code"` | | `` `text `_ `` / `` `text `__ `` | `[text](url)` | | bare URL `https://…` | `` (angle-bracket autolink — **`linkify` is off**) | | same-page section link `` `text `_ `` | `[text](#sec)` (fragment) — **never keep the `.html#` URL; see Hard rule 2** | | `` :ref:`text