CLI and Python API#

The complete surface: one builder, five commands, one class, and the shape of the file they all read. Getting started is the guided version of the same material.

Every query command takes --index, which accepts either a builder output directory containing index.json or a direct path to the file itself.

Sphinx builder#

The installed package registers a native builder through Sphinx’s builder entry point. No conf.py change is required:

sphinx-build -b lens docs/ docs/_build/lens/

The builder loads the same sources, extensions, domains, objects, and references as every other Sphinx build. Its only output is docs/_build/lens/index.json. A Makefile can expose the command as make lens.

CLI#

sphinx-lens build SOURCE [--output DIRECTORY] [--fail-on-warning]
sphinx-lens locate QUERY [--index PATH] [--limit N]
                   [--regex] [--kind KIND] [--domain DOMAIN] [--json]
sphinx-lens inspect TARGET [--index PATH]
sphinx-lens read TARGET [--index PATH]
sphinx-lens links TARGET [--index PATH]

sphinx-lens build is a convenience wrapper around the native builder. It writes SOURCE/_build/lens/index.json by default. --fail-on-warning applies Sphinx’s warning-as-error policy.

locate normally ranks exact names, headings, body phrases, and unordered token matches. --regex interprets the query as a case-insensitive Python regular expression. Repeat --kind to select documents, sections, or objects; use --domain py to restrict domain objects. --json returns structured results.

sphinx-lens locate "database transactions" -i docs/_build/lens
sphinx-lens locate 'QuerySet\.(get|filter)' --regex --kind object --domain py \
  --json -i docs/_build/lens

Targets use one of these forms:

  • Document: guide/network

  • Section: guide/network#timeouts

  • Domain object: py:class:example.Client

Shell composition#

Use jq for structured predicates and projections over either search results or the complete model:

sphinx-lens locate 'QuerySet\..*' --regex --kind object --json \
  -i docs/_build/lens \
  | jq -r '.[] | [.entry.ref, .score] | @tsv'

jq -r '.links[] | select(.kind == "unresolved") | .target' \
  docs/_build/lens/index.json \
  | sort | uniq -c | sort -nr

Use rg when a quick textual scan is enough and ranking or typed fields do not matter:

rg -n -i 'transaction|atomic' docs/_build/lens/index.json

Python API#

from sphinx_lens import Lens, build

lens = build("docs/", "artifacts/lens")
lens = Lens.open("artifacts/lens")

entry = lens.resolve("guide/network#timeouts")
client = lens.resolve("py:class", "example.Client")
results = lens.locate(
    r"Client\.(connect|close)",
    regex=True,
    kinds={"object"},
    domain="py",
)
text = lens.read(entry.ref)
children = lens.children("guide/network")
outgoing = lens.references(entry.ref)
both_directions = lens.linked(entry.ref)

Entry.location maps domain objects back to their physical document#anchor. Links use physical locations so incoming references to a section and to an object at the same Sphinx anchor can be combined.

Index model#

The version 3 JSON document contains:

  • source: the source directory relative to the artifact, or null when the artifact was written outside the source tree and no relative path would survive being moved.

  • metadata: Sphinx version, configured extensions, UTC build time, Git commit, and a SHA-256 hash for each source document.

  • entries: documents, sections, and domain objects with normalized text, parent relationships, and an order recording each entry’s position in its document.

  • links: internal, external, and unresolved directed references.

Lens.open() warns when available local sources no longer match their hashes. Missing sources, and a null source, do not prevent an artifact from loading.

Documents, sections, and objects store only their own normalized text. read reconstructs a scope by composing its descendants in source order, and children returns them the same way, so a composed page reads top to bottom rather than alphabetically. Markup distinctions such as code blocks and tables are not preserved.

The index is a portable intermediate representation and nothing more: one JSON file, readable without Sphinx, a database, or a model. locate is a reference finder, not semantic similarity search.