Built for the WeMakeDevs × FalkorDB Graph Hacks hackathon. Track: Agents That Act on Connected Data.
There are two ways to ask an AI about a codebase you never read, and both of them are wrong.
The first hands the repository to a model and lets it describe the structure. It is fast, and a dependency that is ninety percent right is worse than no dependency, because there is no way to tell which ten percent is wrong. The moment a model is allowed to guess an edge, every edge becomes a maybe.
The second draws a picture. Folders as boxes, imports as lines, a canvas you can pan. If you take the database away and the picture still answers "what imports this?", the database was decoration. Graph Hacks says that in the rules, and it should. A visualisation on top of ordinary storage does not qualify.
I wanted the picture and the answer to be the same object. A parser reads the TypeScript and JavaScript and proves each edge. FalkorDB stores those edges. The agent may only ask questions that graph can answer, through tools that run fixed queries. It does not get to write Cypher. It does not get to say two files are connected because that seems likely.
That is Graph Verse.
Repo: https://github.com/ANAMASGARD/graph-verse
Live: https://graph-verse.vercel.app/
What it actually does
You paste a public github.com/owner/name. No token. Nothing private.
Graph Verse then, on its own:
- Fetches the public tarball and records the commit.
- Parses the tree. A resolved import, re-export, dynamic
import(), orrequire()becomes an edge. An import it cannot resolve is counted, with a reason, and is never stored as a line. - Writes the result into that team's FalkorDB graph. One graph per Clerk organization. Switching team switches graph. There is no organization column to filter on.
- Draws the map from those nodes. Click a file and the detail pane is a walk of the edges already stored: what it imports, what imports it, what sits two hops out.
- Lets you ask, in a panel that shows each tool call as it happens.
- Stops the model from inventing a path. If a tool did not return a path, that path is not in the answer.
Step 6 is the whole project. Everything before it is there so the agent has a graph worth walking.
The part I care about: the edge is real
Anyone can tell a model "only use real imports" and hope. That is a convention. The model can ignore it. A later prompt can soften it. The answer still looks confident.
In Graph Verse the split is structural.
The parser does not know Next, React, or FalkorDB exist. It takes a directory and returns files, edges, and a coverage report. An edge exists only when a specifier resolved to a file that is actually in the tree. IMPORTS, RE_EXPORTS, DYNAMIC_IMPORT, and REQUIRES are the only ways two files get connected.
The agent does not see the database. It is a separate process. It is never told which analysis it is reading. A short-lived credential, minted on the server, names one organization and one analysis. The six tools call back into the app, and the app runs one fixed query each:
- summary of the repository
- search by part of a path
- list files by role
- direct neighbours
- a walk of at most two hops, in or out, including a shortest chain between two files
- the route table
The walk is Cypher, variable length, capped at two:
MATCH (a:Analysis {id: $id})-[:HAS_FILE]->(start:File {path: $path})
MATCH p = (start)-[:IMPORTS|RE_EXPORTS|DYNAMIC_IMPORT|REQUIRES*1..2]->(other)
WHERE other <> start
RETURN other.path AS path, length(p) AS depth
ORDER BY depth, path
If the question needs a third hop, the instructions say to walk again from a file the first walk returned. They do not say to guess the rest.
The browser never opens FalkorDB. If the agent process is down, the map, the blast radius, and Explain still work, because those read the same stored edges. If FalkorDB is down, none of them work. That is the test I kept using. A product that still answers with the graph removed has a picture, not a graph.
How FalkorDB fits
I want to be precise, because "we used the sponsor database" can mean a logo in the README.
FalkorDB is the context layer. My code does not walk the import graph in memory and then draw the result. The relationships are the product.
Four things it actually does:
One graph per team.
selectGraph(orgId)opens the Clerk organization's graph. Two teams on one instance do not share nodes. Tenancy is which graph you opened, not aWHEREclause.The traversals the UI and the agent share. Neighbours, blast radius, dependency chain, and the agent walk are the same four relationship types. Fan-in and fan-out are counts stored on the file. Who depends on a file is a query.
Routes as nodes, only when both ends are known. A route is a
:Routewith a method, a path, and a line, linkedHAS_ROUTEandDEFINED_IN. If the parser cannot recover both the method and the full path, it stores none. A wrong route is the same failure as an invented edge.Memory in that same graph. An explanation is written from the file and its real neighbours, then stored on an
:AiCachenode. The next request for the same explanation is a graph read. Each Ask is stored as an:Inquiryon the analysis: the question, the thread, and the paths the tools returned. The next session can show how an earlier answer was reached. That is the memory. It is not a chat log in the browser.
src/components/Layout/index.tsx in xizon/fullstack-nextjs-app-template is a file a lot of other files import. What it itself imports is this, not a sentence the model felt like writing:
MATCH (p:Project {repoOwner: 'xizon', repoName: 'fullstack-nextjs-app-template'})
-[:HAS_ANALYSIS]->(a:Analysis)
-[:HAS_FILE]->(f:File {path: 'src/components/Layout/index.tsx'})
-[r:IMPORTS|RE_EXPORTS|DYNAMIC_IMPORT|REQUIRES]->(other:File)
RETURN type(r) AS kind, other.path AS path, r.specifier AS specifier
ORDER BY path
That returns BackToTop, Footer, Header, MultilevelDropdownMenu, and src/store/actions/demoMenuActions.js. If the agent names a sixth file, it is wrong, full stop.
Proving it is not pattern-matching
One happy question proves nothing. Ask "what imports this?" on a file whose name is Header and a model will invent a reasonable list. It will look like the tool worked.
So the checks disagree with each other.
The lookup. Ask what Layout imports. The answer is allowed to contain only paths a tool returned. The five files above are the list. A sixth name, however plausible, fails. There is a separate check that does the same thing to explanations: any token that looks like a source file must have been in the set the model was shown. Score is 1 or 0. A model does not grade the model.
The refusal. Ask it to grade the code. Say whether a file is good, safe, or well written. The instructions are to decline in one sentence and say what it can answer instead: where a file is, what it imports, what imports it, what sits two hops out, which routes exist. If it writes a review, the run failed. The product explains a codebase. It does not score one. A score is how people stop reading the map.
Same agent. Same tools. Same graph. One question must come back with those five paths. The other must come back with no opinion at all.
What went wrong
Almost none of this was the model being clever. The failures were the system letting a guess look like a fact, or hiding the graph I had just stored.
Clicking a box made the map vanish. Opening a folder recenters the camera on that one node. The rest of the graph left the viewport, which feels exactly like a delete. On top of that, React Flow will draw nothing if its parent has no height, and the canvas was sizing itself from content that is positioned absolutely. The parent collapsed, the library logged that it had no width and no height, and the edges were gone. The fix was to give the canvas the space under the header, and to fit the whole graph after a folder opens, not one box.
The dashboard crashed on a team with no graph yet. Listing analyses used a read-only query. FalkorDB answers that with Invalid graph operation on empty key when that organization's graph has never been written. A session refresh then sent the browser to /dashboard instead of back to the analysis, and the error overlay replaced the map. An empty team is an empty list. It is not an exception.
The agent would not even compile. The dev server refreshes a lockfile and tries to fetch an optional WebAssembly package. npm on this machine refuses remote tarballs unless you allow them. The agent is a separate service. Until that fetch was allowed, Ask had no process to talk to, and the map was the whole product. Which is fine. Ask is allowed to be down. The map is not allowed to lie.
Progress could not use the database's pub/sub. The FalkorDB user cannot SUBSCRIBE. Analysis progress is a server-sent event on an in-process bus, after the server has checked that the analysis id is in the current organization's graph. The browser still never opens a database connection.
Every one of those would have left a demo that looked finished while the claim was soft. The happy path, a map with lines on it, works either way.
What I would tell you if you are building one of these
Put the edge in the parser, not the prompt. "Please do not invent imports" is a wish. A resolved specifier written as a relationship is a property of the system. If your graph story depends on the model cooperating, you do not have a graph.
Build the question your agent should get wrong. "What does Layout import?" is the easy one, and it can be faked. "Grade this file" is the one that shows whether the refusal is real.
The strings you return from a tool are the only nouns the model is allowed to use. A path that was not in the tool result does not get to appear because it would make a nicer sentence.
When the agent behaves strangely, suspect the instruction that was quietly wrong about the world. The two-hop cap is one of those. Past two hops it must start again from a file it already has, and say so. Letting it "just continue" is how invented files come back.
What it does not do
- It does not score, rate, or review the code.
- It does not open private repositories. Public GitHub URLs only.
- It does not parse languages other than TypeScript and JavaScript.
- A walk is two hops. Farther than that is another walk, from a file the first one returned.
- A route is stored only when both the method and the full path come back from the syntax.
- Ask needs the agent process running. With it stopped, the map, the blast radius, and Explain still answer from the stored edges.
Try it
https://graph-verse.vercel.app/
Sign in, create or pick an organization, paste a public repository, and wait for the four stages. Then ask what a file imports, and ask it to grade that file. The first answer should be a list of paths. The second should be a refusal.
The video is the same run: https://youtu.be/hz-TFz4LJ4I
Source: https://github.com/ANAMASGARD/graph-verse
The graph model, the decision that the parser proves edges and FalkorDB walks them, and the checks above are the part I had to be able to explain without them.



Top comments (0)