Contributing to the Ray documentation#
There are many ways to contribute to the Ray documentation, and we’re always looking for new contributors. Even if you want to fix a typo or expand a section, feel free to do so!
This document walks you through everything you need to do to get started.
Editorial style#
The Ray documentation follows a house style guide that covers voice, word choice, sentence structure, headings, lists, links, and formatting. Read it before you write or edit a page. See Ray documentation style guide.
The house guide builds on the Google developer documentation style guide, which is the fallback for anything the house guide doesn’t cover. Vale checks an automated subset of the Google guide. Its CI check is temporarily off, so run Vale locally. For more information, see How to use Vale.
Building the Ray documentation#
If you want to contribute to the Ray documentation, you need a way to build it. Don’t install Ray in the environment you plan to use to build documentation. The requirements for the docs build system are generally not compatible with those you need to run Ray itself.
Follow these instructions to build the documentation:
Fork Ray#
Clone the forked repository to your local machine.
Next, go to the ray/doc directory:
cd ray/doc
Install dependencies#
If you haven’t done so already, create a Python environment separate from the one you use to build and run Ray. Use Python 3.11 to match the version Read the Docs builds with. For example, if you’re using conda:
conda create -n docs python=3.11
Next, activate the Python environment you’re using (for example, venv or conda). With conda, this would be:
conda activate docs
Install the documentation dependencies with the following command:
pip install -r requirements-doc.lock.txt
Don’t use -U in this step. requirements-doc.lock.txt is a lock file that pins the exact versions of all the required dependencies.
Build documentation#
Before building, clean your environment by running:
make clean
Choose from the following two options to build documentation locally:
Incremental build
Full build
1. Incremental build with global cache and live rendering#
To use this option, you can run:
make local
We recommend this option if you need to make frequent, small, uncomplicated changes such as editing text or adding content within existing files.
In this approach, Sphinx only builds the changes you made in your branch compared to your last pull from upstream master. The rest of the doc is cached with pre-built doc pages from your last commit from upstream. For every new commit pushed to Ray, CI builds all the documentation pages from that commit and stores them on S3 as cache.
The build first traces your commit tree to find the latest commit that CI already cached on S3. Once the build finds the commit, it fetches the corresponding cache from S3 and extracts it into the doc/ directory. Simultaneously, CI tracks all the files that have changed from that commit to current HEAD, including any unstaged changes.
Sphinx then rebuilds only the pages that your changes affect, leaving the rest untouched from the cache.
When the build finishes, the doc page automatically opens in your browser. If you make a change in the doc/ directory, Sphinx automatically rebuilds and reloads the page. Stop it with Ctrl+C.
For more complicated changes that involve adding or removing files, always use make develop first. Then use make local to iterate on the cache that make develop produces.
2. Full build from scratch#
In the full build option, Sphinx rebuilds all files in the doc/ directory, ignoring all cache and saved environment. Because of this behavior, you get a clean build, but it’s much slower.
make develop
Find the documentation build in the _build directory. After the build finishes, open the _build/html/index.html file in your browser. It’s good practice to check the output of your build to make sure everything works as expected.
Before committing any changes, run the linter with pre-commit run from the doc folder to make sure your changes are formatted correctly.
Verify a Read the Docs-faithful build#
make local and make develop are for fast iteration while you author. Before you push, verify your changes the way Read the Docs builds them, so you catch failures locally instead of waiting on a Read the Docs build:
make rtd-build
make rtd-build reproduces the full build Read the Docs runs from a fresh checkout, with fail_on_warning enabled, so any Sphinx warning fails the build exactly as it does on Read the Docs. It first runs a preflight check that your environment matches Read the Docs — the Python version Read the Docs builds with (3.11) and the dependency versions pinned in requirements-doc.lock.txt — and stops with an explanation if it finds drift. Run that check on its own at any time with:
make rtd-doctor
A full build matters most when you add, remove, or rename files. The incremental make local build reuses cached pages, so a rename that breaks a cross-reference in an otherwise-unchanged page can pass locally and only fail on Read the Docs. make rtd-build always does a full build, so it catches these.
If you intend to build on an environment that doesn’t match Read the Docs, run make rtd-build RTD_DOCTOR_ARGS=--warn-only to downgrade the preflight check from an error to a warning.
Code completion and other developer tooling#
If you find yourself working with documentation often, you might find the esbonio language server useful. Esbonio provides context-aware syntax completion, definitions, diagnostics, document links, and other information for RST documents. If you’re unfamiliar with language servers, they’re important pieces of a modern developer’s toolkit. If you’ve used pylance or python-lsp-server before, you’ll know how useful these tools can be.
Esbonio also provides a VS Code extension that includes a live preview. Install the esbonio VS Code extension to start using the tool:

As an example of Esbonio’s autocompletion capabilities, you can type .. to pull up an autocomplete menu for all RST directives:

Esbonio also works with neovim. See the lspconfig repository for installation instructions.
The basics of our build system#
The Ray documentation is built with the sphinx build system. We use the PyData Sphinx Theme for the documentation.
We use myst-parser so Ray documentation supports both Sphinx’s native reStructuredText (rST) and Markedly Structured Text (MyST). New pages must be MyST Markdown (.md). A lint check rejects newly added .rst files, though edits to existing .rst files are fine. MyST is CommonMark-compliant, and you can convert between the two formats, so existing rST pages are straightforward to work with.
Some older examples are Jupyter notebooks (.ipynb), which the build renders with MyST-NB. Don’t add new notebooks. Write new examples as MyST Markdown pages. See Writing an end-to-end guide.
What to contribute?#
If you take Ray Tune as an example, you can see that our documentation consists of several types of documentation, all of which you can contribute to:
This structure is reflected in the Ray documentation source code as well, so you should have no problem finding what you’re looking for. All other Ray projects share a similar structure, but depending on the project there might be minor differences.
Each type of documentation listed above has its own purpose, but ultimately our documentation comes down to two types of documents:
Markup documents, written in MyST or rST. Every new page uses this format, including examples. Most of the documents in Ray Tune are written in this way, for instance the key concepts or API documentation.
Notebooks, written in
.ipynbformat. Some existing examples, such as many of the Tune examples, are notebooks. Don’t add new ones.
Fixing typos and improving explanations#
If you spot a typo in any document, or think an explanation isn’t clear enough, consider opening a pull request. In this scenario, run the linter as described above and submit your pull request.
Adding API references#
We use Sphinx’s autodoc extension to generate our API documentation from our source code. If we’re missing a reference to a function or class, consider adding it to the document in question.
For example, here’s how you can add a function or class reference using autofunction and autoclass:
.. autofunction:: ray.tune.register_env
.. autoclass:: ray.tune.Tuner
These directives appear throughout the API reference, such as the Tune API documentation, which you can look at for reference.
If you want to change the content of the API documentation, you must edit the function or class signatures directly in the source code. For example, in the above autofunction call, to change the API reference for ray.tune.register_env, you would edit its docstring in the source file.
To show the usage of APIs, it’s important to have small usage examples embedded in the API documentation. These should be self-contained and run out of the box, so a user can copy and paste them into a Python interpreter and play around with them. For example, if applicable, they should point to example data. Users often rely on these examples to build their applications. To learn more about writing examples, read How to write code snippets.
How the docs build renders your API signatures#
The API reference is generated from your source code: autodoc imports the module to read its signatures and docstrings. Two build behaviors affect what you write in code, even if you never build the docs yourself.
Heavy dependencies are mocked, so keep your imports safe. The docs build installs only a light dependency set, not Ray’s full runtime. Heavy or optional libraries such as torch, tensorflow, and pandas are replaced by mock objects, listed in autodoc_mock_imports in doc/source/conf.py, so autodoc can import your module without importing those libraries. If your module imports a heavy dependency at import time and that library isn’t mocked, the API-ref build fails. Note that Sphinx’s autodoc sets typing.TYPE_CHECKING to True during the build to resolve type annotations, so imports guarded by if TYPE_CHECKING: will still be executed and can cause failures if not mocked. A mock can also stand in for an object incorrectly and abort the whole module import, which surfaces as a confusing, unrelated error. To avoid both, import heavy dependencies lazily inside the function or method that needs them rather than at module top level. If you add a public API that puts a new heavy dependency in a signature, add that library to autodoc_mock_imports.
Type annotations link to external docs through intersphinx. When a public signature is annotated with a type from an external library, such as numpy.ndarray or torch.Tensor, the build turns it into a link to that library’s own documentation using the intersphinx_mapping in doc/source/conf.py. The link resolves only if the library is in that mapping. If you add a public API whose signature references a new external library and you want its types linked, add the library to intersphinx_mapping (and, per the point above, usually to autodoc_mock_imports too). Annotations that don’t resolve render as plain text; they don’t fail the build. That holds for third-party types, which resolve as py:class and fall under a blanket nitpick_ignore_regex entry. It does not hold for None and typing.* annotations, which Sphinx emits as py:obj. Since there is no blanket ignore rule for py:obj, they build cleanly only because the python intersphinx target resolves them.
Adding code to an .rST or .md file#
Modifying text in an existing documentation file is easy, but adding code takes more care. To show code that Ray CI tests, use a testcode block or include a script that CI runs. Use these only for code that runs as written. To learn how to write tested code snippets, read How to write code snippets.
from ray import train
def objective(x, a, b): # Define an objective function.
return a * (x ** 0.5) + b
def trainable(config): # Pass a "config" dictionary into your trainable.
for x in range(20): # "Train" for 20 iterations and compute intermediate scores.
score = objective(x, config["a"], config["b"])
train.report({"score": score}) # Send the score to Tune.
This code is imported by literalinclude from a file called doc_code/key_concepts.py. CI runs the doc_code scripts that the targets in doc/BUILD.bazel select, which excludes some files and some directories. Check that a target covers your script, and run scripts that you change or add locally first. You don’t need to run the testing framework locally.
When CI can’t run your code, such as pseudo-code that demonstrates a concept or a step that needs a cluster or credentials, put it in a plain fenced code block with a language, such as ```python. CI doesn’t run plain code blocks, so run the code yourself before you open a pull request. For a full guide that CI doesn’t test, see Writing an end-to-end guide.
Creating a new document from scratch#
Sometimes you might want to add a completely new document to the Ray documentation, such as a new user guide or a new example.
For this to work, you must add the new document explicitly to a parent document’s toctree, which determines the structure of the Ray documentation. See the Sphinx documentation for more information.
Depending on the type of document you’re adding, you might also have to make changes to an existing overview page that curates the list of documents in question. For instance, for Ray Tune each user guide is added to the user guide overview page as a panel, and the same goes for all Tune examples. Always check the structure of the Ray sub-project whose documentation you’re working on to see how to integrate it within the existing structure. In some cases you may need to choose an image for the panel. Images are in doc/source/images.
Writing an end-to-end guide#
An end-to-end guide walks the reader through a complete task, from installing dependencies to a working result. Write it as a MyST Markdown page, like any other page in the Ray documentation.
To start, copy the end-to-end guide template into the directory of the library your guide covers. The template shows the page structure and the syntax Ray uses for admonitions, tabs, dropdowns, and cross-references. Then add the page to a toctree. Ray Data, Ray Serve, and Ray Train also have an examples.yml gallery, and for those libraries you can list the page there instead.
Ray CI doesn’t run the code in a guide like this, so the guide is only as current as the last time someone ran it. Run every step yourself before you open a pull request, and record the Ray version you used in the HTML comment that the template puts under the title. The comment is for maintainers and doesn’t render on the page. When you update the guide later, run it again and update the version.
To publish an example that Ray tests and keeps current, use the template-collections flow instead. See Publishing an example.
Don’t write the guide as a notebook. Leave out Jupyter front matter such as jupytext and kernelspec, {code-cell} blocks, and companion .ipynb files. The docs build doesn’t execute them, and the Ray documentation is retiring in-tree notebooks. To turn an existing notebook into a guide, convert it to Markdown, then edit the result to match the template:
jupyter nbconvert your-example.ipynb --to markdown
The converted file shows cell outputs as indented blocks and writes images to a your-example_files/ directory. Move any images you keep to an images/ directory next to your guide.
If you have questions about your guide, ask in the Ray community Slack or on your pull request.
How to use Vale#
What is Vale?#
Vale checks whether your writing adheres to the Google developer documentation style guide. The CI check that runs Vale on the Ray Data documentation and the example gallery is temporarily off.
Vale catches typos and grammatical errors. It also enforces stylistic rules such as “use contractions” and “use second person.” For the full list of rules, see the configuration in the Ray repository.
How do you run Vale?#
How to use the VS Code extension#
Install Vale. If you use macOS, use Homebrew.
brew install vale
Otherwise, use PyPI.
pip install vale
For more information on installation, see the Vale documentation.
Install the Vale VS Code extension by following these installation instructions.
VS Code should show warnings in your code editor and in the “Problems” panel.

How to run Vale on the command line#
Install Vale. If you use macOS, use Homebrew.
brew install vale
Otherwise, use PyPI.
pip install vale
For more information on installation, see the Vale documentation.
Run Vale in your terminal.
vale doc/source/data/overview.rstVale should show warnings in your terminal.
❯ vale doc/source/data/overview.rst doc/source/data/overview.rst 18:1 warning Try to avoid using Google.We first-person plural like 'We'. 18:46 error Did you really mean Vale.Spelling 'distrbuted'? 24:10 suggestion In general, use active voice Google.Passive instead of passive voice ('is built'). 28:14 warning Use 'doesn't' instead of 'does Google.Contractions not'. ✖ 1 error, 2 warnings and 1 suggestion in 1 file.
How to handle false Vale.Spelling errors#
To add custom terminology, complete the following steps:
If it doesn’t already exist, create a directory for your team in
.vale/styles/Vocab. For example,.vale/styles/Vocab/Data.If it doesn’t already exist, create a text file named
accept.txt. For example,.vale/styles/Vocab/Data/accept.txt.Add your term to
accept.txt. Vale accepts Regex.
For more information, see Vocabularies in the Vale documentation.
How to handle false Google.WordList errors#
Vale errors if you use a word that isn’t on Google’s word list.
304:52 error Use 'select' instead of Google.WordList
'check'.
If you want to use the word anyway, modify the appropriate field in the WordList configuration.
Troubleshooting#
If you run into a problem building the docs, following these steps can help isolate or eliminate most issues:
Clean out build artifacts. Use
make cleanto clean out docs build artifacts in the working directory. Sphinx uses caching to avoid doing work, and this sometimes causes problems. This is particularly true if you build the docs, thengit pull origin masterto pull in recent changes, and then try to build docs again.Check your environment. Use
pip listto check the installed dependencies. Compare them todoc/requirements-doc.txt. The documentation build system doesn’t have the same dependency requirements as Ray. You don’t need to run ML models or execute code on distributed systems in order to build the docs. In fact, it’s best to use a completely separate docs build environment from the environment you use to run Ray to avoid dependency conflicts. When installing requirements, dopip install -r doc/requirements-doc.txt. Don’t use-Ubecause you don’t want to upgrade any dependencies during the installation. To check your environment against Read the Docs automatically, runmake rtd-doctor, which compares your interpreter and the pinned docs dependencies to the versions Read the Docs uses and tells you what to fix.Match the Read the Docs Python version. The docs build system doesn’t keep the same dependency and Python version requirements as Ray. Read the Docs builds with the Python version pinned in
.readthedocs.yaml(currently 3.11), so use that same version locally; building with a different version can surface or hide warnings that then behave differently on Read the Docs.Enable breakpoints in Sphinx. Add
-Pto theSPHINXOPTSindoc/Makefileto tellsphinxto stop when it encounters a breakpoint, and remove-j autoto disable parallel builds. Now you can put breakpoints in the modules you’re trying to import, or insphinxcode itself, which can help isolate stubborn build issues.[Incremental build] Side navigation bar doesn’t reflect new pages. If you’re adding new pages, they should always show up in the side navigation bar on index pages. However, incremental builds with
make localskip rebuilding many other pages, so Sphinx doesn’t update the side navigation bar on those pages. To build docs with a correct side navigation bar on all pages, consider usingmake develop.
Getting a docs change onto the released version#
docs.ray.io/en/latest is built from the newest releases/X.Y.Z branch, not from master. A docs change merged to master appears on docs.ray.io/en/master right away, but only reaches the default /latest site once it’s cherry-picked onto the current release branch.
If a merged docs change should be live on the released version — for example, documentation for a feature that has already shipped — open a cherry-pick pull request against the releases/X.Y.Z branch:
Base the PR on
releases/X.Y.Zand title it[cherry-pick][X.Y.Z][docs] ...to match the branch’s convention.Apply the commits with
git cherry-pick -x --signoffto preserve provenance and the required DCO sign-off.Before you start, check that the change isn’t already backported under a different commit (
git log --oneline <remote>/releases/X.Y.Z --grep "#<PR>)") and that no cherry-pick PR is already open against the branch.
If you use Claude Code, the /backport-docs skill walks through this end to end, including the build-safety checks. See Using agents for development.
Where to go from here?#
There are many ways to contribute to Ray other than documentation. See our contributor guide for more information.