<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jignesh Dabhi</title>
    <description>The latest articles on DEV Community by Jignesh Dabhi (@zephyr2e1).</description>
    <link>https://dev.to/zephyr2e1</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4192648%2Fe6126160-dfe5-4d16-bacb-552500115172.png</url>
      <title>DEV Community: Jignesh Dabhi</title>
      <link>https://dev.to/zephyr2e1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zephyr2e1"/>
    <language>en</language>
    <item>
      <title>We loaded FalkorDB's GitHub into FalkorDB: Now it explains itself</title>
      <dc:creator>Jignesh Dabhi</dc:creator>
      <pubDate>Sun, 18 Oct 2026 18:34:19 +0000</pubDate>
      <link>https://dev.to/zephyr2e1/we-loaded-falkordbs-github-into-falkordb-now-it-explains-itself-5f13</link>
      <guid>https://dev.to/zephyr2e1/we-loaded-falkordbs-github-into-falkordb-now-it-explains-itself-5f13</guid>
      <description>&lt;p&gt;We chose the dataset where a wrong answer would get caught fastest: a year of FalkorDB's own GitHub history, loaded into FalkorDB. Ask Aevion "Who knows the falkordb-py client code best?" and it names five people, starting with gkorland, who authored 5 merged PRs in that code and reviewed 4. Under the answer is the graph walk behind every name, 20 nodes and 27 edges, from each person to the pull requests that earned their score and the files those PRs changed. Click a person, PR or issue and it opens on GitHub. The Cypher tab shows the read-only query that ran.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5485c1hpva845sdjp0og.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5485c1hpva845sdjp0og.gif" alt="Asking Aevion " width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We built Aevion for Graph Hacks and had it in production about 23 hours after our first commit. No answer leaves our API without its path. It's live at &lt;a href="https://aevion-alpha.vercel.app" rel="noopener noreferrer"&gt;aevion-alpha.vercel.app&lt;/a&gt;, no login needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The graph
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpvvk7sxvjunwomuc73sn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpvvk7sxvjunwomuc73sn.png" alt="Aevion's graph model: Person, PullRequest, Issue, Comment, File, Component, Repo, Decision, Release, Label, Team, CachedAnswer and TriageRun nodes and the relationships between them, with the expertise path Person to PullRequest to File to Component highlighted" width="799" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nine repositories, the last 12 months: 20,961 nodes and 80,642 edges, including 3,544 pull requests, 2,326 issues and 8,607 comments. Most of the 13 labels map straight onto GitHub (a Person &lt;code&gt;REVIEWED&lt;/code&gt; a PullRequest, which &lt;code&gt;FIXES&lt;/code&gt; an Issue). Two that we added carry most of this post. A Component is a directory prefix in a repo, such as &lt;code&gt;src/udf&lt;/code&gt; in FalkorDB core, and every File sits &lt;code&gt;IN_COMPONENT&lt;/code&gt; one. A Decision is a choice someone made in a PR or issue thread, linked to where it was made, who made it and the comments that show it. We extracted 534 of them.&lt;/p&gt;

&lt;p&gt;Every record loads with &lt;code&gt;UNWIND … MERGE&lt;/code&gt; on its key. A full ingest of the nine repos takes about 10 minutes, and running it a second time added 0 nodes and 0 edges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who knows the falkordb-py client code best?
&lt;/h2&gt;

&lt;p&gt;The agent never writes Cypher. It picks from six fixed tools: &lt;code&gt;experts_for&lt;/code&gt;, &lt;code&gt;decision_trail&lt;/code&gt;, &lt;code&gt;triage_candidates&lt;/code&gt;, &lt;code&gt;area_history&lt;/code&gt;, &lt;code&gt;related_work&lt;/code&gt; and &lt;code&gt;catch_up&lt;/code&gt;. Here it used &lt;code&gt;experts_for&lt;/code&gt; on &lt;code&gt;falkordb&lt;/code&gt;, the package folder that is falkordb-py's only Component.&lt;/p&gt;

&lt;p&gt;From the Component, the scoring query walks three hops: Component ← File ← PullRequest ← Person. Each merged PR that touched the code gives its author 3.0 points and each reviewer 2.0. A comment on such a PR is worth 0.5, scored by a second query on &lt;code&gt;(:Person)-[:AUTHORED]-&amp;gt;(:Comment)-[:ON]-&amp;gt;(pr)&lt;/code&gt;. Every contribution is multiplied by &lt;code&gt;exp(-age/260 days)&lt;/code&gt;, so a PR from about six months ago counts half. Bots and unmerged PRs never score. Here is the authored-and-reviewed half:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;c:&lt;/span&gt;&lt;span class="n"&gt;Component&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:IN_COMPONENT&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;f:&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:MODIFIES&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;pr:&lt;/span&gt;&lt;span class="n"&gt;PullRequest&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;c.key&lt;/span&gt; &lt;span class="ow"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;$components&lt;/span&gt; &lt;span class="ow"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;pr.merged_at&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="ow"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;p:&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="py"&gt;r:&lt;/span&gt;&lt;span class="n"&gt;AUTHORED&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;REVIEWED&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="ow"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;p.is_bot&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f.key&lt;/span&gt;&lt;span class="ss"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c.key&lt;/span&gt;&lt;span class="ss"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt;
     &lt;span class="nf"&gt;exp&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;((&lt;/span&gt;&lt;span class="nf"&gt;timestamp&lt;/span&gt;&lt;span class="ss"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pr.merged_at&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt; &lt;span class="err"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;86400000.0&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt; &lt;span class="err"&gt;/&lt;/span&gt; &lt;span class="n"&gt;$decay&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;recency&lt;/span&gt;
&lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;p.login&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pr.key&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pr.title&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pr.url&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pr.merged_at&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'AUTHORED'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="n"&gt;$authored&lt;/span&gt; &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="n"&gt;$reviewed&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;recency&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;points&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FalkorDB's &lt;code&gt;timestamp()&lt;/code&gt; and &lt;code&gt;exp()&lt;/code&gt; compute the decay inside the traversal, fresh on every ask. In design we considered precomputed &lt;code&gt;EXPERT_IN&lt;/code&gt; edges and a PageRank job and dropped both: a stored score needs a job to keep it current, and it can't tell you which PRs earned it. Python only sums the points per person and keeps each person's three strongest PRs as evidence.&lt;/p&gt;

&lt;p&gt;In the Path tab, two of the nine PRs behind gkorland's score read like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gkorland
├─ AUTHORED → falkordb-py#247  "chore(release): prepare v1.6.2"
│  └─ MODIFIES → falkordb/falkordb.py → IN_COMPONENT → falkordb
└─ REVIEWED → falkordb-py#236  "Fix async unix-socket connection crashing in Is_Cluster (#235)"
   └─ MODIFIES → falkordb/asyncio/cluster.py → IN_COMPONENT → falkordb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After gkorland come Naseem77, who fixed the execution plan parser and kwargs forwarding in &lt;code&gt;Is_Cluster&lt;/code&gt; (#267), and swilly22, who wrote the UDF command propagation change. Then SantoshDhaladhuli, who fixed the async connection pool's kwargs mutation (#276), and AviAvni, a reviewer on the async connection fixes. The answer ends with a caveat we liked: the client code is spread across &lt;code&gt;falkordb/falkordb.py&lt;/code&gt;, &lt;code&gt;falkordb/cluster.py&lt;/code&gt; and &lt;code&gt;falkordb/asyncio/cluster.py&lt;/code&gt;, "so the sync and async paths may have different experts."&lt;/p&gt;

&lt;p&gt;That answer is cached as a node in the same graph, with a &lt;code&gt;CITES&lt;/code&gt; edge to every node it cites, so the server returns it in 2 ms.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Why did FalkorDB gate main on a merge queue?"
&lt;/h2&gt;

&lt;p&gt;This one goes to &lt;code&gt;decision_trail&lt;/code&gt;, which starts with FalkorDB's full-text index over &lt;code&gt;Decision(summary, rationale)&lt;/code&gt;. The index stems words, so "queues" matches "queue" without a synonym list.&lt;/p&gt;

&lt;p&gt;We expected the merge-queue decision itself to rank first, but TF-IDF put another one above it. It ranked "Every CI job sets an explicit timeout-minutes, and merge queue entries are not cancelled" above "Gate main with a merge queue (merge_group) and run fork PR CI through it…". The shorter summary packed the query words into fewer terms, and TF-IDF rewards that. FalkorDB still does the finding and returns a pool of 50. Python re-ranks that pool by keyword coverage, the share of the question's keywords a Decision contains, and breaks ties with full-text score times extraction confidence. Over 534 Decisions that takes 8 to 20 ms.&lt;/p&gt;

&lt;p&gt;From the winning Decision, one query walks the trail:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DECIDED_IN&lt;/code&gt; to FalkorDB/FalkorDB#2718, "ci: make PR CI fork-safe and gate main on a merge queue".&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FIXES&lt;/code&gt; from that PR to FalkorDB/FalkorDB#2632, where CI couldn't run for external contributors because fork PRs get a read-only &lt;code&gt;GITHUB_TOKEN&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MADE_BY&lt;/code&gt; to DvirDukhan, on 2026-09-17.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AFFECTS&lt;/code&gt; to the Components it changed, &lt;code&gt;.github/workflows&lt;/code&gt; among them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A second query follows &lt;code&gt;EVIDENCED_BY&lt;/code&gt; to the two review comments on #2718 that the Decision rests on.&lt;/p&gt;

&lt;p&gt;The rest of the answer comes from the Decision's &lt;code&gt;rationale&lt;/code&gt; and &lt;code&gt;alternatives&lt;/code&gt; properties. The alternative on the table was &lt;code&gt;pull_request_target&lt;/code&gt; behind an approval label, which would hand a writable token to fork-authored code. A merge queue run gets a writable token natively. The path has 17 nodes and 19 edges.&lt;/p&gt;

&lt;p&gt;The Decisions themselves come from an extraction pass over 1,177 candidate threads. A language model proposes them, and code checks each one against the graph: a person stays only if they took part in the thread, a Component only if the thread's PRs touched it, and evidence only if it's a real comment from that thread. Anything under 0.5 confidence is dropped.&lt;/p&gt;

&lt;h2&gt;
  
  
  "A new issue just came in. Where does it go?"
&lt;/h2&gt;

&lt;p&gt;Take FalkorDB/FalkorDB#3357: "GRAPH.UDF LOAD REPLACE is not atomic: concurrent queries fail with Unknown function". A new issue has no edges yet, so triage reasons by analogy, along &lt;code&gt;Issue ← FIXES – PullRequest – MODIFIES → File – IN_COMPONENT → Component&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc2ohn1x56bbxeufxdm3c.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc2ohn1x56bbxeufxdm3c.gif" alt="Triaging FalkorDB/FalkorDB#3357 on the live app: hovering the issue lights the walk on the graph model, the result lists three similar issues and the src/udf Component, and clicking swilly22 on the map opens the pull requests they authored there" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full-text search on the title, re-ranked by coverage as above, finds three closed issues: #1529 "UDF getNeighbors incoming edges aren't returned", #2075 "Avoid QuickJS context creation when there are no UDF libraries" and #1265 "Implement UDF", fixed by #1530, #2076 and #1266. Those PRs changed files such as &lt;code&gt;node_class.c&lt;/code&gt; and &lt;code&gt;udf_ctx.c&lt;/code&gt;, and each file belongs to a Component. A PR that touched n Components gives each of them a vote scaled by 1/√n, so a focused fix counts for more per area than a sweeping refactor. Tests, CI, docs and packaging folders never vote; we added packaging to that list after &lt;code&gt;docker&lt;/code&gt; and &lt;code&gt;helm&lt;/code&gt; folders kept outvoting falkordb-py's real code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/udf&lt;/code&gt; wins, marked "moderate" because its votes cleared the 0.4 bar but not the 1.0 bar for "strong". &lt;code&gt;experts_for&lt;/code&gt; on &lt;code&gt;src/udf&lt;/code&gt; returns swilly22, with 8 merged PRs authored and 2 reviewed there. The whole triage uses 54 nodes and 49 edges.&lt;/p&gt;

&lt;p&gt;The hop from issue to fixing PR is where our deploy went wrong. We had written it as one long &lt;code&gt;MATCH&lt;/code&gt;, and FalkorDB planned it from a scan of every File node. On a laptop that took 0.8 s, under the 1 s default timeout, so we didn't notice. On Railway, a little after midnight on the night we deployed, it timed out. One &lt;code&gt;WITH&lt;/code&gt; after the indexed &lt;code&gt;Issue.key&lt;/code&gt; hop made the plan start from the index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="k"&gt;UNWIND&lt;/span&gt; &lt;span class="n"&gt;$issues&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;issue_key&lt;/span&gt;
&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;i:&lt;/span&gt;&lt;span class="n"&gt;Issue&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;issue_key&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:FIXES&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;pr:&lt;/span&gt;&lt;span class="n"&gt;PullRequest&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;issue_key&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;
&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:MODIFIES&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;f:&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:IN_COMPONENT&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;c:&lt;/span&gt;&lt;span class="n"&gt;Component&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="ow"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;f.is_doc&lt;/span&gt;
&lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;issue_key&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;issue&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pr.key&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f.key&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c.key&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c.name&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same rows, 5 ms. Our query notes now say: run &lt;code&gt;GRAPH.EXPLAIN&lt;/code&gt; and look for &lt;code&gt;Node By Label Scan&lt;/code&gt; on big labels.&lt;/p&gt;

&lt;h3&gt;
  
  
  The agent that acts
&lt;/h3&gt;

&lt;p&gt;On FalkorDB's repos, triage is only a preview: it suggests the label &lt;code&gt;area: src/udf&lt;/code&gt;, links swilly22's profile and drafts a reply, but posts nothing. On our &lt;a href="https://github.com/hineshmiyani/aevion-sandbox" rel="noopener noreferrer"&gt;sandbox repo&lt;/a&gt; it does all three.&lt;/p&gt;

&lt;p&gt;When someone opens a sandbox issue, a signed webhook reaches the API. The issue is loaded into its own graph, &lt;code&gt;org:aevion-sandbox&lt;/code&gt;, and triaged against &lt;code&gt;org:falkordb&lt;/code&gt;. FalkorDB keeps many named graphs on one server, so the two stay apart while one process queries both. Sandbox issue #34 reports a server crash when a UDF library is replaced mid-query. The label and reply came 11 s after it was opened, and the reply led with FalkorDB/FalkorDB#3357:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs70367cp6o1vpnh7ph7v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs70367cp6o1vpnh7ph7v.png" alt="Sandbox issue #34 on GitHub: a synthetic report that replacing a UDF library during queries crashes the server, the area: src/udf label added by Aevion, and its reply pointing to FalkorDB/FalkorDB#3357, the src/udf code and swilly22" width="800" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The agent can write, so we locked it down in code, with tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two locks on where it writes: a repo allow-list in the code and a GitHub token scoped to the sandbox repo only. A bug in one still can't touch FalkorDB's repos.&lt;/li&gt;
&lt;li&gt;It never notifies anyone at FalkorDB. Experts appear as profile links, not @-mentions, and FalkorDB issues are written as code spans so they don't collect "mentioned this issue" events.&lt;/li&gt;
&lt;li&gt;A final scan of the reply blocks the post if anything could still notify someone.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MERGE (t:TriageRun {issue_key: $key})&lt;/code&gt; records each run, so the same issue is never answered twice, and only &lt;code&gt;issues.opened&lt;/code&gt; starts a triage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every tool query also runs through &lt;code&gt;GRAPH.RO_QUERY&lt;/code&gt;, so FalkorDB itself rejects a write from the read path.&lt;/p&gt;

&lt;h2&gt;
  
  
  What FalkorDB did for us
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyy88wrt0tlbr82ff7yz8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyy88wrt0tlbr82ff7yz8.png" alt="Architecture: visitors reach the Next.js app on Vercel, which calls a FastAPI service on Railway; FastAPI reads FalkorDB on Railway's private network and calls the LLM; GitHub sandbox webhooks come into FastAPI, and labels and comments go back to the sandbox only; an MCP server exposes the same tools; ingest and extraction write to FalkorDB" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FalkorDB and our FastAPI service run on Railway, with FalkorDB reachable only on the private network. The web app is on Vercel. The six tools are shared by the HTTP API, the agent (at most four tool calls per answer) and an MCP server, so any MCP client can query the same graph.&lt;/p&gt;

&lt;p&gt;The matched nodes and edges are the evidence we draw, and our tests check that every drawn edge exists in the graph. Full-text search lives in the same engine, so a question can start as a word search and carry on as a walk. On the full graph, locally, &lt;code&gt;experts_for&lt;/code&gt; runs in 88 ms, &lt;code&gt;decision_trail&lt;/code&gt; in 14 ms and &lt;code&gt;triage_candidates&lt;/code&gt; in 75 ms.&lt;/p&gt;

&lt;p&gt;We didn't re-ingest for production. We moved each graph with Redis &lt;code&gt;DUMP&lt;/code&gt;/&lt;code&gt;RESTORE&lt;/code&gt; over a temporary TCP proxy in about 9 s, indexes, Decisions and cached answers included, and both sides counted 20,961 nodes and 80,642 edges. The one gotcha we'd pass on: &lt;code&gt;GRAPH.RO_QUERY&lt;/code&gt; on a graph that doesn't exist yet fails with "Invalid graph operation on empty key", so we create every graph at startup.&lt;/p&gt;

&lt;p&gt;Next we want polling to keep the FalkorDB graph fresh (webhooks only cover our sandbox), and a second organisation in its own named graph.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aevion-alpha.vercel.app" rel="noopener noreferrer"&gt;The app&lt;/a&gt;, no login. Start with &lt;a href="https://aevion-alpha.vercel.app/?q=Who+knows+the+falkordb-py+client+code+best%3F" rel="noopener noreferrer"&gt;who knows the falkordb-py client code&lt;/a&gt; and open the Path and Cypher tabs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aevion-alpha.vercel.app/triage" rel="noopener noreferrer"&gt;Triage&lt;/a&gt;, including #3357.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/hineshmiyani/aevion" rel="noopener noreferrer"&gt;The code&lt;/a&gt;, with every query and the reasoning behind it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The quickest test is the &lt;a href="https://github.com/hineshmiyani/aevion-sandbox" rel="noopener noreferrer"&gt;sandbox&lt;/a&gt;: open an issue there and count to ten.&lt;/p&gt;

</description>
      <category>falkordb</category>
      <category>ai</category>
      <category>database</category>
      <category>hackathon</category>
    </item>
  </channel>
</rss>
