nusy-codegraph
Code as a live Arrow object graph — parse source code into structured Arrow RecordBatches for zero-copy querying, versioning via git-native graph operations, semantic search, and impact analysis.
Note: This crate depends on internal NuSy workspace crates (
nusy-arrow-core,nusy-arrow-git,nusy-graph-query,noesis-ship) and cannot compile standalone from crates.io. It is designed for use within the NuSy monorepo or as a framework reference for building your own code graph system.
For AI Developers
This crate demonstrates a complete code-as-graph pipeline:
Source code → tree-sitter CST → CodeNodes + CodeEdges → Arrow RecordBatches
↓
Semantic search + impact analysis
If you want to build a similar system for your own language or toolchain, the key ideas are:
- Use tree-sitter for language-accurate CST parsing (not regex)
- Arrow RecordBatches for zero-copy columnar storage and Parquet persistence
- CodeEdges (calls, imports, inheritance) as first-class graph citizens
- Semantic search via embeddings over code nodes (fastembed or ollama)
- Git-native versioning via
nusy-arrow-gitWAL + atomic rename
Features
Code Parsing
- Rust — full support: functions, structs, enums, impl blocks, macros, const, static
- Python — partial support: functions, classes, async def
Code Graph
CodeNode— every function, class, module as a typed node with location and signatureCodeEdge— calls, imports, inheritance, containment as typed directed edges- Cross-file edge resolution via
NameResolver - Arrow schema for zero-copy columnar storage
Semantic Search
- Embed code nodes via fastembed or ollama
- Cosine similarity search over the embedded graph
- Natural-language queries via
codegraph_query_objects
Git-Native Graph Operations
codegraph_diff— what changed in the graph between commits?codegraph_merge— three-way graph merge with conflict detectionsmart_merge— semantic merge using AST-aware conflict resolution- Impact analysis: which nodes are affected by a change?
MCP Tools
nusy-mcp-bridgeexposes 4 tools as an MCP server:codegraph_query_objects— search the graphcodegraph_add_edge/codegraph_remove_edge— modify edgescodegraph_update_object— update node metadata
Binaries
| Binary | Purpose |
|---|---|
nusy-codegraph-ingest |
Ingest a directory into the graph |
nusy-codegraph-query |
Query the self-graph |
nusy-codegraph-service |
Long-running NATS service mode |
nusy-mcp-bridge |
MCP protocol bridge |
Architecture
Data Model
CodeNode
id: String # "module::function" path
kind: String # function | class | module | method | ...
language: String # rust | python
file_path: String
start_line: u32
end_line: u32
name: String
signature: String # full type signature
doc: String # docstring
CodeEdge
source_id: String
predicate: String # calls | imports | inherits | contains | ...
target_id: String
file_path: String # where the edge was observed
Schema (Arrow)
code_nodes_schema // subject, predicate, object, graph, version columns
code_edges_schema // source_id, predicate, target_id, file_path columns
Ingestion Pipeline
1. Discover → find all .py / .rs files by language
2. Parse → tree-sitter CST → CodeNodes (functions, classes, etc.)
3. Extract → extract_edges() builds Contains/Imports/Inheritance edges
4. Resolve → NameResolver (Python) or RustModuleResolver (Rust)
maps unqualified names → full CodeNode IDs
5. Write → Arrow RecordBatch → Parquet (WAL + atomic rename)
6. Embed → optional: embed_nodes() for semantic search
NameResolver (edges.rs) — Python and cross-language edges.
Maps short names and qualified names to CodeNode IDs using a HashMap.
Used by extract_edges() for Python files and as a fallback for Rust.
RustModuleResolver (module_resolver.rs) — Rust-specific resolution.
Handles use statements → specific CodeNodes (not just module-level edges),
impl Trait for Type → ImplementsTrait edges, pub use → ReExports edges.
Used by extract_cross_file_edges() for Rust files.
extract_call_edges (edges.rs) — call edge extraction.
When rust-analyzer is available, uses extract_scip_call_edges() for
compiler-quality call detection via SCIP. Falls back to text scanning
(name( pattern matching) when SCIP is unavailable.
Known limitations of text scanning: misses indirect calls, dynamic dispatch,
and calls via variables. Use rust-analyzer for production-accuracy.
Quick Start
# Ingest a Rust project into the graph
# Query the self-graph (project ingests itself)
# Start service mode (NATS)
# MCP bridge for AI agent integration
As a Library
use ;
Semantic Diff
use semantic_diff;
let diff = semantic_diff?;
println!;
Ecosystem
nusy-codegraph is part of the NuSy Arrow workspace:
| Crate | Role |
|---|---|
| nusy-arrow-core | Arrow schemas, graph store |
| nusy-arrow-git | Graph-native git primitives |
| nusy-graph-query | SPARQL-style graph queries |
| nusy-codegraph | Code-as-graph with tree-sitter parsing |
| nusy-kanban | Arrow-native kanban + HDD research |
Performance
| Operation | Typical Time | Notes |
|---|---|---|
| Ingest Rust crate (1k files) | 30–60s | tree-sitter parsing is CPU-bound |
| Ingest Python project (1k files) | 20–40s | Partial support — faster |
| Semantic search (10k nodes) | 100–300ms | Embedding lookup + cosine similarity |
| Query (100k nodes) | <10ms | Arrow columnar — O(result set) |
Memory usage: ~500MB for 10k-node graph. Larger graphs scale linearly with node count.
Known bottlenecks:
- tree-sitter parsing is single-threaded per file (use
--jobsfor parallelism) extract_call_edgestext scanning is O(source_lines × callable_count) when SCIP is unavailable
Limitations
- Python support is partial — only functions and classes are extracted. Type hints, decorators, and complex control flow are not yet parsed.
- Only Rust and Python — no TypeScript, Go, or other languages.
- Not standalone — requires
nusy-arrow-core,nusy-arrow-git,nusy-graph-query, andnoesis-shipas path dependencies. A fully FOSS version would need to publish those crates separately or reimplement against public crate equivalents. - No incremental parsing — re-ingestion is a full re-parse. Large codebases pay the full tree-sitter cost on every update.
License
MIT