Skip to main content

Unified code + documentation knowledge graph from Sphinx builds and Python AST analysis

Project description

sphinxcontrib-nexus

A unified code + documentation knowledge graph extracted from Sphinx builds and Python AST analysis. Queryable via MCP, CLI, and Python API.

What makes it unique: Nexus is the only tool that puts code structure (call graphs, imports, inheritance, type annotations) and documentation structure (equations, cross-references, citations, theory pages) in the same graph. This enables queries that are impossible with code-only or doc-only tools — like tracing from a literature citation through an equation to the function that implements it.

Quick Start

pip install sphinxcontrib-nexus

As a Sphinx Extension

Add to your docs/conf.py:

extensions = ['sphinxcontrib.nexus']

After sphinx-build, find the graph at <outdir>/_nexus/graph.db (SQLite) and <outdir>/_nexus/graph.json.

Standalone AST Analysis (no Sphinx needed)

nexus analyze src/ --db graph.db

MCP Server (for Claude Code / AI agents)

nexus serve --db graph.db --project-root /path/to/project

Install Skills + MCP Server for Claude Code

nexus setup           # project-level: .mcp.json + .claude/skills/
nexus setup --global  # user-level: ~/.claude.json + ~/.claude/skills/ (all projects)

Ingest a Paper

nexus ingest paper.pdf --db graph.db     # extracts concepts, equations, citations via LLM

Interactive Graph Visualizer

nexus visualize --db graph.db            # opens HTML graph explorer in browser

Configuration

Config value Default Description
nexus_output _nexus Output directory relative to build output
nexus_ast_analyze True Run AST analysis during Sphinx build
nexus_max_viz_nodes 300 Max nodes in auto-generated graph.html
nexus_extra_source_dirs [] Extra directories (relative to project root) to analyze in addition to autodetected source roots. Useful for out-of-tree test suites or separate module roots.
nexus_analyze_tests True Whether Python test modules are merged into the graph. Set to False to exclude them entirely (e.g. to keep coverage numbers focused on production code).
nexus_test_patterns ["tests/*", "*/tests/*", "test_*.py", "*/test_*.py"] Glob patterns (POSIX, evaluated with fnmatch against the path relative to each source dir) identifying Python test modules. Used both by nexus_analyze_tests=False exclusion and by the is_test flag on function nodes — a function is marked as a test only when its name follows the test/test_* convention and it lives in a file matching one of these patterns.
nexus_source_exclude_patterns [] Extra glob patterns (POSIX, same fnmatch semantics as nexus_test_patterns) listing directories or files to exclude from AST analysis entirely. Use this for tutorial scripts, vendored copies, legacy modules, or any other source that lives in the project tree but should not contribute nodes or edges to the graph. Patterns are applied in addition to the always-on base exclusions (docs/*, .venv/*, __pycache__/*) and to nexus_test_patterns when nexus_analyze_tests=False.
nexus_infer_implements True Whether to run the token-intersection heuristic in merge._infer_implements. Set False when explicit registry / marker / directive coverage is complete and the heuristic's inferred edges are noise.
nexus_verification_registry [] List of paths (relative to conf.py) to YAML files declaring explicit verification and implementation edges. See schema version 1 in the README's V&V section. Missing nodes are logged and skipped; schema errors raise RegistryError at build time.

Supported Project Layouts

Nexus works with any Python project:

  • Standard packages: myproject/mypackage/__init__.py — detected automatically
  • src layout: src/mypackage/ — detected automatically
  • Flat modules: directories with .py files but no __init__.py — detected automatically
  • Custom sys.path: projects that add directories to sys.path in conf.py — picked up from the Sphinx build environment

What the Graph Contains

Node Types (14)

Type Source Example
file Sphinx RST/doc pages
section Sphinx Labeled sections (:ref: targets)
equation Sphinx Labeled math equations (:eq: targets)
term Sphinx Glossary terms
function Sphinx + AST Python functions
class Sphinx + AST Python classes
method Sphinx + AST Python methods
attribute Sphinx + AST Class attributes
module Sphinx + AST Python modules
data Sphinx Module-level data
exception Sphinx Exception classes
type Sphinx Type aliases
external Auto-detected stdlib, builtins, installed packages (numpy, scipy, ...)
unresolved Auto-detected Referenced but not documented symbols

Edge Types (12)

Edge Meaning Source
contains Parent → child (toctree, module→function, class→method) Sphinx + AST
references Cross-reference (:ref:, :term:) Sphinx
documents Doc page → code symbol (:func:, :class:) Sphinx
equation_ref Doc → equation (:eq:) Sphinx
cites Doc → citation Sphinx
implements Code → equation (inferred from co-occurrence in docs) Merge
calls Function → function AST
imports Module → module AST
inherits Class → parent class AST
type_uses Function → type (from annotations) AST
tests Test → tested function AST
derives Derivation → equation AST

MCP Tools (28)

Exploration

  • query — keyword search across node names
  • node_at — map a file position (LSP result, stack trace) to the innermost enclosing graph node; warns when the file changed since the graph was built (positions in a snapshot drift with edits)
  • context — 360-degree view of a symbol (all connections grouped by type)
  • neighbors — direct connections with direction and type filtering
  • callers — functions that call a given node (optionally transitive)
  • callees — functions called by a given node (optionally transitive)
  • shortest_path — how two concepts connect
  • god_nodes — most connected nodes (entry points)
  • stats — graph-level statistics

Safety & Refactoring

  • impact — blast radius analysis (what breaks if you change X)
  • detect_changes — map git diff to affected symbols
  • rename — safe multi-file rename with confidence tagging
  • retest — minimum set of tests to re-run after changes
  • communities — detect functional groupings with cohesion scores
  • graph_query — Cypher-like pattern matching ("function -calls-> function")
  • bridges — find architectural hotspots connecting communities

Code + Doc Fusion (unique to Nexus)

  • provenance_chain — citation → equation → code traceability
  • verification_coverage — equation → code → test coverage map (supports limit/offset pagination)
  • verification_audit — complete V&V audit: coverage + staleness + prioritized gap list (supports group_by and include_tests)
  • verification_gaps — untagged tests, unverified equations, missing err catchers (supports module and level filters)
  • staleness — detect docs that drifted from code
  • session_briefing — AI agent context restoration
  • trace_error — trace from failing test to equations on call path
  • migration_plan — plan dependency migration with phased blast radius
  • ingest — LLM-powered paper/PDF ingestion into the graph
  • processes — detect named execution flows through the codebase (supports limit/offset pagination)

Workspaces (git worktrees)

  • workspaces — list every checkout of the project (main tree + linked git worktrees) with branch, graph presence, and build provenance
  • use_workspace — switch the server to the graph built inside another checkout, referenced by worktree name, branch name, or absolute root path (per-session; auto-reload follows)

Node results from AST-derived symbols carry file_path and lineno, so any query answer can be fed straight back to an editor, LSP request, or file read — the position → node bridge (node_at) runs in both directions.

Edit-time file brief (the ambient channel)

nexus file-brief path/to/module.py --db _nexus/graph.db --project-root .

Prints ≤6 lines of graph context for one source file — node count and external callers, the highest-degree node's copy-pasteable ID, the equations the file implements and how many tests verify them, the doc pages documenting it, and a staleness flag when the file changed since the graph was built. It reads the SQLite database directly (no graph load, ~100 ms warm), which makes it cheap enough to wire into an edit-time hook (e.g. a Claude Code PostToolUse hook on Edit|Write): graph context then arrives WITH every edit, the way a language server pushes diagnostics, instead of waiting to be asked. --json emits the full structured brief.

Usage journal

Every tool call appends one JSON line to ~/.nexus/usage.jsonl (timestamp, tool, args, duration, outcome, active workspace) so tool adoption can be evaluated from recorded behavior. Set NEXUS_USAGE_LOG=<path> to relocate it, or set it empty to disable. Journaling never blocks or fails a tool call.

MCP Resources (4)

Resource Content
nexus://graph/stats Node/edge counts by type
nexus://graph/communities Functional area summaries
nexus://graph/schema Node types, edge types, ID format
nexus://briefing Session briefing for AI agents

Skills (9)

Installed via nexus setup. Each skill triggers on natural language:

Skill Triggers on
nexus-exploring "How does X work?", "What calls this?"
nexus-impact "Is it safe to change X?", "What tests to re-run?"
nexus-debugging "Why is X failing?", "Which equation is wrong?"
nexus-refactoring "Rename this", "Extract this into a module"
nexus-verification "What's verified?", "Which docs are stale?"
nexus-migration "Plan numpy→jax migration"
nexus-guide "What Nexus tools are available?"
nexus-cli "Analyze the codebase", "Start the server"
behavioral-auto-regression "Agent is using Grep instead of Nexus", "Tool selection is wrong"

V&V Integration

Nexus turns pytest markers, RST directives, and repository-level YAML into typed verification edges in the graph, so audit tools can answer "which equations are actually verified, and by which tests, at what V&V level?" without hand-wiring.

From pytest markers (zero config)

Add standard pytest markers to your tests and they flow through to the graph automatically:

import pytest

@pytest.mark.l0
@pytest.mark.verifies("transport-cartesian")
@pytest.mark.catches("FM-07")
def test_attenuation_vacuum_source():
    ...

After the next Sphinx build, the corresponding test node carries vv_level="L0", verifies=("transport-cartesian",), and catches=("FM-07",) in its metadata. A merge.write_verifies_edges pass then walks every function with a verifies tuple and emits real EdgeType.TESTS edges from the test to math:equation:transport-cartesian. Class-level and module-level pytestmark declarations propagate to contained test methods (gated on is_test=True — private helpers don't inherit).

The @verify.l0(equations=[...], catches=[...]) sugar form is also recognized.

From RST directives

Declare verification edges directly in theory prose:

.. math::
   :label: transport-cartesian

   \dots

.. implements:: transport-cartesian
   :by: orpheus.sn.solve_sn

.. verifies:: transport-cartesian
   :by: tests.test_sn.test_transport

Both directives accept an explicit :by: option naming the Python symbol. When omitted, they fall back to inspecting env.ref_context so usage nested inside .. py:function:: / .. autofunction:: blocks picks up the enclosing signature automatically. Directive edges are tagged source="directive" and survive incremental builds via a docname-keyed pending queue with an env-purge-doc handler.

From a registry YAML

For bulk declarative facts that live with the repo rather than the tests, drop a verification.yaml somewhere and point nexus_verification_registry at it:

version: 1

verifications:
  - test: py:function:tests.test_solver.test_attenuation
    verifies: [transport-cartesian]
    level: L0
    catches: [FM-07]

implementations:
  - function: py:function:orpheus.sn.solve_sn
    implements: [transport-cartesian]
    confidence: 1.0

Schema errors raise RegistryError at build time with a path-and-field context. Missing nodes (test / function / equation) are logged and skipped — the registry can name symbols that don't exist yet without breaking the build.

Querying the result

Every path above produces the same EdgeType.TESTS / EdgeType.IMPLEMENTS edges, so the audit tools don't care which source they came from. The source attribute distinguishes pytest.mark.verifies, directive, registry, and the fallback inferred heuristic.

from sphinxcontrib.nexus.query import GraphQuery
from sphinxcontrib.nexus.export import load_sqlite

q = GraphQuery(load_sqlite("docs/_build/html/_nexus/graph.db"))

# Full audit bucketed by V&V level
audit = q.verification_audit(group_by="level", include_tests=True)
for level, gaps in audit.grouped.items():
    print(f"{level}: {len(gaps)} unverified equations")
print(f"declared: {audit.summary['tests_declared']}  heuristic: {audit.summary['tests_inferred']}")

# Gap hunt
gaps = q.verification_gaps(module="orpheus.sn", level="L0")
print(f"untagged tests in orpheus.sn: {len(gaps.untagged_tests)}")
print(f"unverified L0 equations:     {len(gaps.unverified_equations)}")

Same surface on the MCP side (verification_audit, verification_gaps) and the CLI (nexus audit, nexus gaps).

Git Worktrees & Workspaces

A graph database is a snapshot of one checkout. Agent harnesses (e.g. Claude Code) spawn the MCP server against the main checkout and keep it running when a session moves into a git worktree — so without help, worktree sessions silently query the wrong branch's graph. Nexus closes that hole in four layers:

  1. Provenance stamping. Every graph write (Sphinx build, nexus analyze) stamps metadata["provenance"] with source_root, built_at, git_branch, git_commit, git_dirty. Every database says which tree it is a snapshot of.
  2. Discovery. workspaces (MCP) / nexus workspaces (CLI) enumerate all checkouts via git worktree list and report which have graphs, on which branch, built from where.
  3. Switching + tripwire. use_workspace(root) re-points the server at another checkout's graph (one server per agent session, so the switch is session-scoped); it accepts a worktree directory name, a branch name, or an absolute root path. session_briefing carries a workspace block that warns when the graph's branch no longer matches the checkout or when sibling worktrees have graphs of their own — the wrong-tree mismatch surfaces on the session's first turn.
  4. Roots auto-alignment. session_briefing asks the client (MCP roots/list) which directory the session was launched from; when that lies inside a different checkout that has a graph, the server switches to it automatically and reports the switch under workspace.auto_align. Sessions launched inside a worktree need no manual step at all.

Recommended agent protocol for sessions that enter a worktree mid-session (roots updates there are client-dependent): build the docs (or run nexus analyze) inside the worktree, then call use_workspace(<worktree name>).

Storage

The graph is stored in two formats:

  • SQLite (primary) — indexed queries, FTS5 full-text search, 0.05ms neighbor lookups. Written with a schema_version row in the metadata table. load_sqlite rejects databases written by a future nexus release with SchemaVersionError, so downgrading consumers fail loud instead of silently misreading.
  • JSON (secondary) — human-readable, NetworkX node-link format.

Python API

from sphinxcontrib.nexus.export import load_sqlite
from sphinxcontrib.nexus.query import GraphQuery

kg = load_sqlite("_nexus/graph.db")
q = GraphQuery(kg)

# What uses numpy.ndarray?
q.query("ndarray", node_types=["external"])

# Blast radius of changing a function
q.impact("py:function:sn_solver.solve_sn", direction="upstream")

# Citation → equation → code chain
q.provenance_chain("py:function:sn_sweep.sweep_spherical")

# Migration plan
q.migration_plan("numpy", "jax")

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sphinxcontrib_nexus-0.12.0.tar.gz (125.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sphinxcontrib_nexus-0.12.0-py3-none-any.whl (139.4 kB view details)

Uploaded Python 3

File details

Details for the file sphinxcontrib_nexus-0.12.0.tar.gz.

File metadata

  • Download URL: sphinxcontrib_nexus-0.12.0.tar.gz
  • Upload date:
  • Size: 125.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sphinxcontrib_nexus-0.12.0.tar.gz
Algorithm Hash digest
SHA256 48cb18df37d70b8cb65b8cad1471c82ebb1c4aaf71a4baa1bf07dec3f7eae7cb
MD5 4e1ecda80293a2c3fa57899e5e6267e7
BLAKE2b-256 59be2d2b7c3d76da596f07ce3aca4fa7dd5e1fcf36b125766e0a221aeb6ae2e8

See more details on using hashes here.

Provenance

The following attestation bundles were made for sphinxcontrib_nexus-0.12.0.tar.gz:

Publisher: publish.yml on deOliveira-R/sphinxcontrib-nexus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sphinxcontrib_nexus-0.12.0-py3-none-any.whl.

File metadata

File hashes

Hashes for sphinxcontrib_nexus-0.12.0-py3-none-any.whl
Algorithm Hash digest
SHA256 46aeefd42e6e19f9d8adaf02280c2368769faceb1ad8feeeca34ed0b5de9f347
MD5 a72818e757b9dc8260fb2a3d65b50957
BLAKE2b-256 11c81526c4d81d63b46b00f94dced53afdb13fa42ab24c8bc298bbd5988a20c9

See more details on using hashes here.

Provenance

The following attestation bundles were made for sphinxcontrib_nexus-0.12.0-py3-none-any.whl:

Publisher: publish.yml on deOliveira-R/sphinxcontrib-nexus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page