<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>GraphSlice Blog</title>
    <link>https://graphslice.com/blog/</link>
    <atom:link href="https://graphslice.com/blog/feed.xml" rel="self" type="application/rss+xml" />
    <description>Notes on semantic code graphs, C# code intelligence, and feeding LLMs the context they actually need.</description>
    <language>en</language>
    <lastBuildDate>Thu, 02 Jul 2026 09:00:00 GMT</lastBuildDate>
    <item>
      <title>Why your AI assistant should query your architecture, not your files</title>
      <link>https://graphslice.com/blog/why-ai-assistants-should-query-architecture/</link>
      <guid isPermaLink="true">https://graphslice.com/blog/why-ai-assistants-should-query-architecture/</guid>
      <pubDate>Thu, 02 Jul 2026 09:00:00 GMT</pubDate>
      <description>File dumps and vector search break down on large C# codebases. A semantic code graph gives an LLM the exact dependency paths a question needs — nothing more.</description>
      <content:encoded><![CDATA[<p>Every AI coding assistant faces the same bottleneck: it can only reason about
what fits in its context window. On a small project that&#39;s a non-issue — paste
the repo, ask the question. On a real C# monorepo with thousands of types, it
becomes <em>the</em> issue.</p>
<h2 id="the-two-default-strategies-and-why-they-fail">The two default strategies, and why they fail</h2>
<h3 id="strategy-one-dump-the-files">Strategy one: dump the files</h3>
<p>The brute-force approach is to hand the model whole files — the one you&#39;re
editing, plus whatever looks related. It fails in both directions at once:</p>
<ul>
<li><strong>Too much:</strong> most of every file is irrelevant to the question, so you pay
for tokens that add noise, not signal.</li>
<li><strong>Too little:</strong> the behavior you&#39;re asking about usually lives <em>between</em>
files — an interface here, three implementations there, a decorator
registered in a DI container nobody remembers.</li>
</ul>
<h3 id="strategy-two-vector-search">Strategy two: vector search</h3>
<p>Embeddings retrieve text that <em>looks like</em> the question. But code similarity
is not code relevance. The method that breaks when you change an interface
doesn&#39;t share vocabulary with the interface — it shares a <strong>compile-time
relationship</strong> with it. No embedding captures that reliably, and the index
drifts out of date the moment the code changes.</p>
<h2 id="what-the-compiler-already-knows">What the compiler already knows</h2>
<p>Here&#39;s the thing: a complete, precise map of your codebase already exists.
The C# compiler builds it on every compilation — every symbol, every type,
every call edge, every dependency. It just throws the map away when it&#39;s done
emitting IL.</p>
<p>GraphSlice keeps that map. It compiles your solution with the same semantic
model the compiler uses and materializes the result as a <strong>semantic code
graph</strong>: nodes for solutions, projects, types, and methods; edges for calls,
inheritance, references, and package dependencies.</p>
<h2 id="slices-not-searches">Slices, not searches</h2>
<p>A graph you can&#39;t fit in a context window is no better than a repo you can&#39;t
fit in a context window. The unit of delivery matters. GraphSlice serves
<strong>slices</strong> — the minimal subgraph that answers one question:</p>
<pre><code class="language-text">&gt; what breaks if I change IPaymentProcessor?

IPaymentProcessor (interface, Billing.Core)
├── implemented by StripeProcessor       (Billing.Stripe)
├── implemented by InvoiceProcessor      (Billing.Invoicing)
├── injected into CheckoutService..ctor  (Web.Checkout)
└── mocked in PaymentProcessorTests      (Billing.Tests)
</code></pre>
<p>That&#39;s the whole answer. Four dependency paths, a few hundred tokens — instead
of forty files and a prayer.</p>
<h2 id="why-mcp-is-the-right-delivery-channel">Why MCP is the right delivery channel</h2>
<p>Slices are served over the <a href="https://modelcontextprotocol.io">Model Context Protocol</a>,
which means any MCP-compatible assistant can request them as tools:</p>
<ul>
<li>The model asks a <strong>structural question</strong> (&quot;who calls this?&quot;, &quot;trace this
dependency&quot;) instead of a text query.</li>
<li>The graph does the reasoning about <em>structure</em>, so the model can spend its
reasoning budget on <em>intent</em>.</li>
<li>Your repository is never uploaded or indexed by a third party — the graph
runs where your code runs.</li>
</ul>
<h2 id="the-payoff">The payoff</h2>
<p>Correct context, not just nearby context. Smaller windows, flatter costs as
the repo grows, and answers grounded in how the software actually fits
together. Your AI assistant stops being a very confident text search and
starts being an engineer with the blueprints in hand.</p>
]]></content:encoded>
    </item>
    <item>
      <title>What is a context slice?</title>
      <link>https://graphslice.com/blog/what-is-a-context-slice/</link>
      <guid isPermaLink="true">https://graphslice.com/blog/what-is-a-context-slice/</guid>
      <pubDate>Thu, 25 Jun 2026 09:00:00 GMT</pubDate>
      <description>A context slice is the minimal subgraph of your codebase that answers one question. Here's how GraphSlice extracts one, and why the boundaries matter.</description>
      <content:encoded><![CDATA[<p>&quot;Context slice&quot; is the core noun in GraphSlice, so it deserves a precise
definition: a slice is the <strong>minimal connected subgraph</strong> of your semantic
code graph that is sufficient to answer one question.</p>
<h2 id="anatomy-of-a-slice">Anatomy of a slice</h2>
<p>Every slice has three parts:</p>
<h3 id="the-anchor">The anchor</h3>
<p>The symbol the question is about — a method, a type, an interface, a project.
Anchors are resolved by real symbol identity, not by name matching, so
<code>Process</code> on <code>OrderService</code> never gets confused with <code>Process</code> on
<code>ImagePipeline</code>.</p>
<h3 id="the-traversal">The traversal</h3>
<p>From the anchor, GraphSlice walks the edges that the question type calls for:</p>
<table>
<thead>
<tr>
<th>Question</th>
<th>Edges walked</th>
</tr>
</thead>
<tbody><tr>
<td>&quot;Who calls this?&quot;</td>
<td>incoming call edges</td>
</tr>
<tr>
<td>&quot;What breaks if I change this?&quot;</td>
<td>implementations, overrides, references</td>
</tr>
<tr>
<td>&quot;Trace this dependency&quot;</td>
<td>project + package dependency edges</td>
</tr>
<tr>
<td>&quot;Show the flow&quot;</td>
<td>call edges, direction of execution</td>
</tr>
</tbody></table>
<p>The traversal is bounded — by depth, by project boundary, or by relevance —
so a hub symbol with ten thousand references doesn&#39;t flood the window.</p>
<h3 id="the-rendering">The rendering</h3>
<p>The subgraph is rendered in a form an LLM consumes efficiently: compact,
hierarchical, deduplicated, with file-and-line anchors so the assistant can
jump from structure to source when it needs the actual code.</p>
<h2 id="what-a-slice-deliberately-leaves-out">What a slice deliberately leaves out</h2>
<p>The discipline is in the omissions. A slice does <strong>not</strong> include:</p>
<ul>
<li>Method bodies that aren&#39;t on the dependency path.</li>
<li>Symbols that merely live in the same file as something relevant.</li>
<li>Anything retrieved because it was <em>textually similar</em> to the question.</li>
</ul>
<p>Proximity in a file is an accident of formatting. Proximity in the graph is a
fact about your software.</p>
<h2 id="why-minimal-is-a-feature">Why &quot;minimal&quot; is a feature</h2>
<p>It&#39;s tempting to pad context &quot;just in case&quot; — but every irrelevant symbol in
the window is a chance for the model to anchor on the wrong thing. Precision
in, precision out. Keeping slices minimal is what keeps token costs flat as
the repository grows: the graph gets bigger, but the answers don&#39;t.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
