<?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: Esan Mohammad</title>
    <description>The latest articles on DEV Community by Esan Mohammad (@esankhan).</description>
    <link>https://dev.to/esankhan</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%2F535191%2F1258a937-0655-4b14-aa8e-1d0c48b86e10.png</url>
      <title>DEV Community: Esan Mohammad</title>
      <link>https://dev.to/esankhan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/esankhan"/>
    <language>en</language>
    <item>
      <title>I rebuilt my open-source AI coding agent that routes each pipeline stage to a different LLM</title>
      <dc:creator>Esan Mohammad</dc:creator>
      <pubDate>Tue, 05 May 2026 15:55:01 +0000</pubDate>
      <link>https://dev.to/esankhan/i-rebuilt-my-open-source-ai-coding-agent-that-routes-each-pipeline-stage-to-a-different-llm-5fph</link>
      <guid>https://dev.to/esankhan/i-rebuilt-my-open-source-ai-coding-agent-that-routes-each-pipeline-stage-to-a-different-llm-5fph</guid>
      <description>&lt;p&gt;The pattern in AI coding tools has been bugging me for a while.&lt;/p&gt;

&lt;p&gt;You sign up for one of them. You agree to a per-seat subscription. You get exactly one model: the one the vendor picked for you.&lt;/p&gt;

&lt;p&gt;Underneath, the whole thing is glued to that vendor’s SDK, so even if you wanted to swap models, you couldn’t without forking. Then the next month, a better model ships from a different vendor, and you’re stuck.&lt;/p&gt;

&lt;p&gt;That way of building locks users out of one of the most valuable properties of LLMs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;They are swappable, comparable, and increasingly cheap.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I built &lt;strong&gt;Anvil&lt;/strong&gt; — an open-source coding agent that takes a one-line feature request and ships a PR end-to-end.&lt;/p&gt;

&lt;p&gt;The thing that makes it different is &lt;strong&gt;per-stage model routing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A single pipeline run can cycle through three or four different LLMs, each picked for what it is actually good at.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pitch in one example
&lt;/h2&gt;

&lt;p&gt;Here is an actual run from yesterday:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clarify     →  Ollama qwen3:14b      (local)          ~ $0.00
plan        →  Claude Sonnet 4.6     (deep analysis)  ~ $0.05
build       →  Ollama qwen3:14b      (local)          ~ $0.00
test        →  Ollama qwen3:14b      (local)          ~ $0.00
validate    →  Claude Haiku 4.5      (cheap, fast)    ~ $0.01
review      →  Claude Sonnet 4.6     (judgment)       ~ $0.08
ship        →  Ollama qwen3:14b      (local git ops)  ~ $0.00
──────────
~ $0.14
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read that top to bottom.&lt;/p&gt;

&lt;p&gt;That is a fully reviewed, tested, PR’d feature for &lt;strong&gt;fourteen cents&lt;/strong&gt; in cloud spend.&lt;/p&gt;

&lt;p&gt;Most stages ran free on a local model. Premium models only showed up where premium models actually move the quality needle: planning the work and reviewing the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  The routing is just config
&lt;/h2&gt;

&lt;p&gt;The routing is not hardcoded. It is a YAML file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ~/.anvil/stage-policy.yaml&lt;/span&gt;
&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;clarify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;capability&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reasoning&lt;/span&gt;
    &lt;span class="na"&gt;complexity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S&lt;/span&gt;
    &lt;span class="na"&gt;prefer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;cheap&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;premium&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;capability&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reasoning&lt;/span&gt;
    &lt;span class="na"&gt;complexity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;L&lt;/span&gt;
    &lt;span class="na"&gt;prefer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;premium&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;capability&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;code&lt;/span&gt;
    &lt;span class="na"&gt;complexity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;M&lt;/span&gt;
    &lt;span class="na"&gt;prefer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;local&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;cheap&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;premium&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;review&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;capability&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reasoning&lt;/span&gt;
    &lt;span class="na"&gt;complexity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;L&lt;/span&gt;
    &lt;span class="na"&gt;prefer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;premium&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You declare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the capability each stage needs&lt;/li&gt;
&lt;li&gt;the complexity of the task&lt;/li&gt;
&lt;li&gt;the tier preference order&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The resolver walks &lt;code&gt;~/.anvil/models.yaml&lt;/code&gt; and picks the cheapest model that matches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eight providers, one pipeline
&lt;/h2&gt;

&lt;p&gt;Anvil ships with eight LLM provider adapters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude&lt;/li&gt;
&lt;li&gt;OpenAI&lt;/li&gt;
&lt;li&gt;Gemini&lt;/li&gt;
&lt;li&gt;OpenRouter&lt;/li&gt;
&lt;li&gt;OpenCode&lt;/li&gt;
&lt;li&gt;Ollama&lt;/li&gt;
&lt;li&gt;Gemini CLI&lt;/li&gt;
&lt;li&gt;Google ADK&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every adapter speaks the same streaming format, throws the same &lt;code&gt;UpstreamError&lt;/code&gt; on retryable failures, and reports cost the same way.&lt;/p&gt;

&lt;p&gt;What is deliberately not in there: &lt;strong&gt;vendor SDKs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every HTTP adapter is hand-rolled with &lt;code&gt;fetch()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;@anthropic-ai/sdk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;openai&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;No LangChain.&lt;/p&gt;

&lt;p&gt;No Vercel AI SDK.&lt;/p&gt;

&lt;p&gt;If a model is dropped tomorrow, your code keeps compiling.&lt;/p&gt;

&lt;p&gt;That is the whole point of being provider-agnostic: you cannot be agnostic if you are importing the vendor’s TypeScript types.&lt;/p&gt;

&lt;p&gt;If a model 429s mid-run, the chain-walker burns it for the rest of that run and falls through to the next entry in the same tier. Same provider or different provider — your call.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ships in v0.1.0
&lt;/h2&gt;

&lt;p&gt;I just cut MVP 2: &lt;strong&gt;v0.1.0&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is what is in the box, framed by why each piece keeps runs cheap and quality high.&lt;/p&gt;

&lt;h3&gt;
  
  
  9-stage pipeline runner
&lt;/h3&gt;

&lt;p&gt;Small, focused stages mean each agent call is short and can run on the cheapest model that is good enough.&lt;/p&gt;

&lt;p&gt;Chain fallback also means one rate-limited provider does not kill the run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hybrid retrieval
&lt;/h3&gt;

&lt;p&gt;Anvil combines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;vector search&lt;/li&gt;
&lt;li&gt;BM25&lt;/li&gt;
&lt;li&gt;project graph retrieval&lt;/li&gt;
&lt;li&gt;cross-encoder reranking&lt;/li&gt;
&lt;li&gt;AST chunking via tree-sitter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sharp context lets cheaper models do work that would otherwise need a premium model.&lt;/p&gt;

&lt;p&gt;The build stage rarely needs a frontier model because it is already looking at the right code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Long-term memory
&lt;/h3&gt;

&lt;p&gt;Anvil has long-term memory with bi-temporal validity and code-fact drift detection.&lt;/p&gt;

&lt;p&gt;Agents do not re-derive what they have already learned, and stale memories get pruned automatically.&lt;/p&gt;

&lt;p&gt;No tokens burned rediscovering a pattern you fixed last week.&lt;/p&gt;

&lt;h3&gt;
  
  
  Convention engine
&lt;/h3&gt;

&lt;p&gt;Recurring review complaints get promoted to deterministic rules.&lt;/p&gt;

&lt;p&gt;Once a mistake has been called out twice, the rule engine catches it at lint time instead of review time.&lt;/p&gt;

&lt;p&gt;That is zero LLM tokens.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plan validator
&lt;/h3&gt;

&lt;p&gt;The plan validator catches issues before any code is written, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;missing tests&lt;/li&gt;
&lt;li&gt;wrong stage routing&lt;/li&gt;
&lt;li&gt;undocumented rollback strategies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cheapest place to fix anything is the planning stage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-pass PR review
&lt;/h3&gt;

&lt;p&gt;The PR review system includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;evidence gating&lt;/li&gt;
&lt;li&gt;scope matching&lt;/li&gt;
&lt;li&gt;knowledge-base context&lt;/li&gt;
&lt;li&gt;dismissal filtering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Premium spend lands where it actually moves the quality needle.&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenTelemetry and cost ledger
&lt;/h3&gt;

&lt;p&gt;Every adapter call attaches a real &lt;code&gt;gen_ai.usage.cost&lt;/code&gt; from a vendored LiteLLM pricing table.&lt;/p&gt;

&lt;p&gt;No estimates. No surprises.&lt;/p&gt;

&lt;p&gt;Anvil is MIT-licensed, runs locally, has no hosted plan, and sends no telemetry home.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to try it
&lt;/h2&gt;

&lt;p&gt;Install the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @esankhan3/anvil-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set up a project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;anvil init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the dashboard and ship:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;anvil dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dashboard hosts both the React UI and the WebSocket backend in a single Node process.&lt;/p&gt;

&lt;p&gt;Open the browser tab and you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pipeline view&lt;/li&gt;
&lt;li&gt;run history&lt;/li&gt;
&lt;li&gt;knowledge graph&lt;/li&gt;
&lt;li&gt;memory inspector&lt;/li&gt;
&lt;li&gt;settings UI for provider keys&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have Ollama installed, you can run the cheap-tier stages fully offline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;ollama
ollama pull qwen3:14b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have an OpenCode Zen subscription, you do not even need a GPU. It can replace the entire local tier with hosted open-coding models.&lt;/p&gt;

&lt;p&gt;For the full walkthrough — prerequisites, provider keys, and troubleshooting — check the getting-started doc in the repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is intentionally not in v0.1.0
&lt;/h2&gt;

&lt;p&gt;A few things are intentionally not in this release.&lt;/p&gt;

&lt;h3&gt;
  
  
  No hosted plan
&lt;/h3&gt;

&lt;p&gt;No hosted plan. No SaaS.&lt;/p&gt;

&lt;p&gt;This is by design. Hosting is a different business, and I want to keep the project unencumbered.&lt;/p&gt;

&lt;h3&gt;
  
  
  No vendor SDKs
&lt;/h3&gt;

&lt;p&gt;Same reason as above.&lt;/p&gt;

&lt;p&gt;The goal is provider-agnostic infrastructure, not a wrapper around one vendor’s client library.&lt;/p&gt;

&lt;h3&gt;
  
  
  No durable execution yet
&lt;/h3&gt;

&lt;p&gt;Today the pipeline is “Pattern 1”: audit log plus state-file granularity, not cross-process step replay.&lt;/p&gt;

&lt;p&gt;That is the next big thing on the roadmap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory-layer vector retrieval is still in progress
&lt;/h3&gt;

&lt;p&gt;Vector retrieval is stubbed today in the memory layer. Knowledge-core retrieval is fully featured.&lt;/p&gt;

&lt;p&gt;Sleeptime population of memory embeddings is in flight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;p&gt;If you have ever felt the pull of:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I should be able to swap this model.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;only to realize SDK lock-in makes it a project-level rewrite, this might be for you.&lt;/p&gt;

&lt;p&gt;If you have watched cloud LLM costs creep into a budget that should have been local-model-cheap, this might be for you.&lt;/p&gt;

&lt;p&gt;If you maintain a multi-repo project and existing tools force you to think one repo at a time, this is definitely for you.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/esanmohammad/Anvil" rel="noopener noreferrer"&gt;https://github.com/esanmohammad/Anvil&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would love feedback, especially on the per-stage routing model.&lt;/p&gt;

&lt;p&gt;Does it match how you would want to spend tokens? What stages would you route differently?&lt;/p&gt;

&lt;p&gt;Drop a comment.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>productivity</category>
      <category>llm</category>
    </item>
    <item>
      <title>I was tired of re-explaining my project to Claude every session</title>
      <dc:creator>Esan Mohammad</dc:creator>
      <pubDate>Wed, 22 Apr 2026 13:02:00 +0000</pubDate>
      <link>https://dev.to/esankhan/i-was-tired-of-re-explaining-my-project-to-claude-every-session-5d38</link>
      <guid>https://dev.to/esankhan/i-was-tired-of-re-explaining-my-project-to-claude-every-session-5d38</guid>
      <description>&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.amazonaws.com%2Fuploads%2Farticles%2Fcmklanuf37js2boi50gv.gif" 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.amazonaws.com%2Fuploads%2Farticles%2Fcmklanuf37js2boi50gv.gif" alt="Anvil" width="760" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd start a new Claude Code session and spend the first ten minutes pasting files.&lt;/p&gt;

&lt;p&gt;"Here's the API gateway. Here's the user service. The gateway talks to users over HTTP. Users publish to this Kafka topic. The payments service consumes it. The shared types live in this package. Here's the schema."&lt;/p&gt;

&lt;p&gt;Next day. New session. Same ten minutes.&lt;/p&gt;

&lt;p&gt;Some days I'd realize halfway through that I'd already burned half my context window on orientation and hadn't gotten to the actual problem yet. That was the moment I knew this was broken.&lt;/p&gt;

&lt;p&gt;Our work project spans five repos. TypeScript, Go, Python, Kafka, shared Postgres. Real production stuff. And every AI tool I tried treated my project like a blank slate every time I opened it. The better the model, the more it noticed the gaps, the more it guessed. And when it guessed wrong, it guessed wrong confidently.&lt;/p&gt;

&lt;p&gt;I got tired of it. I spent three months of weekends building the thing I wished existed. It ended up being two things.&lt;/p&gt;

&lt;p&gt;The first thing: a pipeline with a built-in knowledge graph&lt;/p&gt;

&lt;p&gt;The core idea is stupid simple. Parse the project once. Build a compact architectural summary. Inject that summary into every agent call.&lt;/p&gt;

&lt;p&gt;I call it Anvil Pipeline. Here's what it actually does:&lt;/p&gt;

&lt;p&gt;It walks every repo in your project. Uses tree-sitter to extract functions, classes, interfaces, types, imports. Builds a graph where nodes are symbols and edges are the relationships between them. Then it looks across repos and auto-detects the connections between them — Kafka topic producers and consumers, HTTP routes and their callers, shared TypeScript interfaces, protobuf definitions, Docker Compose service links, environment variables that reference other services. Fourteen detection strategies in total.&lt;/p&gt;

&lt;p&gt;The output is a GRAPH_REPORT.md file per repo. It's designed to be low-token — a compact architectural overview, not a dump of code. That file gets injected into every agent prompt.&lt;/p&gt;

&lt;p&gt;The first time I ran it and started a Claude session, the agent just... knew. Knew which services I had. Knew Kafka was between them. Knew which types were shared. I didn't paste anything. I saved a conservative 20,000 tokens in the first session alone, probably more.&lt;/p&gt;

&lt;p&gt;That alone would have been enough. But while I was there I built the pipeline part.&lt;/p&gt;

&lt;p&gt;Anvil Pipeline takes a feature description and runs it through eight stages: clarify the intent, produce a high-level plan, break it into per-repo requirements, write technical specs, generate task lists, build the code, validate with build and test commands, ship as pull requests. Each stage writes artifacts to disk. Each stage is resumable.&lt;/p&gt;

&lt;p&gt;The resumability part matters. If you've run long agent sessions you know: Claude's auth expires. Your budget hits its limit. Your laptop goes to sleep. The dashboard crashes. Any of these kills a naive agent loop and you lose everything.&lt;/p&gt;

&lt;p&gt;Anvil checkpoints at every stage. When auth expires, the pipeline pauses, sends a browser notification, auto-opens the re-login page, and resumes from the same spot once you're authenticated. I built this part after losing a 40-minute run to a five-second auth check. The kind of thing where you walk away to grab water and come back to nothing.&lt;/p&gt;

&lt;p&gt;The second thing: a plug-and-play MCP server&lt;/p&gt;

&lt;p&gt;The other half of my frustration was smaller but more constant. AI tools making up function names. Imports that don't exist. Helpers I never wrote.&lt;/p&gt;

&lt;p&gt;The fix here is also stupid simple: give the model actual tools to look up the code, instead of asking it to recall from training.&lt;/p&gt;

&lt;p&gt;Code Search MCP is a standalone MCP server. Any MCP client picks it up — Claude Code, Claude Desktop, Cursor, whatever you're using next month. One line to install in Claude Code:&lt;/p&gt;

&lt;p&gt;That's it. Claude now has eleven new tools, including the ones I actually use:&lt;/p&gt;

&lt;p&gt;search_code for hybrid search — vector plus BM25 plus graph expansion plus cross-encoder reranking&lt;br&gt;
find_callers — everywhere a function is called across all your repos&lt;br&gt;
find_dependencies — what a function depends on&lt;br&gt;
impact_analysis — what breaks if you change this file&lt;br&gt;
impact_analysis has turned out to be the one I use most. I did not expect that. Before, I'd ask Claude "what breaks if I remove this" and get a plausible-sounding guess. Now I get a real answer, because the tool walks the graph.&lt;/p&gt;

&lt;p&gt;The part I spent the most time on is incremental indexing. Codebases change constantly. Re-embedding the whole thing on every commit is expensive and slow. So I built four layers of skip logic:&lt;/p&gt;

&lt;p&gt;Git SHA at the repo level. If the repo's HEAD hasn't moved, skip entirely.&lt;br&gt;
Git diff at the file level. Only files that changed.&lt;br&gt;
SHA-256 at the content level. Files that changed but ended up with the same content get skipped too.&lt;br&gt;
Embedding diff at the chunk level. Only new chunks are embedded. Existing embeddings in LanceDB are preserved.&lt;br&gt;
A typical "I changed 2 files" reindex embeds about 5 new chunks instead of redoing the whole repo.&lt;/p&gt;

&lt;p&gt;Embeddings are provider-agnostic. Ollama is the default, which means it runs free and local out of the box. If you want better quality you can plug in Voyage, Mistral/Codestral, OpenAI, Gemini, or any OpenAI-compatible endpoint. I did not want to force anyone into a specific cloud.&lt;/p&gt;

&lt;p&gt;Why both live in the same repo&lt;/p&gt;

&lt;p&gt;I almost split them. They target different users. Pipeline is for teams doing feature work across repos. Code Search MCP is for any developer using any AI assistant. Different install stories, different mental models.&lt;/p&gt;

&lt;p&gt;But they share the hard parts. The tree-sitter parsing, the cross-repo edge detection, the embedding pipeline. Splitting them meant maintaining two copies of all that.&lt;/p&gt;

&lt;p&gt;So they ship together, under the Anvil umbrella. Use either. Use both. Use neither — the code is MIT, so rip out the parts you want.&lt;/p&gt;

&lt;p&gt;What I care about, technically&lt;/p&gt;

&lt;p&gt;Everything runs on your machine. Dashboard, pipeline, knowledge graph, indexing — all local.&lt;/p&gt;

&lt;p&gt;No telemetry. No analytics. No crash reporters. No phone-home. I checked twice.&lt;/p&gt;

&lt;p&gt;No account system. Nothing to sign up for.&lt;/p&gt;

&lt;p&gt;Your code only goes to the LLM provider you explicitly select. Anvil never proxies or stores it.&lt;/p&gt;

&lt;p&gt;MIT licensed. Every line auditable.&lt;/p&gt;

&lt;p&gt;I wanted AI tooling that didn't compromise on any of this. There is a lot of AI dev tooling out there now, but most of it sends your code through someone's SaaS. I didn't want that for my own work, and I figured other people might not want it either.&lt;/p&gt;

&lt;p&gt;What's still weak&lt;/p&gt;

&lt;p&gt;The 8-stage pipeline is opinionated. It works for how I work. If your workflow doesn't fit "describe, plan, code, ship" it'll feel stiff.&lt;/p&gt;

&lt;p&gt;The cross-repo detection strategies cover my stack. GraphQL federation, event sourcing, and some message queue patterns aren't handled yet. I'm collecting edge cases.&lt;/p&gt;

&lt;p&gt;The dashboard isn't pretty. I spent the time on correctness.&lt;/p&gt;

&lt;p&gt;If you try it&lt;/p&gt;

&lt;p&gt;The repo is at &lt;a href="https://github.com/esanmohammad/Anvil" rel="noopener noreferrer"&gt;https://github.com/esanmohammad/Anvil&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code Search MCP is one line to install. Pipeline takes a config file — anvil init walks you through it.&lt;/p&gt;

&lt;p&gt;I'd love to hear what breaks. Especially the cross-repo detection, and which of the 11 MCP tools you actually use in practice. I suspect two or three should be cut and I don't know which ones yet.&lt;/p&gt;

&lt;p&gt;This is my first time shipping a side project in public. Feedback welcome, roasts too.&lt;/p&gt;

&lt;p&gt;If you found any of this useful, the repo is on GitHub and I'd love a star — it helps other people find it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
