Skip to content
Oday Bakkour
Back to Knowledge Hub

Graphify: I Mapped My 3,690-File Repo Into a Knowledge Graph

Oday Bakkour profile photo
Oday Bakkour
4 min read
Share
Graphify: I Mapped My 3,690-File Repo Into a Knowledge Graph

Executive Summary

  • What it is: Graphify is an open-source (Apache-2.0) tool that turns a repo into a knowledge graph your coding agent can query instead of grepping. It has 134k stars on GitHub and gained about 6.9k of them this week (GitHub trending).
  • I ran it on my own repo: Helpdock's 3,690 code files became 30,114 nodes and 111,921 edges in 33 seconds, with 0 LLM tokens. None of the code left my machine.
  • What it found: the hubs everything runs through (DbTransaction, 1,693 edges) and 6 import cycles in my admin app.
  • Answers you can check: every edge is tagged EXTRACTED (read from the code) or INFERRED (resolved by Graphify), so you know what it read and what it worked out.
  • Make your agent use it: graphify claude install adds a hook that points Claude at the graph before it greps, and graphify hook install rebuilds the graph on every commit.

I made a short video of this on X. The map in it is the real graph.html from my runs.

Give your coding agent a map. Graphify turns your repo into one.

Give your coding agent a map. Graphify turns your repo into one.

Install it

You need Python 3.10+ and uv (or pipx):

install.sh
uv tool install graphifyy   # the PyPI name has two y's
graphify install            # registers the /graphify skill for your assistant

Then type /graphify . in Claude Code. Codex uses $graphify. Watch the package name: the README says graphifyy is the official package and other graphify* packages on PyPI aren't affiliated, and the PyPI page links back to the same repo.

Map a repo without sending code anywhere

I didn't want any of Helpdock's code going to a model, so I ran the headless CLI with two switches:

map-helpdock.sh
cd ~/helpdock
GRAPHIFY_BACKEND=none graphify extract . --code-only   # local tree-sitter parsing, no LLM
graphify cluster-only .                               # communities, GRAPH_REPORT.md and graph.html
  • --code-only indexes the code and skips docs, PDFs and images, the files that would need a model.
  • GRAPHIFY_BACKEND=none turns off every LLM backend, including the one that names communities.

Without them, docs and images go to your assistant's model or to whichever provider's API key is set (README, Privacy). On my Mac, extraction took 33 seconds and clustering 18. The summary at the top of the report:

GRAPH_REPORT.md
- 30114 nodes · 111921 edges · 512 communities (485 shown, 27 thin omitted)
- Extraction: 97% EXTRACTED · 3% INFERRED · 0% AMBIGUOUS · INFERRED: 2922 edges (avg confidence: 0.85)
- Token cost: 0 input · 0 output
I ran it on my Helpdock repo: 30,114 nodes, 111,921 edges, 512 communities

I ran it on my Helpdock repo: 30,114 nodes, 111,921 edges, 512 communities

What the report told me

The report starts with the hubs:

graphify god-nodes
God nodes (most connected):
  1. DbTransaction - 1693 edges
  2. vitest - 1081 edges
  3. useT() - 979 edges
  4. useSemanticTokens() - 664 edges
  5. Requires() - 474 edges

That's my app at a glance: the database transaction type, the test runner, the translation hook, the design tokens and the permission decorator.

It also found 6 import cycles, all in my admin app, for example providers.tsx → toasts.tsx → tokens.ts → providers.tsx. A cycle like that can leave a module half-initialized when it's first imported, so they're on my cleanup list.

The map is one HTML file

graphify-out/graph.html opens in any browser. Click a node to see its file, its number of connections and its neighbors, search for any symbol, or switch communities on and off in the legend. Two things I learned:

  • Above 5,000 nodes you get communities, not nodes. My full repo rendered as 512 community dots (rendering limits in the README). For node-level detail, map one part of the repo.
  • Include what that part imports. When I mapped only apps/widget, imports from my shared packages became nodes named after absolute paths on my machine. Mapping the widget together with packages/schemas, i18n and ui fixed it: 4,085 nodes, 6,728 edges, 145 communities.
The chat widget and its packages, mapped: click WidgetController to see its file and neighbors

The chat widget and its packages, mapped: click WidgetController to see its file and neighbors

Ask the graph

path traces how two things connect:

graphify path
$ graphify path "TicketsController" "DbTransaction"
Shortest path (3 hops):
  TicketsController --method [EXTRACTED]--> .find() --calls [INFERRED]--> .markTicketRead() --references [EXTRACTED]--> DbTransaction

That's what happens in Helpdock when a staff member opens a ticket: find() handles GET /tickets/:ticketId and marks the ticket's notifications read inside the request's database transaction. The calls edge is INFERRED because Graphify resolved that call itself. The other two are read straight from the code.

explain shows a node's neighborhood with file and line:

graphify explain
$ graphify explain "TicketsService"
Node: TicketsService
  Source:    apps/api/src/tickets/tickets.service.ts L167
  Community: tickets.service.ts
  Degree:    69

Connections (69):
  <-- tickets.module.ts [imports] [EXTRACTED] apps/api/src/tickets/tickets.module.ts:L50
  --> TicketRepository [references] [EXTRACTED] apps/api/src/tickets/tickets.service.ts:L168
  --> SlaService [references] [EXTRACTED] apps/api/src/tickets/tickets.service.ts:L183

When a name exists in two places, it lists both instead of guessing:

ambiguous name
$ graphify path "WidgetController" "DbTransaction"
Ambiguous: 'WidgetController' matches 2 nodes in different files.
  apps/api/src/widget/widget.controller.ts
  apps/widget/src/state/controller.ts
Retry with path::symbol using one of the paths above (e.g. <path>::WidgetController) or the full node id.

For scripts, the exit code tells you what happened: 0 an answer, 3 an ambiguous name, 4 no matching node.

What happens when I open a ticket: three hops from TicketsController to DbTransaction

What happens when I open a ticket: three hops from TicketsController to DbTransaction

Make your agent use it

agent-setup.sh
graphify claude install   # a graphify section in CLAUDE.md + a PreToolUse hook
graphify hook install     # rebuild the graph on commit, checkout, merge and rewrite

The Claude Code hook fires before search-style tool calls and points Claude to graphify query, path and explain instead of grepping file by file. Cursor, Codex and Gemini CLI have their own graphify <platform> install, and graphify uninstall removes it from every platform at once.

Make your agent use it: graphify claude install, graphify hook install, --code-only

Make your agent use it: graphify claude install, graphify hook install, --code-only

Privacy notes

  • Code: parsed locally with tree-sitter, with no API key. Nothing leaves your machine.
  • Docs, PDFs and images: sent to your assistant's model, or to the backend you configure, unless you pass --code-only.
  • Query log: every query, path and explain call is logged to ~/.cache/graphify-queries.log. Set GRAPHIFY_QUERY_LOG_DISABLE=1 to turn it off.
  • Telemetry: the README says there is none.

Sources

Add Oday Bakkour as a preferred source on Google

Comments

Share your thoughts and join the conversation

Leave a Comment

Loading comments...
RELATED