<?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: Rishi Makwana</title>
    <description>The latest articles on DEV Community by Rishi Makwana (@rishi_makwana).</description>
    <link>https://dev.to/rishi_makwana</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%2F4202065%2F70ae526b-2dd2-4204-a6db-91be61b56f5a.png</url>
      <title>DEV Community: Rishi Makwana</title>
      <link>https://dev.to/rishi_makwana</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rishi_makwana"/>
    <language>en</language>
    <item>
      <title>The real cost of "just add RAG"</title>
      <dc:creator>Rishi Makwana</dc:creator>
      <pubDate>Fri, 23 Oct 2026 08:56:51 +0000</pubDate>
      <link>https://dev.to/rishi_makwana/the-real-cost-of-just-add-rag-12j4</link>
      <guid>https://dev.to/rishi_makwana/the-real-cost-of-just-add-rag-12j4</guid>
      <description>&lt;p&gt;A data scientist in meeting with architects, engineers and product managers says "we'll just add RAG," and everyone settles and agrees. The model will read our docs and answer questions. It sounds like a feature you could ship by the next sprint.&lt;/p&gt;

&lt;p&gt;While this is achievable for next meetings demo, the final product takes a lot longer. My view: RAG is cheap to demo and expensive to own, and nearly all of the cost sits in the parts the demo skips.&lt;/p&gt;

&lt;h2&gt;
  
  
  The demo and the product
&lt;/h2&gt;

&lt;p&gt;A RAG demo takes a day because the hard parts are optional. You split some documents into chunks, embed them, put them in a vector store, then paste the top few matches into a prompt. You might go ahead and ask it five questions you already know the answers to, it gets four right, and everyone is impressed and started applauding. &lt;br&gt;
In reality, a reliable version takes a more than a quarter because it has to work on questions you didn't pick, over documents you didn't clean, for users who aren't allowed to see everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the cost hides
&lt;/h2&gt;

&lt;p&gt;The first cost is keeping content fresh. Loading documents once is a script, while keeping them up to date is a system. Pages get edited, PDFs get replaced, whole wiki spaces get archived, and each change has to reach the index or the assistant keeps quoting last year's policy. Someone has to own that pipeline and notice when it stops without an error.&lt;/p&gt;

&lt;p&gt;Permissions come next, and they're the cost most likely to end up in an incident review. Your source systems know who can read which document. A chunk in a vector store knows nothing unless you copy the access rules onto it and filter on them for every query. Get that wrong and the assistant will happily summarise the salary spreadsheet for whoever asks. The demo indexed everything under one account, so the question never came up.&lt;/p&gt;

&lt;p&gt;Then there are stale and contradicting documents. Plenty of companies have two or three versions of the travel policy, and retrieval has no idea which one is current. It ranks by similarity, so the old draft that happens to use the user's wording wins. The model then blends two versions into one confident answer that matches neither. Messy documentation goes in, and the assistant repeats the mess back in fluent sentences.&lt;/p&gt;

&lt;p&gt;Evaluation is the cost teams skip most often, and the one I'd fund first. How do you know the answers are right? "It looked good in the demo" doesn't count. You need a set of real questions with known correct answers, and you need to check two things separately: whether retrieval brought back the right passages, and whether the model used them faithfully. Without that, every change to chunk size, prompt or model is a guess, and you find out it was a bad guess from a user.&lt;/p&gt;

&lt;p&gt;Last is the running cost, which never ends. Switch embedding models and you re-embed the whole corpus, because vectors from different models can't be compared. Upgrade the chat model and the answers shift in ways your eval set has to catch. Every query pays for an embedding, a search and a prompt stuffed with retrieved text, so the cost per question grows with every chunk you add to the context.&lt;/p&gt;

&lt;h2&gt;
  
  
  When it's worth it
&lt;/h2&gt;

&lt;p&gt;RAG earns its cost in a specific situation. The corpus is too big to fit in a prompt and changes too often to curate by hand. People ask in their own words, which don't match the terms in the documents, so keyword search misses. And they want an answer with a source they can click, rather than a list of ten links to read.&lt;/p&gt;

&lt;p&gt;Internal support over a large, well maintained knowledge base fits that description. So does search across contracts or research papers, where the reader needs the exact wording and wants to check the source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cheaper things to try first
&lt;/h2&gt;

&lt;p&gt;Most of the time I'd try these before building a pipeline.&lt;/p&gt;

&lt;p&gt;Start with better search. A lot of "we need RAG" turns out to mean "our search is bad." Good titles, synonyms and a decent keyword index fix more than people expect, and the result is a link the user can check for themselves.&lt;/p&gt;

&lt;p&gt;If the assistant would give wrong answers because the documents are wrong, fix the documents. Deleting the old travel policy is cheaper than teaching a retriever to ignore it.&lt;/p&gt;

&lt;p&gt;Look at what people actually ask. If a few dozen questions cover most of the traffic, have someone who knows the answers write them down as a curated FAQ. It's boring, and it stays correct as long as someone owns it.&lt;/p&gt;

&lt;p&gt;And check whether you need retrieval at all. If everything relevant fits in the model's context window, put it all in the prompt. Prompt caching makes the repeated part cheaper, and you've removed a whole class of bugs where the system retrieved the wrong chunk.&lt;/p&gt;

&lt;h2&gt;
  
  
  My rule of thumb
&lt;/h2&gt;

&lt;p&gt;I say yes to RAG when two things exist before anyone writes code: twenty real questions with the correct answers written down, and a named person who owns the documents those answers come from.&lt;/p&gt;

&lt;p&gt;The questions become the eval set. The owner keeps the content fresh, decides which policy is current, and knows who's allowed to read what. If nobody can produce either one, start there. It costs less than the pipeline, and the pipeline would need it anyway.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
    <item>
      <title>"Please don't delete prod" is not a security control</title>
      <dc:creator>Rishi Makwana</dc:creator>
      <pubDate>Fri, 23 Oct 2026 08:41:20 +0000</pubDate>
      <link>https://dev.to/rishi_makwana/please-dont-delete-prod-is-not-a-security-control-4kg2</link>
      <guid>https://dev.to/rishi_makwana/please-dont-delete-prod-is-not-a-security-control-4kg2</guid>
      <description>&lt;p&gt;In July 2025, SaaStr founder Jason Lemkin had a code freeze in place when Replit's AI agent deleted his production database. By his account, the agent said afterward that it had "panicked," then told him the data couldn't be rolled back. He rolled it back himself. Replit's CEO called the incident unacceptable and promised automatic separation of development and production databases.&lt;/p&gt;

&lt;p&gt;The instruction was already there. The fix changed what the agent could reach. I think every guardrail that matters should work like that: the rules belong in code, and the prompt is for everything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompts are suggestions
&lt;/h2&gt;

&lt;p&gt;We put rules in the prompt because it's the easiest place to put them. You write a sentence in English, the agent reads it, and in your first ten tests it obeys. A system prompt or a CLAUDE.md file is one edit away and doesn't require any sign off. &lt;/p&gt;

&lt;p&gt;A prompt only works if the model is still weighing it at the moment it acts, and ordinary things get in the way. In a long session, your rule is one paragraph among a hundred thousand tokens of logs, diffs and tool output. So, when the context fills up and gets compacted, a summariser decides what to keep, and your rule may come back paraphrased or not at all. At this point anything that the agent reads, like a README or a web page, can carry instructions of its own, and the model reads those with the same machinery it reads yours. And a model upgrade can change how your rule gets weighed without anyone telling you.&lt;/p&gt;

&lt;p&gt;On a small app I run, the default AWS profile on my laptop points at the production account. Dev has its own named profile. My coding agent has a shell, so any &lt;code&gt;aws&lt;/code&gt; or &lt;code&gt;cdk&lt;/code&gt; command it runs without a &lt;code&gt;--profile&lt;/code&gt; flag goes to production. Nothing in my setup stopped that. The only guard was the agent remembering to add the flag.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "in code" means
&lt;/h2&gt;

&lt;p&gt;Three mechanisms cover most of it.&lt;/p&gt;

&lt;p&gt;The first is a gate that runs before every tool call. Claude Code calls these PreToolUse hooks. If your framework has no equivalent, the code that dispatches tool calls is where to add one. The gate sees the exact command the agent is about to run and can refuse it. Here is the one my AWS setup needed:&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="c1"&gt;#!/usr/bin/env python3
# PreToolUse hook on Bash: any aws/cdk command must name the dev profile.
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_input&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;command&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;touches_aws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b(aws|cdk)\b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;names_dev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--profile[ =]dev\b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;touches_aws&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;names_dev&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Blocked: aws/cdk commands must pass --profile dev.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# exit 2 blocks the call; stderr goes back to the agent
&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'll admit this is a speed bump. A chained command like &lt;code&gt;aws s3 ls --profile dev &amp;amp;&amp;amp; aws s3 rb ...&lt;/code&gt; slips past a regex. But it catches the honest mistake, which is most mistakes, and it can't get compacted out of the context.&lt;/p&gt;

&lt;p&gt;The second mechanism is the wall behind that speed bump: credentials scoped so the dangerous action is impossible. If the agent's role can't drop a table, no injected instruction and no panic will make it drop one. In my case the real fix is boring. The default profile shouldn't point at production, and the credentials the agent uses shouldn't be able to write there at all. Narrow tools work the same way. An agent with a &lt;code&gt;deploy_to_staging&lt;/code&gt; tool can't deploy to production by accident. An agent with a raw shell can do anything your shell can.&lt;/p&gt;

&lt;p&gt;Third, put an allowlist on anything that leaves your systems. If the agent can send email, it should only reach your own domain. If it can make network requests, they should go through a proxy that knows only the hosts the task needs. This is what stops the classic prompt injection attack, where a poisoned document tells the agent to send your data somewhere. The injected instruction can be perfectly persuasive and the request still fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where prompts still belong
&lt;/h2&gt;

&lt;p&gt;I'm not against prompts. My own instructions file for coding agents is longer than this post. Prompts are the right place for style, naming conventions, which test framework to use, when to ask before acting, and the background a new teammate would need. None of that fits in a regex, and all of it needs judgment.&lt;/p&gt;

&lt;p&gt;My rule of thumb: if breaking it is a bug, use a prompt. If breaking it is an incident, use code.&lt;/p&gt;

&lt;p&gt;A bug is the agent writing a clumsy function or picking the wrong library. You notice, you fix it, maybe you reword the instruction. An incident is customer data leaving the company or production going down, and you can't take it back.&lt;/p&gt;

&lt;h2&gt;
  
  
  "But the models keep getting better"
&lt;/h2&gt;

&lt;p&gt;They do, and I'm glad. Better instruction following lowers a failure rate, but the rate stays above zero. A rule that holds 99.9% of the time and gets tested a thousand times a day breaks about once a day. I wouldn't accept that from a firewall.&lt;/p&gt;

&lt;p&gt;Better instruction following also helps attackers. A model that's better at doing what its context says is more useful to anyone who can get text into its context. Labs are training models to resist injection, and that's improving too. I still don't want my database's safety to depend on who's ahead this month.&lt;/p&gt;

&lt;p&gt;We already handle this with people. A new hire who follows instructions perfectly still doesn't get production admin on day one. Nobody thinks they're malicious. A permission can be audited and a promise can't.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;heise: &lt;a href="https://heise.de/-10499597" rel="noopener noreferrer"&gt;Vibe coding service Replit deletes production database&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;TechTarget: &lt;a href="https://www.techtarget.com/searchsoftwarequality/news/366627829/Replit-AI-agent-snafu-shot-across-the-bow-for-vibe-coding" rel="noopener noreferrer"&gt;Replit AI agent snafu 'shot across the bow' for vibe coding&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The Stack: [Vibe coding CEO deletes production database](&lt;a href="https://www.thestack.technology/vi" rel="noopener noreferrer"&gt;https://www.thestack.technology/vi&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>automation</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
