Watch an AI agent answer "what calls this function?" and you'll see it run grep. Then grep again with a different pattern. Then open five files. Then grep once more. Every line of output lands in its context window, which is both slow and expensive.
Halfway through ParkEase, the questions that mattered most weren't "where does this string appear?" They were relational: which commands open a database transaction, what writes to the outbox, which API folder imports which domain. So I gave the agent a map.
What graphify does
Graphify builds a knowledge graph of the codebase by parsing it with tree-sitter: actual syntax trees, not text matching. On ParkEase it produced 4,011 nodes and 10,775 edges across 643 code files and the SQL migrations.
Two properties made it trustworthy enough to rely on:
- No embeddings, no vector store. Every edge is a real parse result, tagged as either found directly in the source or inferred by analysis. A wrong answer can be traced to a specific edge, not to a fuzzy similarity score.
- Deterministic and local. The same code gives the same graph, built on my machine.
Questions it answers in one call
graphify explain "withTransaction()" # one symbol and every edge into it graphify path "CreateBookingCommand" "OutboxService" graphify query "how does booking reach the ledger?" explain turned out to be a rules tool. ParkEase has two rules about transactions: one transaction per write, and never call an external service inside one. Listing every command that uses the transaction helper checks both, across the whole domain layer, in one query instead of fifteen greps.
The boundaries that kept it honest
It maps code, not rules. The graph knows what calls what. It has no idea what you're allowed to do. The decision records and rules are still read directly, every time. A graph that answered "is this allowed?" would be answering from the code, which is exactly the thing being checked.
Cost stays at zero. The code graph is built purely from syntax, locally and for free. Graphify can also run an AI pass over documents, and that's the step that bills. It stays off: no API keys are set for it, and the graph is built code-only.
Secrets never enter it. The graph is several megabytes of plaintext on disk. An ignore file keeps environment files, keys and keystores out, and the graph output itself is never committed.
Install it isolated. The first install went into the shared Python user packages and broke three unrelated tools by shadowing their dependencies. It now lives in its own virtual environment. That mistake is, naturally, in the learnings file.
Two false alarms worth knowing
Tree-sitter couldn't parse one valid TypeScript pattern (a tagged template with generic arguments), so two test files report "syntax errors, no symbols". The code is fine. And free-text queries pick start nodes by substring, so the word "connect" drags in an unrelated .connect(). Name a symbol when you want precision.
Was it worth it?
For an AI agent working in a large codebase, yes. The best context is the context you don't have to load, and one structured answer beats a page of grep output.
Next: two posts on the libraries that carried the front ends, starting with TanStack Query: offline mode, retries and a cache, configured rather than built.
ParkEase is a peer-to-peer parking marketplace for India, built solo with Claude Code.
Code: https://github.com/Deonkar/parkease