Skip to content

The Graph Model

CapsaicinBunny edited this page Jun 21, 2026 · 2 revisions

The Graph Model

Everything PolyGraph shows is a projection of one data structure: the GraphModel (lib/graph/types.ts) — nodes, edges, and the evidence behind each edge. This page is the reference for what those are.

Nodes

A node is a file or a symbol within it. Every node has a kind drawn from a universal, language-neutral taxonomy, so a Rust struct and a TypeScript interface sit in the same vocabulary:

file, class, interface, struct, trait, protocol, enum, union, record, object, type, namespace, module, function, method, constructor, accessor, component, macro, variable, constant, field, property, annotation — plus external (an imported third-party dependency).

Each kind has a color, glyph, and icon (lib/graph/visual.ts) and belongs to a filter layer shown in the sidebar:

Layer Kinds
Types class, interface, struct, trait, protocol, enum, union, record, object, type
Callables function, method, constructor, accessor, component, macro
Members field, property, variable, constant, annotation
Modules module, namespace

Collapse-to-file by default. Files start collapsed; expand a file to see its member-level nodes. This keeps even large graphs legible. The expand/collapse projection lives in lib/aggregate.ts.

Edges (relationships)

PolyGraph draws these relationship types automatically — no configuration:

Edge Meaning
import Module dependency between files
call Type-resolved function/method call (resolved via the TypeScript compiler for TS/JS, so two functions named handle link to the correct definition)
instantiates new X() construction
extends / implements Class & interface inheritance
has Composition — a typed field/property referencing another class or interface (resolved through arrays and generics)
injects Dependency injection — constructor parameter types
renders Which component renders which (JSX usage)

Repeated relationships read as a thicker edge with a ×N count rather than N separate lines.

Edge evidence & confidence

This is what separates PolyGraph from a guess. Every edge carries its evidence:

  • occurrences — a list of { filePath, line, column?, provider }. Occurrences are capped per edge (the cap is 25) but the count is the true total.
  • confidence — one of:
    • exact — resolved precisely (e.g. via the TypeScript type checker).
    • inferred — resolved by name against the project's symbol index (how the tree-sitter languages resolve).
    • ambiguous — more than one plausible target; surfaced in the Problems panel.

Click an edge to see exactly where the relationship was observed and how many times. When symbol→symbol edges collapse onto an aggregated file→file edge, the evidence is merged and the underlying edge ids are kept — so the UI can show "what's behind this edge". References PolyGraph couldn't resolve (broken relative imports, ambiguous resolutions) become findings in the Problems panel.

Roles (framework & paradigm detection)

Nodes are tagged with a role (colored + badged), disambiguated by file extension and imports:

  • React (JSX), Vue (.vue SFCs + defineComponent), Svelte, Angular (@Component / @Injectable / @Directive / @Pipe / @NgModule), and ECS (*Component / *System / *Entity, defineSystem / defineQuery).

These power queries like role:react-component (see Query Language).

External dependencies

Toggle external dependencies in the toolbar (off by default) to bring in imported npm packages, Node builtins, and Bun / Deno / process API usage as dashed external nodes, color-coded by source family. They're enriched from package.json with a version and dependency type: dependency / devDependency / peer / undeclared (imported but not in any manifest — a finding in its own right).

The 26 languages

Provider Languages
Precise (ts-morph) TypeScript, JavaScript (incl. .mts/.cts/.mjs/.cjs), and JSX/TSX
Tree-sitter packs Python, Java, Kotlin, Rust, Go, Scala, C#, F#, C, C++, Objective-C, Swift, Zig, Haskell, Ruby, PHP, Bash, Lua, Dart, Julia, R, Nix, OCaml, SQL, WebAssembly text

How each is analyzed — and how to add a new one — is in Language Analysis.

Abstraction levels

PolyGraph reads project manifests (package.json, Cargo.toml, pyproject.toml/poetry, go.mod, Maven pom.xml, Gradle) and projects the file graph up to package and workspace levels (lib/graph/levels/). A monorepo's module boundaries and cross-package dependencies become a single readable graph. The discovered manifests ride along with the scan response, so switching levels is instant — no re-scan.

Clone this wiki locally