M04 Β· Graphify in Practice
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 loadgraph.jsonprogrammatically. - 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:
# Recommended
uv tool install graphifyy && graphify install
# or with pipx
pipx install graphifyy && graphify install
# or plain pip
pip install graphifyy && graphify installgraphify 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:
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:
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).
| Artifact | Consumer | What it is |
|---|---|---|
graph.html | Humans | An interactive, self-contained clickable graph you open in a browser β communities colored, nodes searchable. |
GRAPH_REPORT.md | Humans and agents | A plain-language audit: subsystems, god nodes, oddities. The "compact structural summary" an assistant reads instead of raw files. |
graph.json | Machines | The raw, queryable graph β GraphRAG-ready. This is what MCP servers load (M09) and what your own scripts read. It persists: weeks later, still works. |
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).
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:
# 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:
python -m graphify.serve graphify-out/graph.jsonWhich 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.
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.
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.
"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.
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.
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.
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
GodControllerand 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.
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.
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 = 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.
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.
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}`);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:
- Build β
graphify update .on orderflow; match the expected log shape (nodes/edges/communities, "no LLM needed"). - Read all three artifacts β find the service clusters among the file communities in
graph.html, and read the God Nodes list in the report; checkGRAPH_REPORT.mdnames the same ones; peek atgraph.json. - Query β
graphify path "post_invoice" "decode_jwt"and a dependency query onDatabasePool; verify both against the ground-truth edge list insample-project/README.md. On a 15-file repo you can check the graph by hand β that's the whole point of the repo. - 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?
2. An agent needs to query the graph mid-task, programmatically. Which artifact does it consume?
graph.htmlGRAPH_REPORT.mdgraph.json β the machine-readable graph that MCP servers load and scripts parsecache/ directory3. What did Graphify's own LongMemEval-S benchmark show against dense vector RAG?
4. Your repo has 80 files. What does this module's evidence suggest about adopting Graphify today?
5. The 71.5Γ token-reduction figure was measured onβ¦
6. Leiden clustering on a legacy Java monolith groups the payment module with the logging utilities. Most likely explanation?
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 Β·/graphifyskill 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