Knowledge Graphs for AI Agents Β· From RAG Limits to Self-Updating Codebase Brains
Track 2 β€” Structural Graphs

M04 Β· Graphify in Practice

πŸ“ Module 5 of 14 ⏱ ~60 minutes 🎯 Level: Intermediate πŸ“‹ Prerequisites: M03 (tree-sitter)

Learning objectives Intermediate

  • Install Graphify and build a graph of a real repository with one command β€” and know which pass costs tokens (only docs/PDFs/images) and which is free (all code).
  • Read all three output artifacts β€” graph.json, graph.html, GRAPH_REPORT.md β€” and explain what each is for.
  • Use community detection and god-node identification to see a codebase's real subsystems and refactoring risks.
  • Query the graph from the CLI (graphify path, graphify query) and load graph.json programmatically.
  • Interpret Graphify's benchmark claims honestly: what the 71.5Γ— headline actually measured, what independent replications found (6.8×–49Γ—, 7.3Γ— from scratch), and where the ~500-file payoff floor comes from.

In M03 you built a toy extractor. This module hands you the production version of the same idea β€” then teaches you to evaluate its claims the way an engineer should. Both halves matter: Graphify is genuinely useful, and the numbers on its posters need footnotes. By the end you'll know how to run it and exactly how much to believe.

What Graphify is

Graphify is an open-source tool (built by Safi Shamsi, released under a permissive open-source license, a Y Combinator S26 project) that converts any folder β€” code, docs, PDFs, SQL schemas, configs, images, even video β€” into a queryable knowledge graph. It ships on PyPI as the package graphifyy (two y's; the CLI command is graphify) and installs a /graphify slash-command skill into 17 AI coding assistants, including Claude Code, Cursor, Codex, Gemini CLI, and Aider.

Its core design decision, straight from M03: code is parsed structurally, not semantically. Tree-sitter builds the AST across 36 language grammars (Python, TypeScript, Go, Rust, Java, C/C++, Swift, SQL, Terraform/HCL, and more) β€” no LLM, no API key, no token cost for the code portion, entirely local. Only docs, papers, and images go through an LLM β€” which means only that pass can hallucinate. On a pure-code repository, the entire run is free.

Before: Andrej Karpathy described the problem as the "/raw folder": a place where papers, tweets, screenshots, notes, and code accumulate β€” easy to drop things into, nearly impossible to query later. Everyone has this folder. Some people's is called "the repo."

The pain: 90 days into a project the folder is write-only memory. Finding whether a design decision exists means re-reading everything, and your AI assistant has the same problem at token prices.

The mapping: Graphify is the answer to that folder β€” the timeline is literally that direct. Karpathy posted the "LLM Wiki / knowledge compiler" thought experiment on April 1, 2026; Graphify launched on GitHub on April 3, 48 hours later; by June 1 it had 58,300 stars and 1.2 million PyPI downloads. One command turns the pile into a graph with every relationship labeled as found-or-guessed, and your assistant navigates the map instead of re-reading the pile.

Every extracted relationship carries the provenance tag you met in M03 β€” EXTRACTED (parsed directly from the AST, 100% confidence) or INFERRED (derived via heuristic, lower confidence, with a confidence score). One reviewer who ran it end-to-end on a real 36-file infrastructure repository called this "the whole argument: it is the only one of these tools that tells you which of its answers are facts and which are guesses."

Install and first run

Three install routes, all landing in the same place. The uv route is recommended β€” it works on Mac and Linux with no PATH setup, and on Windows with a current uv:

shell Β· install
# Recommended
uv tool install graphifyy && graphify install

# or with pipx
pipx install graphifyy && graphify install

# or plain pip
pip install graphifyy && graphify install

graphify install is the step people forget: it registers the /graphify skill with the assistants on your machine, so Claude Code (or Cursor, Codex, Gemini CLI…) can invoke the graph natively. Then, from your project root:

shell Β· build the graph
cd your-project
graphify update .
# or, inside your AI assistant:
/graphify .

A successful run logs like this β€” read it closely, because three of these lines encode design decisions you now understand:

log output
Re-extracting code files in . (no LLM needed)...
[graphify watch] Rebuilt: 70 nodes, 89 edges, 15 communities
[graphify watch] graph.json, graph.html and GRAPH_REPORT.md updated in graphify-out
Code graph updated. For doc/paper/image changes run /graphify --update in your AI assistant.
Tip: set MOONSHOT_API_KEY to use Kimi K2.6 for semantic extraction β€” 3x cheaper, richer graphs.
  • "no LLM needed" β€” the code pass is the deterministic, free, zero-hallucination pass from M03.
  • "For doc/paper/image changes run /graphify --update" β€” the semantic pass is separate, optional, and the only part that costs tokens (and the only part that can hallucinate).
  • "15 communities" β€” clustering ran automatically; we'll read those below, and the count is higher than the three services you might expect.

Two housekeeping facts: a .graphifyignore file excludes junk directories (it politely ignores .git and node_modules by default), and on very large codebases graph.html is skipped β€” the log tells you when. The cache/ directory means re-runs only touch changed files.

The three artifacts

Every run writes three files into graphify-out/. They are three views of the same graph for three different consumers β€” and the fact that there are three separate files becomes a production concern in M11 (they can desync; remember this).

ArtifactConsumerWhat it is
graph.htmlHumansAn interactive, self-contained clickable graph you open in a browser β€” communities colored, nodes searchable.
GRAPH_REPORT.mdHumans and agentsA plain-language audit: subsystems, god nodes, oddities. The "compact structural summary" an assistant reads instead of raw files.
graph.jsonMachinesThe raw, queryable graph β€” GraphRAG-ready. This is what MCP servers load (M09) and what your own scripts read. It persists: weeks later, still works.
Animation Β· PIPELINE_FLOW β€” one folder in, three artifacts out
your-project/code Β· docs Β· imgs tree-sitter passcode Β· $0 Β· deterministic LLM pass (optional)docs/imgs Β· tokens Β· can err graph.jsonmachines Β· MCP Β· scripts graph.htmlhumans Β· interactive GRAPH_REPORT.mdplain-language audit

Static description: a project folder feeds two passes β€” a deterministic $0 tree-sitter pass for code, and an optional token-costing LLM pass for docs/images. Both flow into three artifacts: graph.json (for machines), graph.html (interactive, for humans), GRAPH_REPORT.md (plain-language audit for humans and agents).

One folder in; two passes with very different cost models; three views of one graph out.
Artifacts on disk are potential energy. The kinetic form is a query β€” and Graphify gives you three ways to ask.

Querying the graph

The CLI has two workhorse queries. path answers "how are these two things connected?" and query takes a natural-language question against the graph index:

shell Β· queries
# Dependency path between two components
graphify path "UserService" "DatabasePool"

# Architectural blast radius before a refactor
graphify query "What components depend on AuthTokenValidator?"

Inside an assistant, /graphify . plus a question does the same thing conversationally β€” the assistant fetches relevant nodes and edges and reasons over those, not over raw files. And for always-on integration, the graph can be served over MCPModel Context Protocol β€” the open standard that lets AI assistants call external tools. M09 builds a graph-serving MCP server from scratch. so the assistant fetches nodes on the fly:

shell Β· serve over MCP
python -m graphify.serve graphify-out/graph.json

Which of the three routes to use is a serving-architecture question β€” the entire subject of M09. For now: CLI for you, slash-command for conversations, MCP for agents that need to query mid-task.

βœ… Why It Matters β€” the use cases people actually pay for

Onboarding: hand a new dev the graph instead of a 40-page README nobody reads. Impact analysis: "if I delete this 'deprecated' method, will the payment gateway explode?" β€” the graph shows the 14 hidden dependencies that say yes. Security audits: trace exactly how an unauthenticated request flows through the system. Architecture discovery: find out which parts of your "microservices" are actually a secret monolith in a trench coat.

Walk it, step by step

Below is the whole pipeline on the orderflow sample project β€” install, extract, inspect the artifacts, then ask it a question. Watch the node and edge counts appear, and note how few of the edges are EXTRACTED rather than INFERRED.

Communities and god nodes: the graph reads your architecture

Recall from M01: a community is a cluster of nodes more densely connected to each other than to the rest of the graph, and in code graphs communities β‰ˆ natural subsystems. Graphify runs Leiden community detectionA graph-clustering algorithm (successor to Louvain) that partitions nodes to maximize modularity β€” the degree to which clusters are internally dense and externally sparse. M01 introduced it. automatically on every build. On orderflow it does not hand you three tidy services: Graphify reports 15 communities named after files (app.py, db.py, worker.py, webhooks.py, orders.py, invoice.py) plus one per document. The billing / orders / notifications split the architecture doc claims is recoverable from those clusters β€” but you read it out, you are not handed it. At 18 files there is too little call density for the clustering to coarsen further.

It also flags god nodes β€” the high-centrality files that many communities depend on. On orderflow that is shared/db.py β€” but for a narrower reason than it first appears. Billing and orders depend on it (notifications never persists, so it is not universal), and its claim to the title is blast radius: seven functions transitively depend on it, more than any other shared module. It does not win on betweenness β€” it scores 0.00, because nothing routes through a sink that calls nothing back. A god node isn't automatically bad, but it is automatically risky: any change to it has the widest blast radius in the repo, and (M01 foreshadowed this) computing centrality exactly is O(VΓ—E) work β€” which becomes M11's scale-wall story on 450K-node graphs.

Animation Β· COMMUNITY_MAP β€” orderflow clusters itself
app invoice webhooks orders metrics worker shared/db.py shared/events.py 3 service clusters Β· widest blast radius: shared/db.py Β· three-way bridge: shared/events.py

Static description: orderflow's nodes settle into three colored clusters β€” billing (app, invoice, webhooks), orders (orders, metrics), notifications (worker) β€” around two shared hubs. shared/db.py pulses gold: billing and orders both depend on it, giving it the widest blast radius in the repo (seven transitive dependents) β€” though not the highest betweenness, which it does not have. shared/events.py is the only node touching all three clusters: billing and orders publish, notifications subscribes.

Press play: Leiden clustering colors the subsystems; the god node pulses.
⚠️ Common Misconceptions

"Communities are the folder structure." β€” No; they're computed from edges. When they disagree with your folders, the edges are telling you where the architecture actually lives β€” that disagreement is the insight, not an error.

"A god node means bad code." β€” It means concentrated risk. shared/db.py is a reasonable design at orderflow's size; the flag says "changes here have maximum blast radius," not "rewrite this."

"Clustering always finds the right subsystems." β€” In legacy monoliths, Leiden often clusters unrelated modules together just because they share infrastructure utilities (logging, telemetry singletons). Community noise is a known failure mode β€” treat clusters as hypotheses to check, not verdicts.

The honest benchmarks

Now the part most write-ups skip. Graphify's marketing number is famous: up to 71.5Γ— reduction in query tokens. That number is real β€” and almost useless as a planning input. Here is the full picture, every number sourced, vendor claims labeled as such.

Where 71.5Γ— came from

The headline (vendor) figure comes from a single favorable benchmark: a 52-file corpus β€” Karpathy's public repositories, 5 research papers, and 4 diagrams β€” where a naive assistant burned roughly 123,000 tokens answering an architecture question that the graph answered in about 1,700 tokens. That's a ceiling case: a favorable query, on a favorable corpus, measured once.

Independent replications tell the useful story. Across task types and repo sizes, the honest range came out to 6.8Γ— on code-review tasks up to 49Γ— on daily coding in 500+ file repositories. A from-scratch benchmark on a real, non-cherry-picked Python codebase landed at 7.3Γ—. Still genuinely good β€” a different conversation than "70Γ—." As engineering writer Andrus put it during the July 2026 scrutiny wave: "Whether you get anything close to the 70x savings comes down to a single property of your project that almost none of these posts bother to state out loud." That property is corpus topology β€” flat-package enterprise codebases and 50,000-file monorepos do not behave like a curated 52-file demo set.

Animation Β· BENCHMARK_BARS β€” the claim vs. the replications
71.5Γ—vendor Β· 52 files 49Γ—repl. Β· daily, 500+ files 7.3Γ—repl. Β· from-scratch py 6.8Γ—repl. Β· code review Plan around the purple bars, not the red one. The variable is corpus topology.

Static description: four bars β€” 71.5Γ— (vendor, 52-file corpus, tallest, red), 49Γ— (replicated, daily coding on 500+ file repos), 7.3Γ— (replicated from-scratch on a real Python codebase), 6.8Γ— (replicated, code review). Caption: plan around the replicated bars; the variable is corpus topology.

Four measurements of "the same" tool. The difference is what was measured.

The benchmark that contradicts the hype β€” and reframes the tool

Open Graphify's own BENCHMARKS.md and you find numbers the launch posts skip. On LongMemEval-S (n=50), graph-expand retrieval scores 76% QA accuracy with 0.844 recall@10. Dense vector RAG β€” same model (Kimi K2.6), same BGE-m3 embedder, identical token budgets β€” scores 76% accuracy with 0.848 recall@10. A tie on accuracy; a slight loss on recall. And this is Graphify's own vendor-reported, blind-validated dataset (90.6% grading agreement, Cohen's kappa 0.81), not a hostile third party.

On LOCOMO (n=300) the interesting metric shifts to cost: Graphify scores 45.3% accuracy at roughly $1.40 to ingest the dataset; Supermemory scores higher β€” 49.7% β€” but costs $15.67 to ingest, roughly 11Γ— more.

Put together, the honest reframe: Graphify does not out-retrieve a well-tuned vector RAG pipeline. It matches RAG on accuracy while costing a fraction to build, and its two real advantages are exactly the M03 story β€” ingest cost efficiency (AST parsing needs zero LLM calls) and zero-hallucination structural extraction. If you evaluated it as a RAG replacement, you evaluated the wrong axis. One more caveat belongs in your notes: no external benchmark comparing Graphify's graph queries against a raw-file or RAG baseline on a common test set has been independently reproduced β€” treat all vendor figures as directional.

πŸ’° The ~500-file floor

Graph construction and maintenance overhead only pays for itself above roughly 500 files. Below that, you're paying tooling tax for savings that don't exist yet β€” orderflow (15 files) is deliberately below the floor so the lab can teach you to measure rather than assume. If your repo is small, the honest recommendation from this course is: don't bother yet, and know why.

Limitations

  • Noise on messy code: point it at a 5,000-line GodController and the graph looks like a ball of yarn after a cat attack. The graph reflects the code; it cannot untangle what the code tangled.
  • Dynamic-language guessing: in JavaScript and friends, where "types are merely suggestions," edges lean on INFERRED heuristics (M03's ladder). The tags are your audit trail.
  • Large-graph latency: at 500,000 nodes, querying can take a second β€” and rebuild-time centrality math gets far worse than that (the full scale-wall numbers, including a 96-core rebuild killed at 114 minutes, are in M11).
  • Static snapshot: the graph does not update itself as developers commit. Without hooks wired in β€” and working β€” it silently drifts. This single sentence is the seed of the entire production track; M11 grows it into a checklist.
  • Semantic pass hallucination: relationships extracted from docs, PDFs, and images go through an LLM and inherit its error rate. Only the code pass is deterministic.
You've read the artifacts and the caveats. Last step: touch the machine layer yourself β€” because in M09 you'll build a server on top of it, and you should know exactly what's inside.

Code walkthrough: reading graph.json programmatically

The lab's extractor writes the same shape Graphify does: a nodes array and an edges array. Let's load it and compute the top-degree nodes β€” a two-minute god-node detector. Tabs for both languages.

Chunk 1 β€” load defensively. What: read the JSON, fail with a message a human can act on. Why: "graph.json missing" usually means the extractor never ran β€” the fix is a command, and your error should say so. Gotcha: don't catch bare Exception here; a JSON parse error and a missing file deserve different messages.

degree.py Β· chunk 1
import json, sys
from collections import Counter
from pathlib import Path

path = Path("graphify-out/graph.json")
try:
    graph = json.loads(path.read_text(encoding="utf-8"))
except FileNotFoundError:
    sys.exit(f"{path} not found β€” run 'graphify update .' (or kg_extract.py) first")
except json.JSONDecodeError as exc:
    sys.exit(f"{path} is corrupt: {exc} β€” rebuild the graph")

Chunk 2 β€” count degrees. What: one Counter, incremented from both ends of every edge. Why: degree (edge count per node) is the cheapest centrality proxy β€” O(E) instead of betweenness's O(VΓ—E) β€” and on small graphs it finds the same god node.

degree.py Β· chunk 2
degree = Counter()
for edge in graph["edges"]:
    degree[edge["source"]] += 1
    degree[edge["target"]] += 1

print("top nodes by degree:")
for node_id, deg in degree.most_common(5):
    print(f"  {deg:3d}  {node_id}")

# On orderflow: handle_payment_webhook (6), then the shared.auth
# pair (4 each). Degree finds busy nodes; it is not the whole
# story β€” rank by blast radius and shared/db.py wins instead,
# and by betweenness (not computed here) it scores zero.

Chunk 1 β€” load defensively. Same contract: missing file and corrupt JSON get different, actionable messages.

degree.mjs Β· chunk 1
import { readFileSync } from "node:fs";

const path = "graphify-out/graph.json";
let graph;
try {
  graph = JSON.parse(readFileSync(path, "utf8"));
} catch (err) {
  const hint = err.code === "ENOENT"
    ? "run 'graphify update .' (or kg_extract.py) first"
    : `corrupt JSON: ${err.message} β€” rebuild the graph`;
  console.error(`${path}: ${hint}`);
  process.exit(1);
}

Chunk 2 β€” count degrees. A Map instead of a Counter; the logic is identical.

degree.mjs Β· chunk 2
const degree = new Map();
const bump = (id) => degree.set(id, (degree.get(id) ?? 0) + 1);
for (const edge of graph.edges) { bump(edge.source); bump(edge.target); }

const top = [...degree.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5);
console.log("top nodes by degree:");
for (const [id, deg] of top) console.log(`  ${String(deg).padStart(3)}  ${id}`);
πŸ”Ž What Just Happened?

You treated graph.json as what it is: a plain data file you can build tooling on. Degree counting found the same god node the report names, using O(E) arithmetic instead of O(VΓ—E) centrality β€” a tradeoff you'll see matter enormously at scale in M11. Every downstream system in this course (the M08 enrichment hook, the M09 MCP server, the M11 freshness gate) starts exactly like this: load, index, answer.

Hands-on lab

πŸ“‚ Get the files: labs/M04-graphify-end-to-end on GitHub β€” or clone the whole course once: git clone https://github.com/varasrinivas/knowledge-graph-course.git

Run labs/M04-graphify-end-to-end/ now. The four steps:

  1. Build β€” graphify update . on orderflow; match the expected log shape (nodes/edges/communities, "no LLM needed").
  2. Read all three artifacts β€” find the service clusters among the file communities in graph.html, and read the God Nodes list in the report; check GRAPH_REPORT.md names the same ones; peek at graph.json.
  3. Query β€” graphify path "post_invoice" "decode_jwt" and a dependency query on DatabasePool; verify both against the ground-truth edge list in sample-project/README.md. On a 15-file repo you can check the graph by hand β€” that's the whole point of the repo.
  4. The honest measurement β€” ask your assistant a structural question with and without the graph, record real token counts, and keep the number: expect a small multiple, not 71.5Γ—, because orderflow is far below the ~500-file floor. You will reuse this measurement in the capstone.

No install available? Every step has an offline path via labs/shared_tools/kg_extract.py.

Knowledge check

1. Which part of a Graphify run costs LLM tokens?

The tree-sitter code pass
Only the optional semantic pass over docs, papers, and images β€” the code pass is deterministic and free
Every pass β€” building any graph requires LLM extraction
Only community detection

2. An agent needs to query the graph mid-task, programmatically. Which artifact does it consume?

graph.html
GRAPH_REPORT.md
graph.json β€” the machine-readable graph that MCP servers load and scripts parse
The cache/ directory

3. What did Graphify's own LongMemEval-S benchmark show against dense vector RAG?

Graphify beat RAG decisively on both accuracy and recall
A tie on QA accuracy (76% vs 76%) and a slight loss on recall@10 (0.844 vs 0.848) β€” its real edge is ingest cost and zero-hallucination structure, not retrieval superiority
RAG failed to complete the benchmark
The benchmark only measured token counts, not accuracy

4. Your repo has 80 files. What does this module's evidence suggest about adopting Graphify today?

Adopt immediately β€” savings scale down linearly
Probably skip for now: below the ~500-file floor, graph construction and maintenance overhead exceeds savings that don't exist yet β€” measure before adopting
Adopt only the graph.html artifact
Graphify refuses to run on repos under 500 files

5. The 71.5Γ— token-reduction figure was measured on…

A single favorable run: a 52-file corpus (Karpathy's repos, 5 papers, 4 diagrams), one architecture question β€” ~123K tokens naive vs ~1.7K with the graph. Replications land at 6.8×–49Γ—, and 7.3Γ— on a from-scratch real codebase
The median of hundreds of enterprise codebases
VS Code's 10,000-file monorepo
A synthetic corpus with no real code

6. Leiden clustering on a legacy Java monolith groups the payment module with the logging utilities. Most likely explanation?

The payment code secretly implements logging
Community-detection noise: in legacy monoliths, modules cluster around shared infrastructure singletons (logging, telemetry) they all reference β€” treat clusters as hypotheses, not verdicts
The graph is hallucinated by the LLM pass
Leiden cannot run on Java code

Module summary

One command, one graph

uv tool install graphifyy && graphify install, then /graphify . β€” code parsed free and deterministically; only docs/images cost tokens.

Three artifacts, three consumers

graph.json (machines), graph.html (humans), GRAPH_REPORT.md (both). They can desync β€” a production concern M11 owns.

Architecture, rediscovered

Leiden communities β‰ˆ subsystems; god nodes = concentrated blast radius. Both are hypotheses to verify, especially in legacy monoliths.

Honest numbers

71.5Γ— is a ceiling case. Plan around 6.8×–49Γ— (7.3Γ— from-scratch), remember the ~500-file floor, and note the accuracy tie with vector RAG β€” the product is determinism + ingest cost.

What we built on orderflow: a complete graph build with all three artifacts, hand-verified against the repo's ground-truth edge list, plus a six-line god-node detector over graph.json.

Next module preview: Graphify is one point in a fast-moving design space. M05 maps the rest β€” CodeGraph's SQLite-and-watchers architecture (with the best benchmark table in the field), okf-rs's Markdown-bundle bet, and the cloud tools β€” and gives you the comparison axes to evaluate any tool that launches next month.

References

  • Graphify β€” GitHub repository, BENCHMARKS.md, and docs (graphify.net)
  • PyPI: graphifyy Β· install docs for uv/pipx/pip Β· /graphify skill registration
  • Level Up Coding (Andrus) β€” scrutiny of the 70Γ— token-reduction claims; corpus-topology dependence
  • LongMemEval-S and LOCOMO benchmark figures β€” Graphify vendor-reported, blind-validated
  • Course lab: labs/M04-graphify-end-to-end/ Β· offline fallback: labs/shared_tools/kg_extract.py