Every node and edge in the KuzuDB graph follows this schema. Node kinds are
first-class in the query API even though they share one physical Symbol table
(see architecture.md for why).
| Kind | Key properties | Notes |
|---|---|---|
ModuleNode |
name, package | External or unindexed modules (module:requests) |
FileNode |
path, language, size, last_modified | id is the project-relative path |
ClassNode |
name, file, extends, implements, docstring, line_range | |
FunctionNode |
name, file, params, return_type, complexity, docstring, line_range | methods included, qualname Class.method |
TypeNode |
name, file, fields | TypedDict/Protocol/NamedTuple (Py), interface/type/enum (TS) |
ChunkNode |
parent, line_range, embedding_text | sub-function embedding units for long functions |
ExternalNode |
name | unresolved reference target (external:hashlib.sha256) |
file: src/auth/service.py
class: src/auth/service.py:AuthService
function: src/auth/service.py:AuthService.login
chunk: src/auth/service.py:AuthService.login#2
module: module:requests
external: external:hashlib.sha256
Ids are stable and human-readable — you can pass them straight back into
get_symbol.
Every edge carries confidence: float in [0.0, 1.0]. Confidence is stored,
never filtered at write time; callers set their own threshold at query time.
| Edge | Meaning | Typical confidence |
|---|---|---|
IMPORTS |
file → file/module it imports | 1.0 |
DEFINES |
file/class → symbol it defines | 1.0 |
EXTENDS |
class → base class | 1.0 local, 0.9 imported, 0.3 unresolved |
IMPLEMENTS |
class → interface | same as EXTENDS |
CALLS |
function → function it calls | 1.0 direct/local, 0.8–0.9 via import, 0.2–0.5 dynamic |
MUTATES |
function → class/file whose state it mutates | 0.7–0.9 |
TEST_FOR |
test function → symbol under test | 1.0 if naming matches, 0.6 otherwise |
PART_OF |
chunk → parent function | 1.0 |
Confidence exists because static analysis is incomplete, not wrong. A call through dynamic dispatch, dependency injection, or monkey-patching cannot be statically proven to hit a specific definition — but dropping it would produce a misleadingly clean graph. sciogen keeps the edge and scores it low, so:
- High-precision queries filter to
min_confidence >= 0.8and see only edges static analysis can prove. - Exploratory queries keep the default
0.0and see the full picture, weak edges included, each labeled with how much to trust it.
Path confidence on multi-hop traversals is the minimum edge confidence along the path — a call chain is only as trustworthy as its weakest link.
Separate from the graph, ChromaDB holds one embedding per node at four granularities. The query layer picks the granularity based on the API call:
| Granularity | Node kinds | Answers |
|---|---|---|
| file | FileNode | "how is the auth module structured?" |
| class | ClassNode, TypeNode | "classes that handle session management" |
| function | FunctionNode | "functions that validate JWTs" |
| chunk | ChunkNode | "the block that rate-limits login attempts" |
Embedding text is always a normalized summary (name + file + params + docstring + call list), never raw source.