<?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: Ishaan Mavinkurve</title>
    <description>The latest articles on DEV Community by Ishaan Mavinkurve (@idiotcoffee).</description>
    <link>https://dev.to/idiotcoffee</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3935689%2F05dbf0c1-43f1-40d3-a146-030a0662e429.png</url>
      <title>DEV Community: Ishaan Mavinkurve</title>
      <link>https://dev.to/idiotcoffee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/idiotcoffee"/>
    <language>en</language>
    <item>
      <title>Building KernelMind, A Code-Aware Github Companion</title>
      <dc:creator>Ishaan Mavinkurve</dc:creator>
      <pubDate>Sun, 17 May 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/idiotcoffee/building-kernelmind-a-code-aware-github-companion-i3k</link>
      <guid>https://dev.to/idiotcoffee/building-kernelmind-a-code-aware-github-companion-i3k</guid>
      <description>&lt;p&gt;I have always wanted to contribute to Open Source Projects on Github. If you check out my Profile, you will see that I have even tried to get into it. But, once I went past the documentation changes and minor fixes, I realized that OSS Contributions were &lt;strong&gt;HARD&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, I decided to code a RAG project that would help me out. Of course, I could just use the inbuilt coding agents in the IDE, but where's the fun in that? &lt;br&gt;
The original version of KernelMind was pretty basic.&lt;br&gt;
I just wanted a way to ask questions about large repositories without manually opening forty files and mentally reconstructing execution flow.&lt;/p&gt;

&lt;p&gt;At the time, the plan looked straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Repository -&amp;gt; AST Parsing -&amp;gt; Chunk Extraction -&amp;gt; Embeddings -&amp;gt; Vector Search -&amp;gt; Answer Generation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was it.No fancy business. Just embeddings over code. But it broke immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The First Hurdles&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The first step was parsing. I made a basic AST parser and ran it against a deliberately small repository, storing my chunks in MongoDB for now. I wanted something predictable so debugging would be easier. I decided to use &lt;code&gt;full-stack-fastapi-template&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The indexing pipeline finished and printed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inserted 1258 chunks.
Checked 57 files.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That made absolutely no sense. There was no way a small repository like that should explode into that many chunks. So I started tracing the parser output manually.&lt;/p&gt;

&lt;p&gt;The first issue was trivial. I was ingesting... everything. Tests, initializers, EVERYTHING. This was a small fix ... I added a simple IGNORE_LIST that would skip the garbage files and only download the relevant python files. &lt;/p&gt;

&lt;p&gt;The second issue was slightly more confusing: Turns out methods inside classes were being extracted twice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; once correctly as methods&lt;/li&gt;
&lt;li&gt;once incorrectly as standalone functions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This meant that no chunk in my system had a concept of unique identity.&lt;/p&gt;

&lt;p&gt;Everything was just “chunks.” &lt;em&gt;And chunks had repetitive content...&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Another related problem:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Originally, the parser stored function names like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is technically valid. It is also practically useless.&lt;/p&gt;

&lt;p&gt;There could be dozens of &lt;code&gt;__init__&lt;/code&gt; methods across the repository.&lt;/p&gt;

&lt;p&gt;So I introduced this (totally cool and non ChatGPT researched) concept - &lt;strong&gt;Fully Qualified Names.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the system generated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;matplotlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Figure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single architectural change completely shifted the project. FQNs were now the atomic elements in the data - an FQN would be completely unique across the entire repo. Now, while parsing, I had to only construct the FQN once - if I found out that another function had the same FQN, then - it was already parsed, so ignore it.&lt;/p&gt;

&lt;p&gt;Now that symbols had stable identities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;imports could resolve properly&lt;/li&gt;
&lt;li&gt;dependencies became traceable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The repository stopped behaving like disconnected text.&lt;/p&gt;

&lt;p&gt;It started behaving like a connected system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The “self” Problem
&lt;/h2&gt;

&lt;p&gt;One of the &lt;strong&gt;MOST CONFUSING&lt;/strong&gt; bugs came from method calls.&lt;/p&gt;

&lt;p&gt;Initially, method relationships looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self.get_host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which looks reasonable at first glance ... except &lt;code&gt;self&lt;/code&gt; means nothing globally.&lt;/p&gt;

&lt;p&gt;A graph cannot reason over:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;self.get_host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;because it has no stable reference. So I had to build resolution logic that converted local method calls into globally addressable symbols.&lt;/p&gt;

&lt;p&gt;Eventually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src.requests.cookies.MockRequest.get_host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;started appearing in the graph output. That was a huge leap for me - my system was no longer parsing syntax alone. It was starting to reconstruct semantic relationships.&lt;/p&gt;

&lt;p&gt;Once FQNs entered the system, something clicked for me almost immediately.&lt;/p&gt;

&lt;p&gt;I realized I was no longer dealing with isolated chunks of text. Every function now had identity, relationships, callers, callees, imports, and dependencies. The repository was starting to look far less like a document collection and much more like a &lt;em&gt;graph data structure&lt;/em&gt; describing &lt;em&gt;execution flow.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Building The Graph&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;And once I saw the repository that way, a lot of the later architecture decisions suddenly started making sense.&lt;/p&gt;

&lt;p&gt;The next obvious question became:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If functions are connected, could I retrieve them together?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question basically led to the entire graph architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Constructing Relationships
&lt;/h2&gt;

&lt;p&gt;The first step was building explicit call relationships. Whenever the parser encountered a function call, I attempted to resolve it into an FQN and create a directed edge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;caller -&amp;gt; callee
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So if:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;login_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;called:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the graph stored that relationship directly.&lt;/p&gt;

&lt;p&gt;Initially, the graph nodes were fairly simple. Each node stored:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- the FQN
- file path
- source code
- outgoing calls
- incoming calls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Something roughly like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GraphNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;calls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;called_by&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first, this mainly helped with debugging. Then I realized the graph could fundamentally improve retrieval itself. Because codebases are not isolated files. They are execution systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Forward And Reverse Traversal&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Once the graph structure stabilized, I realized traversal needed to work in both directions. Forward traversal helped answer questions like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;“What does this function eventually call?”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which was useful for reconstructing execution flow and understanding downstream behavior. Reverse traversal was equally important because it answered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; “Who depends on this logic?”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That became extremely useful for tracing middleware usage, validation chains, service dependencies, and understanding how deeply certain functionality was integrated into the repository.&lt;/p&gt;

&lt;p&gt;I decided to implement naive BFS - semantic search (implemented later) would reveal the start node most similar to the query, and then BFS would reveal other function calls (and other "chunks") that were related to that node.&lt;/p&gt;

&lt;p&gt;Together, forward and reverse traversal made the graph feel much less like static metadata and much more like a navigable execution map of the repository.&lt;/p&gt;

&lt;p&gt;Once I switched traversal to BFS, retrieval immediately started feeling more coherent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query-Aware Expansion
&lt;/h2&gt;

&lt;p&gt;The next problem was the &lt;em&gt;naive&lt;/em&gt; BFS implementation. Naive graph expansion retrieves way too much context. If you blindly expand neighbors inside a large repository, the graph explodes into noise very quickly. Especially around highly connected framework code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;So graph expansion had to become query-aware.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Instead of expanding everything equally, the system started looking at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- symbol overlap
- semantic similarity
- auth-related terminology
- file roles
- query keywords
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;before deciding what to expand.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query = authentication
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;should prioritize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;token middleware&lt;/li&gt;
&lt;li&gt;JWT validation&lt;/li&gt;
&lt;li&gt;auth decorators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generic request logging&lt;/li&gt;
&lt;li&gt;unrelated utilities&lt;/li&gt;
&lt;li&gt;serialization helpers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I managed to code this in, the graph was no longer purely structural. It was becoming semantic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Utility Node Problem
&lt;/h2&gt;

&lt;p&gt;Another issue appeared during expansion. Highly connected utility functions started dominating retrieval.&lt;/p&gt;

&lt;p&gt;Things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;log_info&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;handle_error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;serialize_response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;showed up everywhere. The graph accidentally rewarded centrality. Which sounds mathematically elegant until your retrieval system starts implying logging is the answer to everything, simply because that function appeared 1000 times...&lt;/p&gt;

&lt;p&gt;So I introduced penalties for high-degree nodes. Highly connected utility-heavy functions received lower expansion priority. This was similar to how  TF-IDF matrix works, except over function calls.&lt;/p&gt;

&lt;p&gt;That cleanup improved retrieval quality far more than I expected ... because now the graph stopped constantly expanding into irrelevant framework plumbing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Semantic Graph Expansion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This was where the architecture started becoming much more interesting. Originally, graph relationships were purely structural:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A calls B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eventually, I started combining: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;graph relationships with semantic similarity&lt;/li&gt;
&lt;li&gt;symbol relevance&lt;/li&gt;
&lt;li&gt;query intent so the traversal could prioritize execution paths actually related to the user’s question instead of blindly expanding every connected node.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This made a huge difference for repository reasoning&lt;br&gt;
Queries about authentication naturally began surfacing middleware chains, token validation logic, and request lifecycle flows instead of drifting into unrelated utility code and framework plumbing.&lt;/p&gt;

&lt;p&gt;The traversal pipeline slowly evolved into something closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;initial_retrieval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;expanded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bfs_expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;query_aware&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;semantic_weighting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, my retrieval architecture started feeling execution-aware.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Biggest Realization
&lt;/h2&gt;

&lt;p&gt;This entire phase fundamentally changed how I thought about retrieval systems. Originally, I assumed retrieval quality depended mostly on embeddings.&lt;/p&gt;

&lt;p&gt;Eventually I realized:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Retrieval quality depends heavily on structure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The graph was improving retrieval not because the model became smarter, but because the context became more coherent. The system stopped retrieving isolated functions. It started retrieving workflows.&lt;/p&gt;

&lt;p&gt;And finally, once the graph structure stabilized:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- symbol identity existed
- traversal worked
- execution flow became traceable
- relationships became meaningful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All this time, I was working with MongoDB, and storing the "chunks" in a collection. This was excellent for debugging, but now that my repository structure had stabilized, and I was confident enough in my Graph architecture,  I was ready to move into embeddings and retrieval ranking properly.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Part 2 is coming up soon! Until then, you can check out my code &lt;a href="https://github.com/IdiotCoffee/kernel-mind" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rag</category>
      <category>programming</category>
      <category>learning</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
