SkillAgentSearch skills...

Graphlens

Polyglot code-analysis framework — parses Python, TypeScript, Go, Rust & PHP into a shared graph IR (tree-sitter + type-aware resolvers: ty, tsc, gopls, rust-analyzer). Call/dependency graphs, cross-language boundaries, Neo4j export

Install / Use

npx skills add Neko1313/graphlens

Installs into whichever agent you are using.

README

[!IMPORTANT] graphlens is archived and no longer maintained. Its successor is callix.

callix is a full rewrite of this project by the same author, with the analysis moved to Rust. What it changes:

  • One install, no assembly. graphlens asks you to bring the language servers yourself — ty, gopls, rust-analyzer, intelephense — and to keep them on PATH and in step with each other. callix links the Python and TypeScript type checkers into the module, standard-library stubs included, so pip install callix is the whole setup. Go and Rust still use the toolchain your project already has, but no separate language server.
  • Faster. 5.2× on apache/superset, 3.3× on colinhacks/zod, 2.6× on gin-gonic/gin. The resolution phase in particular, which used to be JSON-RPC round-trips, dropped from 39.1s to 8.9s on superset.
  • Lighter. Resolving Rust no longer keeps an interactive rust-analyzer server resident — a batch SCIP index is written once and read statically, instead of a process that grows into tens of gigabytes on a large workspace.
  • Same graph. The same 14 node kinds, 12 relation kinds, deterministic IDs and serialization format: a graph written here reads there and back. Structural parity is verified by diffing both implementations on superset, zod, gin, ripgrep and ruff.

Not carried over: the CLI, the MCP server, the Neo4j backend, the HTML visualization, and the PHP and C# adapters. If you depend on those, this repository stays readable at its final state.

Migration notes

<div align="center"> <h1>graphlens</h1> <p>Extensible polyglot code analysis framework that parses source projects, normalizes their structure into a shared graph IR, and exposes it for dependency analysis, navigation, and code intelligence tooling.</p>

PyPI Python License CI codecov

Documentation · Repository · Issues

</div>

Architecture

Repository → Language Adapter → GraphLens (IR) → Graph Backend

| Layer | Responsibility | |---|---| | Language Adapter | Parses source files, produces GraphLens | | GraphLens | Typed nodes + directed relations (the IR) | | Graph Backend | Persists or queries the graph (Neo4j, in-memory, …) |

Adapters are pure data producers — they never write to any backend. The graph is the only output.

Why graph IR?

  • Language-agnostic — one shared model for Python, TypeScript, Go, Rust, PHP, C#, …
  • Plugin-based adapters — each language is a separate package, registered via Python entry points
  • Tree-sitter powered — all adapters use tree-sitter for CST parsing and exact span positions, combined with type-aware resolution (ty for Python, TypeScript Compiler API for TypeScript, gopls for Go, rust-analyzer for Rust, Intelephense for PHP, scip-dotnet for C#)
  • Cross-language aware — adapters emit language-agnostic BOUNDARY ports (HTTP, queues, gRPC, Temporal); graphlens-link connects a consumer in one language to a provider in another
  • Monorepo awarecan_handle() and find_*_roots() handle multi-language repos correctly
  • Deterministic node IDs — SHA-256 hash of project::kind::qualified_name → stable across re-scans

Benchmarks

Analysis throughput on large real-world projects, refreshed automatically on every release — one cold run per project inside the published Docker image (so the numbers reflect exactly the toolchain users get). See benchmarks/ to reproduce locally or add a project.

<!-- BENCH:START -->

Last run: 2026-07-24 12:52 UTC · image latest · runner Linux x86_64 · single cold run, indicative only.

| Project | Lang | Commit | LOC | Files | Nodes | Relations | Time | Peak RSS | KLOC/s | Resolver | Resolved | |---|---|---|--:|--:|--:|--:|--:|--:|--:|:--|--:| | apache/superset | python | c83fb2b | 399 519 | 1 886 | 156 044 | 379 553 | 150.9s | 1,793 MB | 2.6 | ok | 84% of 281 667 (74s) | | colinhacks/zod | typescript | 1fb56a5 | 74 194 | 404 | 8 623 | 24 557 | 22.2s | 567 MB | 3.3 | ok | 87% of 15 771 (19s) | | gin-gonic/gin | go | 73726dc | 23 672 | 98 | 7 227 | 11 882 | 13.9s | 2,186 MB | 1.7 | ok | 100% of 8 920 (13s) | | casdoor/casdoor | go | 696bcf0 | 86 898 | 458 | 14 987 | 28 276 | 130.1s | 14,503 MB | 0.7 | ok | 100% of 19 421 (127s) | | gohugoio/hugo | go | 4d22555 | 224 821 | 897 | 34 809 | 72 225 | 110.8s | 9,499 MB | 2.0 | ok | 99% of 49 013 (104s) | | BurntSushi/ripgrep | rust | 4649aa9 | 50 275 | 98 | 5 365 | 15 087 | 13.9s | 1,264 MB | 3.6 | ok | 99% of 11 435 (0s) | | tokio-rs/axum | rust | c59208c | 43 653 | 296 | 8 093 | 14 798 | 70.2s | 4,544 MB | 0.6 | ok | 88% of 9 662 (0s) | | astral-sh/ruff | rust | 6686f63 | 687 409 | 1 870 | 69 708 | 217 127 | 174.3s | 8,094 MB | 3.9 | ok | 100% of 155 276 (7s) | | laravel/framework | php | bd8aeb6 | 441 358 | 2 478 | 139 764 | 189 708 | 113.9s | 2,958 MB | 3.9 | ok | 56% of 191 435 (98s) | | dotnet/eShop | csharp | 9b4f943 | 25 385 | 527 | 13 124 | 29 171 | 26.0s | 2,413 MB | 1.0 | ok | 80% of 26 629 (2s) | | microsoft/reverse-proxy | csharp | 4154b6d | 63 236 | 585 | 9 714 | 17 756 | 6.7s | 77 MB | 9.5 | unavailable | 0% of 72 295 (5s) | | Total | | | 2 120 420 | | 467 458 | | 832.8s | | 2.5 | | 75% of 841 524 |

ℹ️ prepare exited 155 (dotnet restore YARP.sln)

<sub>Peak RSS measured via cgroup.v2 (whole process tree, incl. LSP resolver subprocesses). KLOC/s = analysed thousands-of-lines per second. Generated by benchmarks/run_benchmarks.py.</sub>

<!-- BENCH:END -->

Documentation

Full product documentation lives at https://Neko1313.github.io/graphlens/ (built with Docusaurus from website/):

  • Getting Started — install, quick start, core concepts
  • Guides — library API, CLI, querying, visualization, Neo4j, cross-language
  • CI Integration — strict mode, GitHub Actions, Docker, local hooks
  • Adapters — Python, TypeScript, Go, Rust, PHP, C#, and writing your own
  • Graph Model — nodes, relations, boundaries, serialization
  • API Reference — exact signatures

To run the docs locally: cd website && pnpm install && pnpm start.

Installation

# Core library only (models, contracts, registry)
pip install graphlens

# Core + Python adapter
pip install "graphlens[python]"

# Core + TypeScript adapter
pip install "graphlens[typescript]"

# Core + Go / Rust / PHP / C# adapters
pip install "graphlens[go]"
pip install "graphlens[rust]"
pip install "graphlens[php]"
pip install "graphlens[csharp]"

# CLI (graphlens analyze / visualize / query / neo4j)
pip install "graphlens-cli[python]"          # with Python adapter
pip install "graphlens-cli[all]"             # Python + TS + Go + Rust + PHP + C# + Neo4j

With uv:

uv add graphlens
uv add "graphlens[python]"
uv add "graphlens[typescript]"
uv add "graphlens-cli[all]"

Docker (all adapters + toolchains pre-installed)

For CI, the published image bundles the CLI with every adapter and the toolchains their resolvers drive (ty, Node, Go + gopls, Rust + rust-analyzer, PHP + Intelephense) — no local setup required, and the supported way to get the Go, Rust and PHP adapters (which are not published to PyPI). Mount your project at /workspace:

docker run --rm -v "$PWD:/workspace" ghcr.io/neko1313/graphlens \
    analyze /workspace --output /workspace/graph.json

The image is published to the GitHub Container Registry on each release (:latest plus :X.Y.Z / :X.Y version tags).

Quick start

from pathlib import Path
from graphlens import adapter_registry

# Load and instantiate the Python adapter
adapter = adapter_registry.load("python")()

# Analyze a project — returns a GraphLens
graph = adapter.analyze(Path("./my-project"))

print(f"Nodes:     {len(graph.nodes)}")
print(f"Relations: {len(graph.relations)}")

# Inspect nodes by kind
from graphlens import NodeKind

modules = [n for n in graph.nodes.values() if n.kind == NodeKind.MODULE]
classes = [n for n in graph.nodes.values() if n.kind == NodeKind.CLASS]

# Check the resolver actually ran (don't trust a silently degraded graph)
from graphlens import RESOLVER_STATUS_KEY
assert graph.metadata[RESOLVER_STATUS_KEY] == "ok"

# Query the graph (indexed lookups, no manual scanning)
fn = next(n fo

Related Skills

View on GitHub
GitHub Stars11
CategoryDevelopment
Updated10d ago
Forks1

Languages

Python

Security Score

95/100

Audited on Jul 29, 2026

No findings