CodeGraph gives Codex and Claude Code a source-linked structural view of a repository: an agent can locate an implementation, follow definitions and references, inspect dependency routes, and cite the exact source it used. The setup is local, keeps indexes outside the target checkout by default, and does not require a model or API key to build the graph.
Use CodeGraph with Codex or Claude Code
Start with Python 3.10 or newer, Git, a clean target repository, and at least one installed codex or claude CLI on PATH. To try the current CodeGraph onboarding workflow from source, install the development checkout:
git clone https://github.com/sysevol-ai/CodeNib.git
cd CodeNib
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[graph,mcp]"
# Preview the plan, then build the indexes and register the MCP server.
codenib codegraph init /absolute/path/to/repository --dry-run
codenib codegraph init /absolute/path/to/repository
codenib codegraph status /absolute/path/to/repository --json
The dry run performs no installation, indexing, receipt write, or client registration. The real initialization detects installed clients, builds reusable repository state outside the target checkout by default, and asks each native client CLI to own its MCP registration. Pass --agent codex or --agent claude to select one explicitly.
Ask through the registered MCP tools
Open a client session for the target repository and give the agent a concrete evidence contract:
Use CodeNib's explore_context to locate and explain the implementation of
<feature>. Cite the returned source paths and line numbers, then use
dependency_subgraph on the key symbol with direction impact and depth 2
before proposing an edit.
explore_context is the broad entry point for bounded, source-verified context. Use dependency_subgraph directly when the question is specifically about callers, callees, or change impact. The CodeGraph guide records language prerequisites, status checks, and safe uninstall behavior.
Abbreviated agent turn · pinned source
From a repository question to a cited answer
This compact transcript is grounded in the CodeNib repository at 85f5bec2; it illustrates the tool contract rather than quoting model output.
You
How does codegraph init protect my checkout, and what would be affected if that guard changed?
CodeNib-backed answer
● pinned source
Initialization repeatedly guards the target checkout against mutation. It captures the exact Git porcelain state in memory, requires a clean checkout, and compares that snapshot after toolchain setup, indexing, and client registration. A mismatch prevents readiness; it does not claim global rollback.
The impact graph identifies _run_codegraph_init as a caller. Exact source windows then show that changing the guard affects every mutable onboarding stage, not just one call site.
The commands above exercise the source-preview onboarding workflow. As of August 14, 2026, it is on main but not in the latest 0.2.0 wheel. The onboarding path prepares the public CodeGraph and MCP surface; it does not force every capability-gated native path described below, and durable FactBatch publication remains opt-in.
Internally, CodeNib traditionally materializes semantic records into a complete CodeGraph before serving definitions, references, positions, and routes. The complete graph remains the compatibility authority, but it is more machinery than a narrow query needs. The implementation described below adds a capability-scoped FactQueryIndex v1 read model and a separate FactBatch v1 per-file semantic contract.
Shared semantics, separate runtime paths
SCIP index.decoded files and clangd .idx shards start with different schemas. Both paths normalize definitions, references, occurrences, traversal order, and capability state against shared semantic contracts, but they do not reuse one runtime decode object. The native clangd query path builds compact C++ records directly; the current clangd FactBatch adapter validates the shards, collects normalized Python records, and then constructs per-file batches.
READ MODEL
FactQueryIndex
Retains decoded records in native memory and builds integer postings for supported symbols and references, plus provider-specific occurrence and adjacency capabilities. It is ephemeral and does not publish graph state.
WRITE MODEL
FactBatch v1
Packages one file's semantic facts with content and analyzer identity. The current durable generation coordinator publishes clangd/C++ units with compare-and-swap.
The distinction matters: FactQueryIndex is not built from FactBatch, and FactBatch does not make an online query faster by itself. Both consume normalized facts, while the existing CodeGraph path remains available for capabilities the compact read model cannot prove.
FactQueryIndex: query-shaped native postings
FactQueryIndex owns immutable decoded records and indexes them by integer vertex or row IDs. Its postings cover canonical and display names, aliases, incoming references, optional per-file occurrence intervals, and optional predecessor/successor adjacency. Supported calls avoid constructing igraph and the intermediate Python dictionaries and dataclasses used by full materialization.
The index validates its input before a candidate can serve results: symbol names must be globally unique, endpoints and source ranges must be valid, complete route order must cover every vertex exactly once, and providers configured to require anchored references must supply their locations. Exact-position lookup uses sorted per-file intervals and a prefix maximum end.
The raw index can retain complete adjacency but does not advertise public graph routes by itself. The clangd provider adapter enriches only touched nodes with source spans and exposes the route contract when the decoded capability is complete. SCIP v1 currently exposes only supported symbol definition and anchored-reference queries.
Atomic fallback
Before a native candidate is published, auto may select the compatible graph. After publication, unsupported or ambiguous positions and unavailable or failed route preparation can recompute the whole request through one graph. Snapshot mutation, receipt failure, and MemoryError do not switch generations or return a partial answer; they fail closed.
What the clangd promotion gate measured
The current production-promoted path is scoped to source-verified, local C/C++ checkouts with existing clangd shards. The final v3 workload gate used fmt 11.2.0 at commit 40626af88bd7df9a5fb80be7b25ac85b122d6c21, 492 shards (4,820,850 bytes), 20 deterministic query entries, one query-only route, and three process-isolated measured rounds after warmup.
Median query-ready wall time for the legacy full graph and native clangd provider across four workloads.
| Workload |
Full graph |
Native |
Improvement |
Native CodeGraph materializations |
| Symbol-only | 2.9039 s | 0.1950 s | 93.3% | 0 |
| Position-first | 3.0069 s | 0.4308 s | 85.7% | 0 |
| Route-first | 2.7913 s | 0.7221 s | 74.1% | 0 |
| Mixed | 2.8408 s | 0.9655 s | 66.0% | 0 |
The zeroes in the final column are intentional. In every measured native sample, graph_materialization_count remained zero: the decoder did not instantiate the complete Python CodeGraph/igraph representation. It still used graph-shaped data—symbol and reference postings, occurrence intervals, and, for supported route requests, compact native adjacency through the clangd adapter. The legacy arm built one complete graph per isolated process.
Scope: median query-ready wall_seconds, including provider startup and the fixed workload over already-generated .idx shards. Process startup, external receipt checks, and clangd index generation are excluded; filesystem page cache was not controlled. Exact public result/error parity, pre/post receipts, source cleanliness, RIFF 18/19/20 support, RSS budgets, zero complete CodeGraph materializations, and three eight-thread route rounds were separate gates. See the measurement protocol.
SCIP passed one boundary and failed another
The low-level SCIP read index also cleared the 20% query-ready gate over saved index.decoded artifacts: CodeNib Python moved from 0.4006 s to 0.2991 s (25.3%), and Ruff Rust from 2.4401 s to 1.7280 s (29.2%). These are median end-to-end decode plus index-or-graph build plus 100 definition/reference symbol pairs, with exact parity; external SCIP generation is excluded.
That result did not promote the production SCIP MCP route. A later end-to-end MCP consumer gate missed the threshold, so its promoted language set remains empty and production agent requests continue to use the persisted CodeGraph. This is why promotion is attached to a specific consumer boundary rather than to the data structure in general.
FactBatch v1: deterministic per-file state
A FactBatch represents the semantic facts for exactly one canonical repository-relative file. Its reuse key binds schema, path, language, source content digest, analyzer profile digest, and provider. The immutable batch digest additionally covers completeness, position encoding, capabilities, and the deterministically sorted definitions, occurrences, edges, provenance, resolver decisions, and bounded diagnostics.
The current durable generation coordinator is restricted to clangd/C++. It applies whole-file upserts and deletes: an unchanged unit keeps its immutable object receipt, a changed unit is republished, and a manifest binds the complete sorted membership and source identity. The named reference moves only after every member verifies and a catalog compare-and-swap succeeds. A failed publication cannot expose a half-written generation.
Measured reuse, not a generic speed claim
On the same pinned fmt checkout and its 492 existing clangd shards, the durable generation gate produced 51 file units containing 9,783 definitions, 98,552 occurrences, and 85,903 edges. An unchanged publication reused all 51 units, republished none, and materialized no CodeGraph.
Median time for the clean adapter and publication arm versus the no-upsert FactBatch reuse publication arm.
| Profiling arm | Median time | Reused | Published |
| Adapter + first publication | 9.9169 s | 0 / 51 | 51 |
| No-upsert reuse publication | 5.2349 s | 51 / 51 | 0 |
The recorded difference between these profiling arms is 47.2%. The first arm includes clangd-record-to-FactBatch adaptation and initial publication; the second loads and validates the prior generation, supplies no upserts, and publishes a new manifest while reusing 51/51 units. It does not rerun the adapter, detect changes, or generate clangd shards, so this is not an end-to-end incremental rebuild claim. The semantic-facts view is opt-in; the legacy materialized graph remains the public graph authority.
The negative result: transport was not enough
FactBatchBuffer v1 is a related but distinct C++/Python transport: fixed-width little-endian tables plus one UTF-8 string arena. By design it can expose ownership-safe read-only table buffers without copying each table into Python bytes, but it did not make the measured consumers faster enough to promote.
Saved-artifact FactBatchBuffer results for CodeNib Python and Ruff Rust consumers.
| Subject | Consumer | Legacy | Buffer | Change |
| CodeNib / Python | Graph-compatible | 0.3775 s | 0.3937 s | −4.3% |
| CodeNib / Python | Logical FactBatch | 0.6271 s | 0.6772 s | −8.0% |
| Ruff / Rust | Graph-compatible | 1.9756 s | 2.0352 s | −3.0% |
| Ruff / Rust | Logical FactBatch | 3.2654 s | 3.2031 s | +1.9% |
These are local median end-to-end measurements from saved SCIP artifacts: CodeNib Python was 41.6 MB and Ruff Rust was 130.5 MB; external SCIP generation was excluded. All parity checks passed, but none of the paths cleared the 20% gate. CODENIB_CORE_FACT_BUFFER therefore remains off by default. The buffer is an intermediate representation, not a promoted acceleration result.
Current selection boundaries
Reproduce and inspect
The repository includes separate profilers because each claim has a different boundary. Supply an existing SCIP artifact or clangd shard directory and keep external index generation distinct from query-ready measurements.
# SCIP: existing index.decoded → query-ready consumer
make fact-query-profile \
FACT_QUERY_PROFILE_INDEX=/path/to/index.decoded \
FACT_QUERY_PROFILE_LANGUAGE=python \
FACT_QUERY_PROFILE_PROJECT_ROOT=/path/to/repository
# clangd: existing shards → fixed symbol/position/route workloads
make clangd-workload-gate \
CLANGD_WORKLOAD_GATE_INDEX_DIR=/path/to/.cache/clangd/index \
CLANGD_WORKLOAD_GATE_PROJECT_ROOT=/path/to/repository \
CLANGD_WORKLOAD_GATE_SUBJECT_ID=fmt-11.2.0
# clangd: clean publication versus unchanged FactBatch reuse
make clangd-fact-generation-profile \
CLANGD_FACT_GENERATION_PROFILE_INDEX_DIR=/path/to/.cache/clangd/index \
CLANGD_FACT_GENERATION_PROFILE_PROJECT_ROOT=/path/to/repository \
CLANGD_FACT_GENERATION_PROFILE_COMPILE_COMMANDS=/path/to/compile_commands.json \
CLANGD_FACT_GENERATION_PROFILE_TARGET_TRIPLE=x86_64-unknown-linux-gnu \
CLANGD_FACT_GENERATION_PROFILE_BUILD_CONTEXT_DIGEST=sha256:<digest>
Implementation and contract details live in C++ core acceleration, Semantic FactBatch v1, and the source for FactQueryIndex, FactBatch, and generation publication.
The design goal is narrower than “remove the graph”: materialize only the representation a proven consumer needs, preserve source and snapshot identity across that choice, and keep the complete graph as an explicit compatibility boundary.