Verify Rez inventory domains

Verify the inventory file of the rez documentation. This is a Sphinx documentation and I want to verify which domains are part of the inventory because we have custom domains and I want to make sure that they are part of the inventory. you can fetch it from the web and the URL I believe is docs.rez-project.io

Inventory verification

The published stable inventory is:

https://docs.rez-project.io/en/stable/objects.inv

It is a valid Sphinx inventory v2 for Rez 3.4.0, containing 3,726 objects.

Domain Entries Object types
py 2,867 attribute, class, data, exception, function, method, module, property
std 779 cmdoption, doc, envvar, label
rex 46 attribute (25), function (21)
pkgdef 34 attribute (28), function (6)

Custom domains are present

Both Rez custom domains defined and registered in docs/rez_sphinxext.py are included:

  • rex — examples: rex:function:alias, rex:function:setenv, rex:attribute:this.root
  • pkgdef — examples: pkgdef:attribute:requires, pkgdef:attribute:variants, pkgdef:function:commands

Their registration is visible here.

I also checked /en/latest/objects.inv. It contains the same custom-domain entries: 46 rex and 34 pkgdef objects.

One URL caveat: https://docs.rez-project.io/objects.inv redirects to a 404. Intersphinx consumers should use the versioned URL, preferably:

intersphinx_mapping = {
    "rez": ("https://docs.rez-project.io/en/stable/", None),
}

Conclusion: both custom Rez domains are successfully represented in the published Sphinx inventory.

Then you try to create a custom documentation, not the one currently in the repository, but just like another documentation for a random test project, and then try to use intersphinx and then verify that the interlinking works with the new domains. Because I'm not sure if another project is going to be able to actually reference the new domains.

Result: inventory alone is not sufficient

I created an isolated Sphinx project outside the repository and configured:

extensions = ["sphinx.ext.intersphinx"]

intersphinx_mapping = {
    "rez": ("https://docs.rez-project.io/en/stable/", None),
}

I then attempted these references:

:external+rez:rex:func:`alias`
:external+rez:rex:attr:`this.root`
:external+rez:pkgdef:func:`commands`
:external+rez:pkgdef:attr:`requires`

With only intersphinx enabled, the build failed under -W:

WARNING: domain for external cross-reference not found: 'rex'
WARNING: domain for external cross-reference not found: 'pkgdef'

A normal Python-domain control reference resolved successfully, proving that the inventory itself was loaded correctly.

Registering compatible domains makes the links work

I repeated the test after registering rex and pkgdef domains compatible with Rez’s Python-derived domains. The Sphinx build then completed with zero warnings, producing these links:

https://docs.rez-project.io/en/stable/package_commands.html#alias
https://docs.rez-project.io/en/stable/package_commands.html#this.root
https://docs.rez-project.io/en/stable/package_definition.html#commands
https://docs.rez-project.io/en/stable/package_definition.html#requires

I also fetched the target pages and verified that all four fragment IDs exist.

Conclusion

The published inventory is correct and contains the custom objects, but Sphinx does not dynamically register unknown domains from an intersphinx inventory.

A consuming project must have both:

  1. The Rez intersphinx mapping.
  2. An extension that registers the rex and pkgdef domains and their roles.

Currently, Rez’s domains are defined in docs/rez_sphinxext.py, which is a documentation-local extension rather than an obvious reusable extension for downstream projects.

The robust solution would be to expose the domain definitions as an installable Sphinx extension. A consumer could then use something like:

extensions = [
    "sphinx.ext.intersphinx",
    "rez.sphinxext",  # hypothetical reusable extension
]

intersphinx_mapping = {
    "rez": ("https://docs.rez-project.io/en/stable/", None),
}

Then these explicit references would work:

:external+rez:rex:func:`alias`
:external+rez:pkgdef:attr:`requires`

So your concern is valid: another project cannot currently reference the custom domains using intersphinx alone, despite their presence in objects.inv.

Try without the consumer domains.py file. I'm skeptical

Confirmed without consumer_domains.py

I reran the test from scratch with only:

  • conf.py
  • index.rst
  • sphinx.ext.intersphinx

The inventory was fetched directly from the published URL:

loading intersphinx inventory 'rez' from
https://docs.rez-project.io/en/stable/objects.inv ...

The four custom-domain references produced:

WARNING: domain for external cross-reference not found: 'rex'
WARNING: domain for external cross-reference not found: 'rex'
WARNING: domain for external cross-reference not found: 'pkgdef'
WARNING: domain for external cross-reference not found: 'pkgdef'

With warnings treated as errors:

SPHINX_EXIT_STATUS=1

The generated HTML contained no links for those four references. Meanwhile, the Python-domain control reference resolved correctly:

https://rez.readthedocs.io/en/stable/api/rez.resolved_context.html#rez.resolved_context.ResolvedContext

So this clean test confirms:

  • The published inventory loads.
  • Built-in domains resolve.
  • Inventory entries do not register custom domains in the consumer.
  • Without a domain extension, rex and pkgdef references do not work.

Your skepticism was reasonable, but the failure is reproducible in a completely clean Sphinx 9.0.4 project. No repository files were changed.

Let me search online and see if there are any open issues relating to that.

There is an exact upstream discussion

The closest match is the still-open Sphinx discussion:

It describes precisely what we observed:

An objects.inv may contain (domain name, object type) that do not have a corresponding role name available in your local Sphinx project.

It also says the current workaround effectively requires:

all the same extensions / bespoke setup as the project you are referencing

That maps directly to Rez’s rex and pkgdef domains.

There is disagreement among the Sphinx maintainers:

  • One position is that domains own lookup and rendering semantics, so consumers must install the corresponding extension.
  • The alternative proposal is for external references to fall back to a generic link when the domain or role is unavailable locally.

That fallback has not been implemented.

Earlier issue

This reported the same underlying problem in 2018. A Sphinx maintainer responded:

You can refer it if you'll also define it on your project.

The issue was closed in June 2026 because its specific confval example was solved by moving confval into Sphinx’s built-in standard domain via PR #12536. That did not solve arbitrary third-party domains such as Rez’s rex and pkgdef.

Related open work

Implication for Rez

This is known upstream behavior rather than a malformed Rez inventory. Unless Sphinx adopts generic fallback resolution, Rez should make its custom domains available as an installable consumer extension if downstream intersphinx references are a supported use case.

Umm, then, maybe we need to provide a sphinx extension for our users...

Yes—that is the most reliable approach under Sphinx’s current model.

I would provide a small, installable extension whose only responsibility is registering:

  • rex
  • pkgdef

Consumers could then configure:

extensions = [
    "sphinx.ext.intersphinx",
    "rez.sphinxext",
]

intersphinx_mapping = {
    "rez": ("https://docs.rez-project.io/en/stable/", None),
}

And use:

:external+rez:rex:func:`alias`
:external+rez:pkgdef:attr:`requires`

The extension should be separated from the existing documentation-local rez_sphinxext.py, because that module also generates Rez documentation and registers project-specific directives. Downstream projects only need the domain classes.

A sensible structure would be:

src/rez/sphinxext.py

with optional Sphinx imports so normal Rez users do not acquire Sphinx as a mandatory dependency. We could also add a documentation extra, for example:

pip install "rez[sphinx]"

The Rez documentation itself should then load the packaged extension, ensuring that the producer and consumers always use identical domain definitions. This avoids maintaining a second mock implementation and gives downstream users a supported intersphinx integration path.

I would put it in `rez.utils.docs`. also,maybe we can move some parts of the rez_sphinxext.py to remove some duplication?
Ran 3 commands
Do we need the full implementation for our users? I want to reference our docs. Or can we just have like stubs? I think the initial implementation you had just like was subclassing the Python domains, I believe, and then replacing the names or something. Please take a look at that. I don't want to tie our code too much to Sphinx so that our users have more flexibility to pick the right Sphinx versions that they want to support without necessarily being tied to the rest version.

Lightweight consumer extension implemented

You were correct: consumers do not need the full directive implementation.

rez.utils.docs now contains only:

  • Two PythonDomain subclasses with replaced names and labels.
  • A minimal Sphinx setup() function.
  • No copied Python directives or Sphinx internals.
  • No Sphinx dependency or version pin in Rez’s package metadata.

Rez’s own documentation still needs its directive workaround to generate the inventory correctly. That remains private in docs/rez_sphinxext.py, layered on top of the lightweight public domain classes to avoid duplicating domain names and definitions.

Usage is documented here.

Verification

External intersphinx builds passed with warnings treated as errors on:

  • Sphinx 5.3.0
  • Sphinx 7.4.7
  • Sphinx 8.2.3
  • Sphinx 9.0.4

All produced the expected links for rex:func, rex:attr, pkgdef:func, and pkgdef:attr.

Additional checks:

  • Rez documentation build succeeded.
  • Generated inventory retained 46 rex and 34 pkgdef entries.
  • Built wheel includes rez/utils/docs.py.
  • Ruff and formatting checks passed.
  • Rez does not install or pin Sphinx, so consumers remain free to select their own supported Sphinx version.
Reduce the diff to the minimum. I see you made like a bunch of unnecessary changes to the extension. Remove all unnecessary modifications.

Reduced to the minimum:

  • Restored docs/rez_sphinxext.py exactly—zero diff.
  • Kept only the lightweight new rez.utils.docs extension.
  • Kept the short usage documentation in package_definition.rst.

Verification:

git diff --exit-code -- docs/rez_sphinxext.py
extension_diff_exit=0

Final changed files:

M  docs/source/package_definition.rst
?? src/rez/utils/docs.py
Can we use the new classes maybe in the extension? I think that made sense, but it was all the other changes that didn't make sense, like you changed all the docstrings and stuff.

Done. The existing extension now reuses the new classes with only these changes:

  • Two imports.
  • RexDomain and PkgDefDomain inherit from their public counterparts.
  • Duplicate name and label declarations removed.

All existing docstrings, comments, directive classes, and formatting remain unchanged.

Verified both domains retain:

  • Correct names and labels.
  • func and attr roles.
  • Rez’s custom producer-side directives.
I like that you added documentation for how to access the package definition attributes and the commands, but you added that inside the package definition RST file. That doesn't seem like the right place because it's too specific. You're basically describing how to access two domains, unrelated domains in one kind of concept. Maybe we can move that into a separate page, but I don't know which one because we don't have a similar documentation right now. Suggest multiple options.

Options

1. Dedicated Reference page — recommended

Create:

docs/source/sphinx_integration.rst

Add it under the existing Reference toctree, near api:

.. toctree::
   :caption: Reference

   configuring_rez
   commands_index
   environment
   api
   sphinx_integration
   changelog.md

Possible title:

===============================
Referencing Rez documentation
===============================

This page could contain:

  • Installation/configuration of rez.utils.docs
  • The intersphinx mapping
  • A table of the rex and pkgdef domains
  • Example references for each domain
  • A note that Rez does not install or pin Sphinx

Why it fits: this is reference material for documentation authors consuming Rez’s published documentation. It is neither package-definition documentation nor a general Rez workflow.

2. User guide

Create:

docs/source/guides/linking_to_rez_documentation.rst

Add it to guides/index.rst.

Possible title:

Linking to Rez from Sphinx documentation

Advantages:

  • More discoverable as a task-oriented walkthrough.
  • Appropriate if we include troubleshooting, inventory inspection, and complete examples.

Disadvantages:

  • The current content is configuration reference rather than a substantial guide.
  • It would sit beside broader guides such as upgrading Rez and developing plugins.

3. General documentation-integration page

Create:

docs/source/documentation_integration.rst

Place it under Advanced or Reference.

This could eventually cover:

  • Sphinx/intersphinx
  • Published inventories
  • Linking to command references
  • Versioned documentation URLs
  • Documentation-related Rez utilities

Advantages: leaves room for future documentation tooling.

Disadvantages: currently speculative and broader than the feature being documented.

4. Put it on the Python API page

Add a section to api.rst documenting rez.utils.docs.

Advantages: the extension is technically a Python module.

Disadvantages: not recommended. Users are configuring Sphinx rather than calling a Rez Python API, and the page’s existing compatibility warnings are unrelated.

Recommendation

Use Option 1: a dedicated sphinx_integration.rst page under Reference, titled “Referencing Rez documentation.”

It provides a natural home for both domains because the organizing concept is external documentation integration—not package definitions or Rex commands. It also leaves the two domain-specific pages focused on their actual subject matter.

Option two seems like a good option. Yeah, and then we can also, for example, give a little example of how this can be added to a conf.py file and then, yeah, document some of the expectations maybe.

Created a dedicated user guide: Linking to Rez documentation.

It covers:

  • Purpose of the pkgdef and rex domains.
  • Complete conf.py configuration.
  • Example references for attributes and functions.
  • Mapping-key and role semantics.
  • Versioned inventory URL expectations.
  • Sphinx version independence.
  • Using -W to catch unresolved references.

The guide is included in the User Guides toctree, and the misplaced section was removed from package_definition.rst.

The full documentation build succeeded. One pre-existing ambiguous Command cross-reference warning remains, unrelated to these changes.

I think for the expectations, I was more probably thinking about like compatibility between rez and Sphinx versions and say that we try not to make them too tightly coupled, but it's possible that it could break. I'm not too sure. Give me some thoughts around that before doing edits. And then I would also like to see a rendered version of it. So if you could take a screenshot of the rendered documentation, like the HTML rendered version, and show the result to me, that would be nice.

Compatibility wording

I agree that “Expectations” should primarily describe the compatibility contract, rather than configuration mechanics.

The extension is intentionally loosely coupled:

  • Rez does not install or pin Sphinx.
  • rez.utils.docs only subclasses Sphinx’s public PythonDomain.
  • Consumers choose and manage their own Sphinx version.
  • The inventory format allows the documentation producer and consumer to use different Sphinx versions.

However, we should avoid promising universal compatibility:

  • Sphinx could change its domain or intersphinx APIs.
  • Role-to-object mappings could evolve.
  • Future Rez releases could add or change custom-domain objects.
  • Installing an extension from one Rez release while referencing another release’s inventory could eventually cause mismatches.

I would rename the section to Compatibility and use wording approximately like:

Rez intentionally keeps this integration small and does not install or pin a Sphinx version. Documentation projects can select and manage the Sphinx version appropriate for their own builds.

We aim to keep rez.utils.docs compatible across Sphinx and Rez releases, but not every combination is guaranteed. Changes to Sphinx’s domain or intersphinx APIs may require an updated Rez extension. For reproducible documentation builds, projects should pin their documentation dependencies and treat unresolved references as errors.

When possible, use the rez.utils.docs extension from the same Rez release as the documentation inventory being referenced.

I would not publish a specific compatibility matrix unless we add those Sphinx versions to CI. Otherwise, the documented list would quickly become an unsupported promise.

The current operational bullets about mapping keys, versioned URLs, and -W could move into a separate Troubleshooting or How it works section.

Current rendered guide

This is the current page before making those compatibility edits:

Rendered Linking to Rez documentation guide

The page renders correctly, including navigation, code blocks, and all sections. The documentation build succeeded with one existing unrelated ambiguous Command reference warning.

Go ahead with the recommendation you made for the new section name, call it Compatibility, and then follow with basically the whole suggestion

Updated the guide with:

  • Compatibility — documents loose Rez/Sphinx coupling, the lack of universal compatibility guarantees, dependency pinning recommendations, and matching the extension to the inventory’s Rez release.
  • Troubleshooting — retains the operational guidance about inventory URLs, mapping keys, domain registration, and unresolved references.

The documentation build succeeded. The only warning is the existing unrelated ambiguous Command reference.

Updated Linking to Rez documentation guide

Diff review comments: 1. docs/source/guides/linking_to_rez_documentation.rst:74 - Remove this section 2. docs/source/guides/linking_to_rez_documentation.rst:2 - The casing for rez is when it's at the beginning of a sentence we use a capital R and we use a lowercase r anywhere else. So only a capital letter at the start of a sentence.

Applied both review comments:

  1. Removed the entire Troubleshooting section.
  2. Updated casing so rez is lowercase except when it begins a sentence.

The documentation build succeeds with only the existing unrelated Command ambiguity warning.

Updated rendered guide

Create a pull request. Don't forget to add the sign-off flag when committing. You can create the pull request directly in the repo attached to this project. You don't need to create it on the upstream repo.
Explored 1 web page
Please create a new branch. Don't push on the main branch.

Pull request created: JeanChristopheMorinPerso/rez#3

  • Branch: docs/sphinx-intersphinx-domains
  • Commit: 18b5822d1d9250a465aa7cac58588d3376c79406
  • Base: main
  • Commit includes the required Signed-off-by trailer.
  • Working tree is clean.
Message from Puck
Ran 1 command, ran 2 searches
Just do a git reset origin branch hard or something.

Done—the local branch is now reset to origin/docs/sphinx-intersphinx-domains at 0dd9b19. I’ll apply the requested import fix on that exact PR head.

Edited 1 file (+1 -1), ran 1 command

The repository’s docs requirement now targets Sphinx 9.1+, but this orb runs Python 3.11 and Sphinx 9.1 requires Python 3.12, so that exact environment cannot be installed here. I’ll run the focused check against the newest compatible Sphinx (9.0.4), which exercises the same import and extension setup path, plus Ruff and byte compilation.

Ran 7 commands, ran 5 searches, ran 3 tools