<?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>Forem: Athreya aka Maneshwar</title>
    <description>The latest articles on Forem by Athreya aka Maneshwar (@lovestaco).</description>
    <link>https://forem.com/lovestaco</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%2F1002302%2F5233b7df-6ee3-46b2-b8d7-1fafe103e8a3.jpg</url>
      <title>Forem: Athreya aka Maneshwar</title>
      <link>https://forem.com/lovestaco</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/lovestaco"/>
    <language>en</language>
    <item>
      <title>How Python's GIL actually works (and when it bites you)</title>
      <dc:creator>Athreya aka Maneshwar</dc:creator>
      <pubDate>Sun, 10 May 2026 10:17:16 +0000</pubDate>
      <link>https://forem.com/lovestaco/how-pythons-gil-actually-works-and-when-it-bites-you-3f2</link>
      <guid>https://forem.com/lovestaco/how-pythons-gil-actually-works-and-when-it-bites-you-3f2</guid>
      <description>&lt;p&gt;&lt;em&gt;Hello, I'm Maneshwar. I'm building git-lrc, a Micro AI code reviewer that runs on every commit. It is free and source-available on Github. &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/em&gt;&lt;/p&gt; 

&lt;p&gt;I remember the first time the GIL ruined my evening.&lt;/p&gt;

&lt;p&gt;I was working on &lt;a href="https://hexmos.com/freedevtools/" rel="noopener noreferrer"&gt;FreeDevTools&lt;/a&gt; and had a script that needed to parse, validate, and rewrite metadata for a few hundred thousand small markdown files and finally stores it into sqlite DB. &lt;/p&gt;

&lt;p&gt;The bulk of my work was pure Python, a lot of looping, dictionary lookups, string concatenation, and small object churn. No NumPy, no Pillow, no native libraries doing the heavy lifting.&lt;/p&gt;

&lt;p&gt;The single-threaded version was going to take forever, so I did what any reasonable person would do, I threw threads at it. &lt;/p&gt;

&lt;p&gt;Eight worker threads. Should be a lot faster, right?&lt;/p&gt;

&lt;p&gt;It was the same speed. Maybe a hair slower. I stared at the terminal for a solid minute thinking I'd done something wrong.&lt;/p&gt;

&lt;p&gt;I had not done something wrong. I had met the GIL.&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.amazonaws.com%2Fuploads%2Farticles%2F7qfgci20dxa3xseb8z9z.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.amazonaws.com%2Fuploads%2Farticles%2F7qfgci20dxa3xseb8z9z.png" alt="distracted boyfriend meme Girlfriend = " width="360" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So what is it
&lt;/h2&gt;

&lt;p&gt;GIL stands for &lt;a href="https://en.wikipedia.org/wiki/Global_interpreter_lock" rel="noopener noreferrer"&gt;Global Interpreter Lock&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The short version: it's a lock inside CPython (the standard Python you almost certainly use) that ensures only one thread executes Python &lt;em&gt;bytecode&lt;/em&gt; at a time, within a single interpreter.&lt;/p&gt;

&lt;p&gt;That word "&lt;em&gt;bytecode&lt;/em&gt;" is doing a lot of work, and we'll come back to it.&lt;br&gt;
For now, the simple version is: even if your laptop has 16 cores and you spin up 50 threads, only one of those threads is running Python code at any given instant. The rest are waiting their turn.&lt;/p&gt;

&lt;p&gt;The threads do take turns. &lt;/p&gt;

&lt;p&gt;CPython periodically gives other waiting threads a chance to acquire the GIL (the interval is 5 ms by default, tunable via &lt;code&gt;sys.setswitchinterval()&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;The actual handoff happens at the next safe point in the bytecode evaluation loop, so things look concurrent, even though no two threads are executing Python in parallel.&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.amazonaws.com%2Fuploads%2Farticles%2F4tjz6eu9u7synnekw1sh.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.amazonaws.com%2Fuploads%2Farticles%2F4tjz6eu9u7synnekw1sh.png" alt="image 815" width="600" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An analogy: you can hire ten cooks, but if there's only one knife, nine of them are watching the tenth one chop onions. They can rotate, but they can't chop simultaneously (Unless one of the cooks leaves the kitchen to wait for ingredients, which is roughly what happens during blocking I/O.)&lt;/p&gt;

&lt;p&gt;One important caveat before we go further: &lt;strong&gt;the GIL is a CPython thing.&lt;/strong&gt; &lt;br&gt;
Other Python runtimes like Jython and IronPython don't use the same GIL model, and modern CPython now also ships an experimental free-threaded build.&lt;/p&gt;

&lt;p&gt;When people say "Python has a GIL," they really mean "the most common Python implementation has a GIL."&lt;/p&gt;
&lt;h2&gt;
  
  
  Why does this exist
&lt;/h2&gt;

&lt;p&gt;Not because anyone was lazy. The GIL is a real engineering tradeoff.&lt;/p&gt;

&lt;p&gt;Python primarily manages memory with reference counting, plus a cyclic garbage collector for reference cycles. &lt;/p&gt;

&lt;p&gt;Every variable assignment, every function call, every time you stuff something into a list, there's a counter being incremented or decremented in the background. &lt;/p&gt;

&lt;p&gt;If two threads update those counters simultaneously without coordination, you get race conditions, and race conditions in memory management lead to crashes and corrupted data.&lt;/p&gt;

&lt;p&gt;The alternatives to the GIL is fine-grained locking on every object, or rewriting the memory model that come with their own costs: more overhead per operation, slower single-threaded code, and a much harder life for anyone writing C extensions. &lt;/p&gt;

&lt;p&gt;Much of the C extension ecosystem (NumPy, Pillow, lxml, every database driver) was built assuming the GIL exists. Rewriting all of that for thread safety is a generational project.&lt;/p&gt;

&lt;p&gt;So the GIL stuck around because the tradeoff genuinely favored it: simpler implementation, faster single-threaded code, and an easy contract for C extensions. &lt;/p&gt;

&lt;p&gt;The cost was no parallel execution of Python bytecode and for most users, that tradeoff was acceptable.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's actually see it
&lt;/h2&gt;

&lt;p&gt;Here's a script that demonstrates the limitation. Two heavy countdowns, run sequentially, then again with threads:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;countdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="n"&gt;COUNT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50_000_000&lt;/span&gt;

&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;countdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;countdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COUNT&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sequential: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;countdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
&lt;span class="n"&gt;t2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;countdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;threaded:   &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&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;&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%2Fki8vsabh1e8jx9cg67ic.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.amazonaws.com%2Fuploads%2Farticles%2Fki8vsabh1e8jx9cg67ic.png" alt="The threaded version will be roughly the same speed, sometimes a hair slower because of GIL switching overhead" width="598" height="68"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This benchmark is intentionally synthetic, a real workload has more nuance but it makes the core limitation visible in a way nothing else does.&lt;/p&gt;
&lt;h2&gt;
  
  
  The plot twist: threading isn't useless
&lt;/h2&gt;

&lt;p&gt;Here's the part that took me embarrassingly long to internalize.&lt;/p&gt;

&lt;p&gt;The GIL is released when Python is doing blocking I/O or, more precisely, when the C code implementing that I/O explicitly releases it. &lt;/p&gt;

&lt;p&gt;Reading a file, waiting on a network request, querying a database, sleeping, the underlying C call releases the GIL during the wait, lets other threads run, then reacquires it on the way back.&lt;/p&gt;

&lt;p&gt;Which means threading is genuinely useful, just not for what I initially thought.&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fake_request&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&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;# pretend this is a network call
&lt;/span&gt;
&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;fake_request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;fake_request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;fake_request&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sequential: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fake_request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;threaded:   &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&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;&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%2Fwah8qw48h46pr5ietu4j.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.amazonaws.com%2Fuploads%2Farticles%2Fwah8qw48h46pr5ietu4j.png" alt="image" width="526" height="65"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The rule of thumb that finally clicked for me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if your workload is mostly &lt;strong&gt;waiting on I/O&lt;/strong&gt;, threads often help a lot&lt;/li&gt;
&lt;li&gt;if your workload is mostly &lt;strong&gt;computing in pure Python bytecode&lt;/strong&gt;, threads usually won't speed it up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Web scrapers, API clients, anything that talks to a database or the filesystem for this, threading (or &lt;code&gt;asyncio&lt;/code&gt;) is great. &lt;/p&gt;

&lt;p&gt;Tight pure-Python loops that crunch data, threads will let you down.&lt;/p&gt;

&lt;p&gt;Quick aside on &lt;a href="https://docs.python.org/3/library/asyncio.html" rel="noopener noreferrer"&gt;asyncio&lt;/a&gt;, since it keeps coming up: &lt;code&gt;asyncio&lt;/code&gt; isn't an alternative to threading for using more cores. &lt;/p&gt;

&lt;p&gt;It's &lt;em&gt;concurrency in a single thread&lt;/em&gt; i.e one event loop juggling many I/O-bound coroutines without the overhead of OS threads. &lt;/p&gt;

&lt;p&gt;It's excellent for high-concurrency I/O workloads, but it does not bypass the GIL for CPU-bound Python code. &lt;/p&gt;

&lt;p&gt;If your workload is CPU-bound, &lt;code&gt;asyncio&lt;/code&gt; won't probably save you either.&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.amazonaws.com%2Fuploads%2Farticles%2Fesawshhvvjipyvhuqee4.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.amazonaws.com%2Fuploads%2Farticles%2Fesawshhvvjipyvhuqee4.png" alt="Drake meme. Rejecting: " width="360" height="360"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  When threads &lt;em&gt;do&lt;/em&gt; use multiple cores
&lt;/h2&gt;

&lt;p&gt;This is the section I wish someone had handed me a year ago.&lt;/p&gt;

&lt;p&gt;The GIL only restricts execution of &lt;strong&gt;Python bytecode&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;C extensions can release the GIL while they do their work in native code, and many of them do exactly that. &lt;/p&gt;

&lt;p&gt;When the GIL is released inside a C extension, other Python threads can run in parallel on multiple cores.&lt;/p&gt;

&lt;p&gt;This is why "threads can't use multiple cores in Python" is one of the most repeated half-truths on the internet. &lt;/p&gt;

&lt;p&gt;Threads doing work inside a well-written C extension absolutely can. &lt;/p&gt;

&lt;p&gt;If the underlying numerical or native library releases the GIL and isn't already saturating your CPU internally, threading on top can give you some parallelism.  (If you want to go down the rabbit hole, &lt;a href="https://stackoverflow.com/questions/7542957/is-python-capable-of-running-on-multiple-cores" rel="noopener noreferrer"&gt;this Stack Overflow thread&lt;/a&gt; has the canonical back-and-forth on the question)&lt;/p&gt;

&lt;p&gt;This is also why scientific Python feels so much faster than the language has any right to be: most of the actual work is happening in C/C++/Fortran, and the GIL gets out of the way for the duration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Okay but what if I genuinely need to crunch in pure Python
&lt;/h2&gt;

&lt;p&gt;This is where &lt;code&gt;multiprocessing&lt;/code&gt; comes in.&lt;/p&gt;

&lt;p&gt;Each process gets its own Python interpreter, its own memory, its own GIL. Spin up four processes on a four-core machine, and you actually get four cores' worth of work — no lock fighting, no taking turns.&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.amazonaws.com%2Fuploads%2Farticles%2Fgz5avo7e0qhcxlab4zig.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.amazonaws.com%2Fuploads%2Farticles%2Fgz5avo7e0qhcxlab4zig.png" alt="image" width="800" height="255"&gt;&lt;/a&gt;&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;multiprocessing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Process&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;countdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;COUNT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50_000_000&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;countdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
    &lt;span class="n"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;countdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
    &lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;multiprocessing: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&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;&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%2Fsgv3brcm0ytnm5rp9ymb.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.amazonaws.com%2Fuploads%2Farticles%2Fsgv3brcm0ytnm5rp9ymb.png" alt="image" width="696" height="45"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For sufficiently CPU-heavy workloads on multi-core systems, this is usually faster than the sequential version.. Won't always be exactly half, it depends on your CPU topology, thermal headroom, and what else your machine is doing but yeah, you'll see some parallelism.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The catch: processes are heavier than threads. They take longer to spin up, they don't share memory by default, and passing data between them involves serialization (usually pickling), which has its own gotchas. If you've ever seen a &lt;code&gt;Can't pickle local object&lt;/code&gt; error, you've met one of them.&lt;/p&gt;

&lt;p&gt;For most everyday cases, reach for &lt;em&gt;concurrent.futures.&lt;a href="https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor" rel="noopener noreferrer"&gt;ProcessPoolExecutor&lt;/a&gt;.&lt;/em&gt; It's a friendlier wrapper that makes multiprocessing feel almost as easy as threading.&lt;/p&gt;
&lt;h2&gt;
  
  
  The places it actually bites in real life
&lt;/h2&gt;

&lt;p&gt;Times I've watched people (also me) get burned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;writing a "fast" data transformation in pure Python with threads, expecting linear scaling, getting none&lt;/li&gt;
&lt;li&gt;threading a pandas pipeline that's mostly &lt;code&gt;.apply()&lt;/code&gt; with a Python function. pandas drops into C and releases the GIL for vectorized ops, but &lt;code&gt;.apply()&lt;/code&gt; calls back into Python — and Python is back to one thread at a time&lt;/li&gt;
&lt;li&gt;web scrapers that thread the &lt;em&gt;parsing&lt;/em&gt; with a pure-Python parser instead of the &lt;em&gt;fetching&lt;/em&gt;. fetching is I/O (good for threads). HTML parsing can become CPU-bound, especially with &lt;code&gt;html.parser&lt;/code&gt;. With &lt;code&gt;lxml&lt;/code&gt;, you'd be fine because lxml releases the GIL, parser choice matters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The throughline is always the same: figure out whether your bottleneck is &lt;strong&gt;waiting&lt;/strong&gt;, &lt;strong&gt;computing in pure Python&lt;/strong&gt;, or &lt;strong&gt;computing in a C extension&lt;/strong&gt;. Threading helps the first and third, not the middle.&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.amazonaws.com%2Fuploads%2Farticles%2Fiu858c5x2dzv7dxvl1am.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.amazonaws.com%2Fuploads%2Farticles%2Fiu858c5x2dzv7dxvl1am.png" alt="" width="360" height="270"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Wait, isn't the GIL going away
&lt;/h2&gt;

&lt;p&gt;Sort of.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://peps.python.org/pep-0703/" rel="noopener noreferrer"&gt;PEP 703&lt;/a&gt; the proposal to make the GIL optional in CPython — was accepted by the Steering Council in 2023, with explicit conditions: the rollout had to be gradual, ecosystem disruption had to stay manageable, and the entire effort could still be rolled back if it proved too disruptive.&lt;/p&gt;

&lt;p&gt;Python 3.13 (October 2024) shipped the first &lt;a href="https://docs.python.org/3/howto/free-threading-python.html" rel="noopener noreferrer"&gt;experimental free-threaded build&lt;/a&gt; of CPython alongside the normal GIL-enabled build. &lt;br&gt;
It allows running Python without the GIL, though many extension modules still rely on GIL assumptions and may re-enable it automatically when imported.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.python.org/3/whatsnew/3.14.html#whatsnew314-free-threaded-cpython" rel="noopener noreferrer"&gt;Python 3.14&lt;/a&gt; substantially improved the experimental free-threaded runtime. &lt;br&gt;
The adaptive interpreter was re-enabled, single-threaded performance penalties dropped substantially, and the project moved into Phase II of the Steering Council's rollout plan  where free-threaded Python is considered supported, but still optional and not the default runtime.&lt;/p&gt;

&lt;p&gt;CPython is clearly moving toward a future where no-GIL Python is viable  but we're not at the point where the standard build is going away anytime soon.&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.amazonaws.com%2Fuploads%2Farticles%2F0i7e3mvtj0u0hfnoh4q6.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.amazonaws.com%2Fuploads%2Farticles%2F0i7e3mvtj0u0hfnoh4q6.png" alt="Anakin/Padmé. " width="360" height="360"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What to actually do with all this
&lt;/h2&gt;

&lt;p&gt;If I had to compress everything I wish someone had told me earlier:&lt;/p&gt;

&lt;p&gt;When your code is slow, before reaching for any concurrency, profile it. Find out where the time is going. Then ask one question: &lt;strong&gt;is this thread waiting, computing in pure Python, or computing inside a C extension?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;waiting → threading or &lt;code&gt;asyncio&lt;/code&gt; will help a lot&lt;/li&gt;
&lt;li&gt;pure Python → threading won't help; reach for multiprocessing, or find a library that drops to C (NumPy, polars, anything with a native backend)&lt;/li&gt;
&lt;li&gt;C extension that releases the GIL → threading already helps; you may not need anything else&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And don't feel dumb if you've been bitten by this. Everyone has. The GIL is one of those things that's obvious in hindsight and completely opaque the first time you hit it. &lt;/p&gt;

&lt;p&gt;Now you've hit it on purpose, in a controlled environment, with a blog post next to you. That puts you ahead of where I was.&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.amazonaws.com%2Fuploads%2Farticles%2Floo7zg8mv8eo7vyae7vr.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.amazonaws.com%2Fuploads%2Farticles%2Floo7zg8mv8eo7vyae7vr.png" alt="Thats all folks" width="360" height="360"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://wiki.python.org/moin/GlobalInterpreterLock" rel="noopener noreferrer"&gt;Python Wiki — Global Interpreter Lock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/faq/library.html#can-t-we-get-rid-of-the-global-interpreter-lock" rel="noopener noreferrer"&gt;Python FAQ — Can't we get rid of the Global Interpreter Lock?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://peps.python.org/pep-0703/" rel="noopener noreferrer"&gt;PEP 703 — Making the Global Interpreter Lock Optional in CPython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/howto/free-threading-python.html" rel="noopener noreferrer"&gt;Python HOWTO — Python support for free threading&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/whatsnew/3.14.html#whatsnew314-free-threaded-cpython" rel="noopener noreferrer"&gt;What's New in Python 3.14 — Free-threaded CPython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://discuss.python.org/t/a-steering-council-notice-about-pep-703-making-the-global-interpreter-lock-optional-in-cpython/30474" rel="noopener noreferrer"&gt;Steering Council notice on PEP 703&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3.8/library/concurrent.futures.html#processpoolexecutor" rel="noopener noreferrer"&gt;Python docs — &lt;code&gt;concurrent.futures.ProcessPoolExecutor&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3.8/library/multiprocessing.html#introduction" rel="noopener noreferrer"&gt;Python docs — &lt;code&gt;multiprocessing&lt;/code&gt; introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://scipy-cookbook.readthedocs.io/items/ParallelProgramming.html" rel="noopener noreferrer"&gt;SciPy Cookbook — Parallel Programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/7542957/is-python-capable-of-running-on-multiple-cores" rel="noopener noreferrer"&gt;Stack Overflow — Is Python capable of running on multiple cores?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production. &lt;/p&gt;

&lt;p&gt;git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.* &lt;/p&gt;

&lt;p&gt;Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use. &lt;/p&gt;

&lt;p&gt;⭐ Star it on GitHub: &lt;br&gt;
 &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HexmosTech" rel="noopener noreferrer"&gt;
        HexmosTech
      &lt;/a&gt; / &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;
        git-lrc
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Free, Micro AI Code Reviews That Run on Commit
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;p&gt;| &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.da.md" rel="noopener noreferrer"&gt;🇩🇰 Dansk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.es.md" rel="noopener noreferrer"&gt;🇪🇸 Español&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fa.md" rel="noopener noreferrer"&gt;🇮🇷 Farsi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fi.md" rel="noopener noreferrer"&gt;🇫🇮 Suomi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ja.md" rel="noopener noreferrer"&gt;🇯🇵 日本語&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.nn.md" rel="noopener noreferrer"&gt;🇳🇴 Norsk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.pt.md" rel="noopener noreferrer"&gt;🇵🇹 Português&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ru.md" rel="noopener noreferrer"&gt;🇷🇺 Русский&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.sq.md" rel="noopener noreferrer"&gt;🇦🇱 Shqip&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.zh.md" rel="noopener noreferrer"&gt;🇨🇳 中文&lt;/a&gt; |&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;img width="60" alt="git-lrc logo" src="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;/a&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;git-lrc&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Free, Micro AI Code Reviews That Run on Commit&lt;/h2&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.producthunt.com/products/git-lrc?embed=true&amp;amp;utm_source=badge-top-post-badge&amp;amp;utm_medium=badge&amp;amp;utm_campaign=badge-git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt" width="200" src="https://camo.githubusercontent.com/87bf2d4283c1e0aa99e254bd17fefb1c67c0c0d39300043a243a4aa633b6cecc/68747470733a2f2f6170692e70726f6475637468756e742e636f6d2f776964676574732f656d6265642d696d6167652f76312f746f702d706f73742d62616467652e7376673f706f73745f69643d31303739323632267468656d653d6c6967687426706572696f643d6461696c7926743d31373731373439313730383638"&gt;&lt;/a&gt;
 &lt;/p&gt;
&lt;br&gt;
&lt;a href="https://discord.gg/sGdnKwB3qq" rel="nofollow noopener noreferrer"&gt;
  &lt;img alt="Discord Community" src="https://camo.githubusercontent.com/b8f979318aaabc8dec512b9d4e6e2a12431fba3c8a3b8738e1a97a0722d4e4bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d436f6d6d756e6974792d3538363546323f6c6f676f3d646973636f7264266c6162656c436f6c6f723d7768697465"&gt;
&lt;/a&gt; &lt;a href="https://goreportcard.com/report/github.com/HexmosTech/git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Go Report Card" src="https://camo.githubusercontent.com/e74c0651c3ee9165a2ed01cb0f6842c494029960df30eb9c24cf622d3d21bf46/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f4865786d6f73546563682f6769742d6c7263"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml" rel="noopener noreferrer"&gt;&lt;img alt="gitleaks.yml" title="gitleaks.yml: Secret scanning workflow" src="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml" rel="noopener noreferrer"&gt;&lt;img alt="osv-scanner.yml" title="osv-scanner.yml: Dependency vulnerability scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml" rel="noopener noreferrer"&gt;&lt;img alt="govulncheck.yml" title="govulncheck.yml: Go vulnerability check" src="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml" rel="noopener noreferrer"&gt;&lt;img alt="semgrep.yml" title="semgrep.yml: Static analysis security scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml/badge.svg"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer" href="https://github.com/HexmosTech/git-lrc/./gfx/dependabot-enabled.svg"&gt;&lt;img alt="dependabot-enabled" title="dependabot-enabled: Automated dependency updates are enabled" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FHexmosTech%2Fgit-lrc%2FHEAD%2F.%2Fgfx%2Fdependabot-enabled.svg"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;p&gt;AI agents write code fast. They also &lt;em&gt;silently remove logic&lt;/em&gt;, change behavior, and introduce bugs -- without telling you. You often find out in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;git-lrc&lt;/code&gt; fixes this.&lt;/strong&gt; It hooks into &lt;code&gt;git commit&lt;/code&gt; and reviews every diff &lt;em&gt;before&lt;/em&gt; it lands. 60-second setup. Completely free.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;See It In Action&lt;/h2&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;See git-lrc catch serious security issues such as leaked credentials, expensive cloud
operations, and sensitive material in log statements&lt;/p&gt;
&lt;/blockquote&gt;

  
    
    

    &lt;span class="m-1"&gt;git-lrc-intro-60s.mp4&lt;/span&gt;
    
  

  

  


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI agents silently break things.&lt;/strong&gt; Code removed. Logic changed. Edge cases gone. You won't notice until production.&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Catch it before it ships.&lt;/strong&gt; AI-powered inline comments show you &lt;em&gt;exactly&lt;/em&gt; what changed and what looks wrong.&lt;/li&gt;
&lt;li&gt;🔁 &lt;strong&gt;Build a&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>programming</category>
      <category>python</category>
    </item>
    <item>
      <title>Error Handling in Go: Stop Panicking, Start Wrapping</title>
      <dc:creator>Athreya aka Maneshwar</dc:creator>
      <pubDate>Fri, 08 May 2026 19:30:03 +0000</pubDate>
      <link>https://forem.com/lovestaco/error-handling-in-go-stop-panicking-start-wrapping-351d</link>
      <guid>https://forem.com/lovestaco/error-handling-in-go-stop-panicking-start-wrapping-351d</guid>
      <description>&lt;p&gt;&lt;em&gt;Hello, I'm Maneshwar. I'm building git-lrc, a Micro AI code reviewer that runs on every commit. It is free and source-available on Github. &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/em&gt;&lt;/p&gt; 

&lt;p&gt;So you wrote your first Go program. It compiled. You felt powerful. Then you saw this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dreams.txt"&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And you thought: &lt;em&gt;"Wait... am I supposed to write &lt;code&gt;if err != nil&lt;/code&gt; for the rest of my life?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yes, you are. But hear me out, it's actually kind of beautiful once you stop fighting it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Go Did This To You (And Why It's Actually Fine)
&lt;/h2&gt;

&lt;p&gt;Other languages treat errors like that one friend who shows up uninvited to your birthday party. They appear out of nowhere, ruin everything, and somebody else has to deal with them.&lt;/p&gt;

&lt;p&gt;Go decided: &lt;strong&gt;errors are values&lt;/strong&gt;. They're just things. Like strings. Or integers. &lt;/p&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Errors are visible in the function signature&lt;/li&gt;
&lt;li&gt;✅ You can't accidentally ignore them (well, you &lt;em&gt;can&lt;/em&gt;, but the linter will judge you)&lt;/li&gt;
&lt;li&gt;✅ No invisible control flow jumping across 14 stack frames&lt;/li&gt;
&lt;li&gt;❌ You have to type &lt;code&gt;if err != nil&lt;/code&gt; approximately 9,000 times&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a tradeoff. You'll grow to appreciate it. Or you'll switch to Rust. Both are valid.&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.amazonaws.com%2Fuploads%2Farticles%2Fr3npmcgs6x1ssi4gpe7g.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.amazonaws.com%2Fuploads%2Farticles%2Fr3npmcgs6x1ssi4gpe7g.png" alt=" " width="350" height="314"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Pattern 1: Just Return It
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;loadConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When you have nothing useful to add and the caller already has enough context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it:&lt;/strong&gt; When the caller is going to see &lt;code&gt;unexpected end of JSON input&lt;/code&gt; and have absolutely no idea which of the 47 JSON files in your app caused it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pattern 2: Wrap It Like It's 1999
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;fmt.Errorf&lt;/code&gt; with &lt;code&gt;%w&lt;/code&gt;. This is your new best friend. Treat them well.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;loadConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"loadConfig: reading %s: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"loadConfig: parsing %s: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now when this fails, you get something like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loadConfig: parsing /etc/app/config.json: unexpected end of JSON input
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;%w&lt;/code&gt; verb  &lt;strong&gt;wraps&lt;/strong&gt; the error so callers can still inspect it with &lt;code&gt;errors.Is&lt;/code&gt; and &lt;code&gt;errors.As&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;%v&lt;/code&gt; instead and you've turned your error into a string. &lt;/p&gt;

&lt;p&gt;The error has been murdered. You are the murderer.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pattern 3: Sentinel Errors (The Named Ones)
&lt;/h2&gt;

&lt;p&gt;Sometimes you want callers to check for &lt;em&gt;specific&lt;/em&gt; errors:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ErrNotFound&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user: not found"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ErrUnauthorized&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user: unauthorized"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ErrRateLimited&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user: rate limited, chill out"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&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;id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ErrNotFound&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And the caller does:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&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;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ErrNotFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&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="m"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"user not found"&lt;/span&gt;&lt;span class="p"&gt;)&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&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="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"something exploded"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;errors.Is&lt;/code&gt; walks the wrap chain, so even if the error got wrapped 12 times on its journey, you can still identify it. It's like DNA testing for errors.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pattern 4: Custom Error Types (When You're Feeling Fancy)
&lt;/h2&gt;

&lt;p&gt;Sometimes a string isn't enough. You want to attach data. You want a struct. You want to &lt;em&gt;flex&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ValidationError&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Field&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"validation failed on %s: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;validateEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"@"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"missing @ symbol, are you okay?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And the caller pulls out the type:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;validateEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;vErr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;vErr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hey, your %s is broken: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vErr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vErr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;errors.As&lt;/code&gt; is &lt;code&gt;errors.Is&lt;/code&gt;'s overachieving cousin. It doesn't just check, it &lt;em&gt;extracts&lt;/em&gt;.&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.amazonaws.com%2Fuploads%2Farticles%2Ff320jpbjbl33mjigwwk3.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.amazonaws.com%2Fuploads%2Farticles%2Ff320jpbjbl33mjigwwk3.png" alt=" " width="350" height="534"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Pattern 5: &lt;code&gt;panic&lt;/code&gt; and &lt;code&gt;recover&lt;/code&gt; (The Forbidden Techniques)
&lt;/h2&gt;

&lt;p&gt;You may have heard of &lt;code&gt;panic&lt;/code&gt;.  Maybe you saw it in a library and felt a chill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule of thumb:&lt;/strong&gt; If you're panicking, you should probably be returning an error instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real exceptions to the rule:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Truly unrecoverable situations (corrupt program state)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;init()&lt;/code&gt; functions where the program literally can't start&lt;/li&gt;
&lt;li&gt;Inside your own package, where you &lt;code&gt;recover()&lt;/code&gt; at the boundary and convert to an error
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;MustCompile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Regexp&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// genuinely fatal at startup&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you're using &lt;code&gt;panic&lt;/code&gt; for normal control flow, the Go gophers will find you. They have ways.&lt;/p&gt;
&lt;h2&gt;
  
  
  TL;DR For The Scrollers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Use This&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Just bubbling it up with no extra info&lt;/td&gt;
&lt;td&gt;&lt;code&gt;return err&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Want to add context&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fmt.Errorf("doing X: %w", err)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Caller needs to check a specific error&lt;/td&gt;
&lt;td&gt;Sentinel error + &lt;code&gt;errors.Is&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Caller needs error data&lt;/td&gt;
&lt;td&gt;Custom type + &lt;code&gt;errors.As&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The world is ending&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;panic&lt;/code&gt; (sparingly!)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Yes, you'll write &lt;code&gt;if err != nil&lt;/code&gt; a lot. &lt;/p&gt;

&lt;p&gt;But here's the thing, once you stop seeing it as boilerplate and start seeing it as a &lt;strong&gt;decision point&lt;/strong&gt;, every one of those blocks becomes a tiny little moment where you, the developer, get to think: &lt;em&gt;"What does failure mean here? What does the caller need to know?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's not a burden. That's craftsmanship.&lt;/p&gt;

&lt;p&gt;Now go forth and wrap your errors. &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.amazonaws.com%2Fuploads%2Farticles%2Fltnldy1pe270irh4mx6g.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.amazonaws.com%2Fuploads%2Farticles%2Fltnldy1pe270irh4mx6g.png" alt=" " width="360" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you enjoyed this, drop a 🦫 in the comments. If you didn't, write &lt;code&gt;if err != nil { return err }&lt;/code&gt; 100 times as penance.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&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%2Fyzvpkxm9mga1pweneahx.png" alt="git-lrc" width="800" height="109"&gt;&lt;/a&gt; &lt;br&gt;
 *AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production. &lt;/p&gt;

&lt;p&gt;git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.* &lt;/p&gt;

&lt;p&gt;Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use. &lt;/p&gt;

&lt;p&gt;⭐ Star it on GitHub: &lt;br&gt;
 &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HexmosTech" rel="noopener noreferrer"&gt;
        HexmosTech
      &lt;/a&gt; / &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;
        git-lrc
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Free, Micro AI Code Reviews That Run on Commit
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;p&gt;| &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.da.md" rel="noopener noreferrer"&gt;🇩🇰 Dansk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.es.md" rel="noopener noreferrer"&gt;🇪🇸 Español&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fa.md" rel="noopener noreferrer"&gt;🇮🇷 Farsi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fi.md" rel="noopener noreferrer"&gt;🇫🇮 Suomi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ja.md" rel="noopener noreferrer"&gt;🇯🇵 日本語&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.nn.md" rel="noopener noreferrer"&gt;🇳🇴 Norsk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.pt.md" rel="noopener noreferrer"&gt;🇵🇹 Português&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ru.md" rel="noopener noreferrer"&gt;🇷🇺 Русский&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.sq.md" rel="noopener noreferrer"&gt;🇦🇱 Shqip&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.zh.md" rel="noopener noreferrer"&gt;🇨🇳 中文&lt;/a&gt; |&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;img width="60" alt="git-lrc logo" src="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;/a&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;git-lrc&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Free, Micro AI Code Reviews That Run on Commit&lt;/h2&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.producthunt.com/products/git-lrc?embed=true&amp;amp;utm_source=badge-top-post-badge&amp;amp;utm_medium=badge&amp;amp;utm_campaign=badge-git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt" width="200" src="https://camo.githubusercontent.com/87bf2d4283c1e0aa99e254bd17fefb1c67c0c0d39300043a243a4aa633b6cecc/68747470733a2f2f6170692e70726f6475637468756e742e636f6d2f776964676574732f656d6265642d696d6167652f76312f746f702d706f73742d62616467652e7376673f706f73745f69643d31303739323632267468656d653d6c6967687426706572696f643d6461696c7926743d31373731373439313730383638"&gt;&lt;/a&gt;
 &lt;/p&gt;
&lt;br&gt;
&lt;a href="https://discord.gg/sGdnKwB3qq" rel="nofollow noopener noreferrer"&gt;
  &lt;img alt="Discord Community" src="https://camo.githubusercontent.com/b8f979318aaabc8dec512b9d4e6e2a12431fba3c8a3b8738e1a97a0722d4e4bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d436f6d6d756e6974792d3538363546323f6c6f676f3d646973636f7264266c6162656c436f6c6f723d7768697465"&gt;
&lt;/a&gt; &lt;a href="https://goreportcard.com/report/github.com/HexmosTech/git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Go Report Card" src="https://camo.githubusercontent.com/e74c0651c3ee9165a2ed01cb0f6842c494029960df30eb9c24cf622d3d21bf46/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f4865786d6f73546563682f6769742d6c7263"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml" rel="noopener noreferrer"&gt;&lt;img alt="gitleaks.yml" title="gitleaks.yml: Secret scanning workflow" src="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml" rel="noopener noreferrer"&gt;&lt;img alt="osv-scanner.yml" title="osv-scanner.yml: Dependency vulnerability scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml" rel="noopener noreferrer"&gt;&lt;img alt="govulncheck.yml" title="govulncheck.yml: Go vulnerability check" src="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml" rel="noopener noreferrer"&gt;&lt;img alt="semgrep.yml" title="semgrep.yml: Static analysis security scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml/badge.svg"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer" href="https://github.com/HexmosTech/git-lrc/./gfx/dependabot-enabled.svg"&gt;&lt;img alt="dependabot-enabled" title="dependabot-enabled: Automated dependency updates are enabled" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FHexmosTech%2Fgit-lrc%2FHEAD%2F.%2Fgfx%2Fdependabot-enabled.svg"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;p&gt;AI agents write code fast. They also &lt;em&gt;silently remove logic&lt;/em&gt;, change behavior, and introduce bugs -- without telling you. You often find out in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;git-lrc&lt;/code&gt; fixes this.&lt;/strong&gt; It hooks into &lt;code&gt;git commit&lt;/code&gt; and reviews every diff &lt;em&gt;before&lt;/em&gt; it lands. 60-second setup. Completely free.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;See It In Action&lt;/h2&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;See git-lrc catch serious security issues such as leaked credentials, expensive cloud
operations, and sensitive material in log statements&lt;/p&gt;
&lt;/blockquote&gt;

  
    
    

    &lt;span class="m-1"&gt;git-lrc-intro-60s.mp4&lt;/span&gt;
    
  

  

  


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI agents silently break things.&lt;/strong&gt; Code removed. Logic changed. Edge cases gone. You won't notice until production.&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Catch it before it ships.&lt;/strong&gt; AI-powered inline comments show you &lt;em&gt;exactly&lt;/em&gt; what changed and what looks wrong.&lt;/li&gt;
&lt;li&gt;🔁 &lt;strong&gt;Build a&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>go</category>
    </item>
    <item>
      <title>Shared Page Cache in SQLite: Smarter Memory, Less Redundant Work</title>
      <dc:creator>Athreya aka Maneshwar</dc:creator>
      <pubDate>Thu, 07 May 2026 12:40:15 +0000</pubDate>
      <link>https://forem.com/lovestaco/shared-page-cache-in-sqlite-smarter-memory-less-redundant-work-58a6</link>
      <guid>https://forem.com/lovestaco/shared-page-cache-in-sqlite-smarter-memory-less-redundant-work-58a6</guid>
      <description>&lt;p&gt;&lt;em&gt;Hello, I'm Maneshwar. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/em&gt;&lt;/p&gt; 

&lt;p&gt;In SQLite’s default behavior, every database connection gets its own page cache. &lt;/p&gt;

&lt;p&gt;This means that if your application opens the same database multiple times, even within the same thread and each connection loads and stores its own copy of data pages in memory.&lt;/p&gt;

&lt;p&gt;This design keeps things simple and isolated, but it comes at a cost. &lt;/p&gt;

&lt;p&gt;Memory usage increases because the same data may be stored multiple times, and disk I/O increases because each connection may read the same pages independently. &lt;/p&gt;

&lt;p&gt;On desktops this might not matter much, but on constrained environments like mobile devices, this duplication becomes inefficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Shared Page Cache Changes
&lt;/h2&gt;

&lt;p&gt;Shared page cache is a feature that allows multiple database connections to reuse a single page cache instead of maintaining separate ones. &lt;/p&gt;

&lt;p&gt;When enabled, connections to the same database within a process share both the page cache and the schema cache.&lt;/p&gt;

&lt;p&gt;This means that once a page is loaded into memory, other connections can use it without reloading it from disk. &lt;/p&gt;

&lt;p&gt;As a result, applications benefit from reduced memory usage and fewer disk operations, which can improve performance in read-heavy or multi-connection scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  How SQLite Implements Shared Caching Internally
&lt;/h2&gt;

&lt;p&gt;Even though connections share the cache, they are not merged into one. &lt;/p&gt;

&lt;p&gt;Each connection still has its own internal B-tree structure, which represents how it interacts with the database. &lt;/p&gt;

&lt;p&gt;However, these B-tree objects point to a shared structure known as &lt;code&gt;BtShared&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This shared object contains the pager, which is responsible for managing the page cache. &lt;/p&gt;

&lt;p&gt;Instead of each connection opening its own pager, they all rely on the same one. &lt;/p&gt;

&lt;p&gt;SQLite keeps track of these shared structures using an internal list, and when a new connection is opened, it checks whether a matching database is already in use. &lt;/p&gt;

&lt;p&gt;If it is, SQLite reuses the existing shared cache instead of creating a new one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enabling and Controlling Shared Cache
&lt;/h2&gt;

&lt;p&gt;Shared caching is not enabled by default. &lt;/p&gt;

&lt;p&gt;You can turn it on using the SQLite API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;sqlite3_enable_shared_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To disable it, you pass &lt;code&gt;0&lt;/code&gt; instead. &lt;/p&gt;

&lt;p&gt;Shared cache operates at the process level, which means only connections within the same process can share memory. &lt;/p&gt;

&lt;p&gt;Connections from different processes still operate independently and rely on standard file-level locking.&lt;/p&gt;
&lt;h2&gt;
  
  
  Locking Behavior in Shared Cache Mode
&lt;/h2&gt;

&lt;p&gt;When multiple connections share the same cache, SQLite introduces additional locking mechanisms to ensure consistency and avoid conflicts. &lt;/p&gt;

&lt;p&gt;These locks operate at different levels.&lt;/p&gt;
&lt;h3&gt;
  
  
  Transaction-Level Locking
&lt;/h3&gt;

&lt;p&gt;At this level, SQLite ensures that only one connection can perform write operations at a time. &lt;/p&gt;

&lt;p&gt;Multiple connections can still read concurrently, but writes are serialized to maintain database integrity.&lt;/p&gt;
&lt;h3&gt;
  
  
  Table-Level Locking
&lt;/h3&gt;

&lt;p&gt;Shared cache introduces a limited form of table-level locking within the same process. &lt;/p&gt;

&lt;p&gt;Instead of locking the entire database, SQLite can lock individual tables that are being accessed. &lt;/p&gt;

&lt;p&gt;This allows different connections to work on different tables simultaneously, improving concurrency compared to the default mode.&lt;/p&gt;
&lt;h3&gt;
  
  
  Schema-Level Locking
&lt;/h3&gt;

&lt;p&gt;Schema changes, such as creating or dropping tables, require stricter coordination. &lt;/p&gt;

&lt;p&gt;SQLite locks the schema to ensure that all connections see a consistent structure and that no conflicting modifications occur during these operations.&lt;/p&gt;
&lt;h2&gt;
  
  
  Benefits of Using Shared Page Cache
&lt;/h2&gt;

&lt;p&gt;The most immediate advantage of shared cache is reduced memory usage. &lt;/p&gt;

&lt;p&gt;Since multiple connections reuse the same cached pages, the overall memory footprint decreases. &lt;/p&gt;

&lt;p&gt;This is particularly useful for applications running on devices with limited resources.&lt;/p&gt;
&lt;h2&gt;
  
  
  Tradeoffs and Considerations
&lt;/h2&gt;

&lt;p&gt;Shared cache introduces additional complexity in locking and coordination. &lt;/p&gt;

&lt;p&gt;While it improves efficiency, it does not eliminate SQLite’s core limitation of allowing only one writer at a time. &lt;/p&gt;

&lt;p&gt;Developers also need to be mindful of how multiple connections interact, as shared state can make debugging more challenging.&lt;/p&gt;

&lt;p&gt;In many simple applications, a single connection is sufficient and avoids these complexities entirely. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&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%2Fyzvpkxm9mga1pweneahx.png" alt="git-lrc" width="800" height="109"&gt;&lt;/a&gt; &lt;br&gt;
 *AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production. &lt;/p&gt;

&lt;p&gt;git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.* &lt;/p&gt;

&lt;p&gt;Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use. &lt;/p&gt;

&lt;p&gt;⭐ Star it on GitHub: &lt;br&gt;
 &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HexmosTech" rel="noopener noreferrer"&gt;
        HexmosTech
      &lt;/a&gt; / &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;
        git-lrc
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Free, Micro AI Code Reviews That Run on Commit
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;p&gt;| &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.da.md" rel="noopener noreferrer"&gt;🇩🇰 Dansk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.es.md" rel="noopener noreferrer"&gt;🇪🇸 Español&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fa.md" rel="noopener noreferrer"&gt;🇮🇷 Farsi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fi.md" rel="noopener noreferrer"&gt;🇫🇮 Suomi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ja.md" rel="noopener noreferrer"&gt;🇯🇵 日本語&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.nn.md" rel="noopener noreferrer"&gt;🇳🇴 Norsk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.pt.md" rel="noopener noreferrer"&gt;🇵🇹 Português&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ru.md" rel="noopener noreferrer"&gt;🇷🇺 Русский&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.sq.md" rel="noopener noreferrer"&gt;🇦🇱 Shqip&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.zh.md" rel="noopener noreferrer"&gt;🇨🇳 中文&lt;/a&gt; |&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;img width="60" alt="git-lrc logo" src="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;/a&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;git-lrc&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;AI Micro Code Reviews That Run on Commit&lt;/h2&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.producthunt.com/products/git-lrc?embed=true&amp;amp;utm_source=badge-top-post-badge&amp;amp;utm_medium=badge&amp;amp;utm_campaign=badge-git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt" width="200" src="https://camo.githubusercontent.com/87bf2d4283c1e0aa99e254bd17fefb1c67c0c0d39300043a243a4aa633b6cecc/68747470733a2f2f6170692e70726f6475637468756e742e636f6d2f776964676574732f656d6265642d696d6167652f76312f746f702d706f73742d62616467652e7376673f706f73745f69643d31303739323632267468656d653d6c6967687426706572696f643d6461696c7926743d31373731373439313730383638"&gt;&lt;/a&gt;
 &lt;/p&gt;
&lt;br&gt;
&lt;a href="https://discord.gg/sGdnKwB3qq" rel="nofollow noopener noreferrer"&gt;
  &lt;img alt="Discord Community" src="https://camo.githubusercontent.com/b8f979318aaabc8dec512b9d4e6e2a12431fba3c8a3b8738e1a97a0722d4e4bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d436f6d6d756e6974792d3538363546323f6c6f676f3d646973636f7264266c6162656c436f6c6f723d7768697465"&gt;
&lt;/a&gt; &lt;a href="https://goreportcard.com/report/github.com/HexmosTech/git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Go Report Card" src="https://camo.githubusercontent.com/e74c0651c3ee9165a2ed01cb0f6842c494029960df30eb9c24cf622d3d21bf46/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f4865786d6f73546563682f6769742d6c7263"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml" rel="noopener noreferrer"&gt;&lt;img alt="gitleaks.yml" title="gitleaks.yml: Secret scanning workflow" src="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml" rel="noopener noreferrer"&gt;&lt;img alt="osv-scanner.yml" title="osv-scanner.yml: Dependency vulnerability scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml" rel="noopener noreferrer"&gt;&lt;img alt="govulncheck.yml" title="govulncheck.yml: Go vulnerability check" src="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml" rel="noopener noreferrer"&gt;&lt;img alt="semgrep.yml" title="semgrep.yml: Static analysis security scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml/badge.svg"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer" href="https://github.com/HexmosTech/git-lrc/./gfx/dependabot-enabled.svg"&gt;&lt;img alt="dependabot-enabled" title="dependabot-enabled: Automated dependency updates are enabled" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FHexmosTech%2Fgit-lrc%2FHEAD%2F.%2Fgfx%2Fdependabot-enabled.svg"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;p&gt;AI agents write code fast. They also &lt;em&gt;silently remove logic&lt;/em&gt;, change behavior, and introduce bugs -- without telling you. You often find out in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;git-lrc&lt;/code&gt; fixes this.&lt;/strong&gt; It hooks into &lt;code&gt;git commit&lt;/code&gt; and reviews every diff &lt;em&gt;before&lt;/em&gt; it lands. 60-second setup. Completely free.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;See It In Action&lt;/h2&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;See git-lrc catch serious security issues such as leaked credentials, expensive cloud
operations, and sensitive material in log statements&lt;/p&gt;
&lt;/blockquote&gt;

  
    
    

    &lt;span class="m-1"&gt;git-lrc-intro-60s.mp4&lt;/span&gt;
    
  

  

  


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI agents silently break things.&lt;/strong&gt; Code removed. Logic changed. Edge cases gone. You won't notice until production.&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Catch it before it ships.&lt;/strong&gt; AI-powered inline comments show you &lt;em&gt;exactly&lt;/em&gt; what changed and what looks wrong.&lt;/li&gt;
&lt;li&gt;🔁 &lt;strong&gt;Build a habit,&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>database</category>
      <category>architecture</category>
    </item>
    <item>
      <title>4 Open-Source Security Tools Every Dev Should Know</title>
      <dc:creator>Athreya aka Maneshwar</dc:creator>
      <pubDate>Wed, 06 May 2026 21:23:57 +0000</pubDate>
      <link>https://forem.com/lovestaco/4-open-source-security-tools-every-dev-should-know-35om</link>
      <guid>https://forem.com/lovestaco/4-open-source-security-tools-every-dev-should-know-35om</guid>
      <description>&lt;p&gt;&lt;em&gt;Hello, I'm Maneshwar. I'm building git-lrc, an AI code reviewer that runs on every commit. &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/em&gt;&lt;/p&gt; 

&lt;p&gt;Go's standard library is solid. The ecosystem is mature. But none of that protects you from leaked secrets, vulnerable dependencies.&lt;/p&gt;

&lt;p&gt;Security tooling fills the gap. The good news: the best tools in this space are open-source, free, and take about 1-10 minutes to set up.&lt;/p&gt;

&lt;p&gt;Here are four that punch way above their weight — what they do, why they matter, and how to drop them into your workflow today.&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.amazonaws.com%2Fuploads%2Farticles%2Fofl4teje2sbppz82carg.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.amazonaws.com%2Fuploads%2Farticles%2Fofl4teje2sbppz82carg.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Gitleaks — The Secret Scanner That Doesn't Sleep
&lt;/h2&gt;

&lt;p&gt;⭐ 26k stars · &lt;a href="https://gitleaks.io/" rel="noopener noreferrer"&gt;gitleaks.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gitleaks scans your git history (yes, the whole thing) and your working tree for leaked secrets — API keys, AWS credentials, JWTs, private keys, the whole rogues' gallery. &lt;/p&gt;

&lt;p&gt;It's basically the de facto standard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gitleaks detect &lt;span class="nt"&gt;--source&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's the whole command. &lt;/p&gt;

&lt;p&gt;Run it, and within seconds it tells you exactly which commit, which file, which line you screwed up.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Semgrep — Grep, But It Actually Understands Code
&lt;/h2&gt;

&lt;p&gt;⭐ 15k stars · &lt;a href="https://semgrep.dev/" rel="noopener noreferrer"&gt;semgrep.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Regular &lt;code&gt;grep&lt;/code&gt; is a hammer. Semgrep is a scalpel.&lt;/p&gt;

&lt;p&gt;Here's what makes it different: Semgrep is &lt;em&gt;semantic&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;If you write a rule looking for the value &lt;code&gt;2&lt;/code&gt;, it'll match &lt;code&gt;x = 1; y = x + 1&lt;/code&gt; because it knows &lt;code&gt;y&lt;/code&gt; evaluates to 2. &lt;/p&gt;

&lt;p&gt;That's not regex magic it's actual code comprehension.&lt;/p&gt;

&lt;p&gt;For Go specifically, this means you can write rules like "flag any &lt;code&gt;exec.Command&lt;/code&gt; call that takes user-controlled input" and it'll find them across your codebase, even when variable names differ. &lt;/p&gt;

&lt;p&gt;Run it as a pre-commit hook to catch the dumb stuff before it ever hits CI:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;semgrep &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;auto &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;auto&lt;/code&gt; config pulls community rules tailored to whatever languages it detects. &lt;/p&gt;
&lt;h2&gt;
  
  
  3. OSV-Scanner — Google's Vulnerability Detective
&lt;/h2&gt;

&lt;p&gt;⭐ 10k stars · &lt;a href="https://osv.dev/" rel="noopener noreferrer"&gt;osv.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your dependencies are a liability. Mine are too. Most projects don't talk about this enough.&lt;/p&gt;

&lt;p&gt;OSV-Scanner is Google's answer, and it plugs into the &lt;a href="https://osv.dev/" rel="noopener noreferrer"&gt;OSV database&lt;/a&gt; — a unified vulnerability feed that aggregates data from dozens of sources. &lt;/p&gt;

&lt;p&gt;Point it at your &lt;code&gt;go.mod&lt;/code&gt; and it tells you exactly which deps have known CVEs and how bad each one is.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;osv-scanner &lt;span class="nt"&gt;--lockfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;go.mod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The genuinely useful feature: &lt;strong&gt;guided remediation&lt;/strong&gt;. It doesn't just yell "you have 47 vulnerabilities" — it ranks fixes by impact, dependency depth, severity, and return on investment. &lt;/p&gt;

&lt;p&gt;It's the difference between a doctor saying "you're sick" and one handing you a treatment plan.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. govulncheck — The Official One With Big Brain Energy
&lt;/h2&gt;

&lt;p&gt;⭐ 470 stars · &lt;a href="https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck" rel="noopener noreferrer"&gt;pkg.go.dev/golang.org/x/vuln&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don't let the modest star count fool you. This is the official Go vulnerability scanner from the Go team itself, and it does something genuinely smarter than most of its competitors.&lt;/p&gt;

&lt;p&gt;Most scanners say: "you import a vulnerable library, panic now."&lt;/p&gt;

&lt;p&gt;govulncheck says: "you import a vulnerable library AND you actually CALL the vulnerable function in your code paths."&lt;/p&gt;

&lt;p&gt;That distinction is huge. The signal-to-noise ratio is night and day. No more drowning in false positives for code paths you never even hit.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The other wild thing: it works on &lt;strong&gt;compiled binaries&lt;/strong&gt; too. &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.amazonaws.com%2Fuploads%2Farticles%2Fy63ii4xm2wu5v0fdiz64.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.amazonaws.com%2Fuploads%2Farticles%2Fy63ii4xm2wu5v0fdiz64.png" alt=" " width="577" height="433"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  AI Just Changed The Game
&lt;/h2&gt;

&lt;p&gt;Here's the thing nobody wants to say out loud: AI is pushing your team's monthly code volume 2x to 10x higher than it was a year ago. &lt;/p&gt;

&lt;p&gt;More code. More diffs. More chances for something subtle to slip through until PR or production.&lt;/p&gt;

&lt;p&gt;Static scanners are necessary, but they weren't designed for this volume. &lt;/p&gt;

&lt;p&gt;They catch &lt;em&gt;known&lt;/em&gt; patterns — leaked secrets, known CVEs, known anti-patterns. They don't catch the new failure modes AI introduces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code that "seems to work" but doesn't handle the edge case the prompt forgot to mention&lt;/li&gt;
&lt;li&gt;The same prompt yielding different implementations on different runs&lt;/li&gt;
&lt;li&gt;Subtle regressions buried in 400-line AI-generated diffs nobody actually reads&lt;/li&gt;
&lt;li&gt;Logic errors that only show up after the demo, in front of customers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you ship AI-generated code, &lt;strong&gt;it's your responsibility to know what you're shipping.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;The model can generate the patch. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your team still owns the outage&lt;/strong&gt;, the exploit, the rollback, and the customer trust.&lt;/p&gt;
&lt;h2&gt;
  
  
  The 60-Second Control Point
&lt;/h2&gt;

&lt;p&gt;This is what I'm building &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;&lt;strong&gt;git-lrc&lt;/strong&gt;&lt;/a&gt; for — micro AI code reviews that run on every commit, before the diff enters git history.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Git-native:&lt;/strong&gt; reviews your staged diff at commit time, while context is still fresh&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast:&lt;/strong&gt; a micro review takes about 30 to 60 seconds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Useful:&lt;/strong&gt; summary + bug, security, and performance warnings before code moves downstream&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Small diffs reviewed early beat large diffs reviewed late. Every time.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The four tools above are your foundation. git-lrc is the verification loop on top — the difference between "we vibe-coded it and shipped" and "we shipped, and we know what we shipped."&lt;/p&gt;

&lt;p&gt;You can't delegate responsibility. But you can automate the part where you check the work.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HexmosTech" rel="noopener noreferrer"&gt;
        HexmosTech
      &lt;/a&gt; / &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;
        git-lrc
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Free, Micro AI Code Reviews That Run on Commit
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;p&gt;| &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.da.md" rel="noopener noreferrer"&gt;🇩🇰 Dansk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.es.md" rel="noopener noreferrer"&gt;🇪🇸 Español&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fa.md" rel="noopener noreferrer"&gt;🇮🇷 Farsi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fi.md" rel="noopener noreferrer"&gt;🇫🇮 Suomi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ja.md" rel="noopener noreferrer"&gt;🇯🇵 日本語&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.nn.md" rel="noopener noreferrer"&gt;🇳🇴 Norsk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.pt.md" rel="noopener noreferrer"&gt;🇵🇹 Português&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ru.md" rel="noopener noreferrer"&gt;🇷🇺 Русский&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.sq.md" rel="noopener noreferrer"&gt;🇦🇱 Shqip&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.zh.md" rel="noopener noreferrer"&gt;🇨🇳 中文&lt;/a&gt; |&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;img width="60" alt="git-lrc logo" src="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;/a&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;git-lrc&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;AI Micro Code Reviews That Run on Commit&lt;/h2&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.producthunt.com/products/git-lrc?embed=true&amp;amp;utm_source=badge-top-post-badge&amp;amp;utm_medium=badge&amp;amp;utm_campaign=badge-git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt" width="200" src="https://camo.githubusercontent.com/87bf2d4283c1e0aa99e254bd17fefb1c67c0c0d39300043a243a4aa633b6cecc/68747470733a2f2f6170692e70726f6475637468756e742e636f6d2f776964676574732f656d6265642d696d6167652f76312f746f702d706f73742d62616467652e7376673f706f73745f69643d31303739323632267468656d653d6c6967687426706572696f643d6461696c7926743d31373731373439313730383638"&gt;&lt;/a&gt;
 &lt;/p&gt;
&lt;br&gt;
&lt;a href="https://discord.gg/sGdnKwB3qq" rel="nofollow noopener noreferrer"&gt;
  &lt;img alt="Discord Community" src="https://camo.githubusercontent.com/b8f979318aaabc8dec512b9d4e6e2a12431fba3c8a3b8738e1a97a0722d4e4bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d436f6d6d756e6974792d3538363546323f6c6f676f3d646973636f7264266c6162656c436f6c6f723d7768697465"&gt;
&lt;/a&gt; &lt;a href="https://goreportcard.com/report/github.com/HexmosTech/git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Go Report Card" src="https://camo.githubusercontent.com/e74c0651c3ee9165a2ed01cb0f6842c494029960df30eb9c24cf622d3d21bf46/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f4865786d6f73546563682f6769742d6c7263"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml" rel="noopener noreferrer"&gt;&lt;img alt="gitleaks.yml" title="gitleaks.yml: Secret scanning workflow" src="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml" rel="noopener noreferrer"&gt;&lt;img alt="osv-scanner.yml" title="osv-scanner.yml: Dependency vulnerability scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml" rel="noopener noreferrer"&gt;&lt;img alt="govulncheck.yml" title="govulncheck.yml: Go vulnerability check" src="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml" rel="noopener noreferrer"&gt;&lt;img alt="semgrep.yml" title="semgrep.yml: Static analysis security scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml/badge.svg"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer" href="https://github.com/HexmosTech/git-lrc/./gfx/dependabot-enabled.svg"&gt;&lt;img alt="dependabot-enabled" title="dependabot-enabled: Automated dependency updates are enabled" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FHexmosTech%2Fgit-lrc%2FHEAD%2F.%2Fgfx%2Fdependabot-enabled.svg"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;p&gt;AI agents write code fast. They also &lt;em&gt;silently remove logic&lt;/em&gt;, change behavior, and introduce bugs -- without telling you. You often find out in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;git-lrc&lt;/code&gt; fixes this.&lt;/strong&gt; It hooks into &lt;code&gt;git commit&lt;/code&gt; and reviews every diff &lt;em&gt;before&lt;/em&gt; it lands. 60-second setup. Completely free.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;See It In Action&lt;/h2&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;See git-lrc catch serious security issues such as leaked credentials, expensive cloud
operations, and sensitive material in log statements&lt;/p&gt;
&lt;/blockquote&gt;

  
    
    

    &lt;span class="m-1"&gt;git-lrc-intro-60s.mp4&lt;/span&gt;
    
  

  

  


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI agents silently break things.&lt;/strong&gt; Code removed. Logic changed. Edge cases gone. You won't notice until production.&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Catch it before it ships.&lt;/strong&gt; AI-powered inline comments show you &lt;em&gt;exactly&lt;/em&gt; what changed and what looks wrong.&lt;/li&gt;
&lt;li&gt;🔁 &lt;strong&gt;Build a habit,&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&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.amazonaws.com%2Fuploads%2Farticles%2F9x6813dnagd045rn1t9q.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.amazonaws.com%2Fuploads%2Farticles%2F9x6813dnagd045rn1t9q.png" alt=" " width="620" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>go</category>
    </item>
    <item>
      <title>6 Agent Gateway Platforms That Actually Exist in 2026 (And What They're Good For)</title>
      <dc:creator>Athreya aka Maneshwar</dc:creator>
      <pubDate>Mon, 04 May 2026 16:10:51 +0000</pubDate>
      <link>https://forem.com/lovestaco/6-agent-gateway-platforms-that-actually-exist-in-2026-and-what-theyre-good-for-2kek</link>
      <guid>https://forem.com/lovestaco/6-agent-gateway-platforms-that-actually-exist-in-2026-and-what-theyre-good-for-2kek</guid>
      <description>&lt;p&gt;Picture this: it's 1:47 AM. Your phone buzzes. It's your team lead.&lt;/p&gt;

&lt;p&gt;The helpful little agent you spun up last quarter to "handle Tier 1 support tickets" has just confidently emailed 47 customers confirming refunds it has no authority to issue. &lt;/p&gt;

&lt;p&gt;None of the refunds are real. The numbers are hallucinated. Support Slack is on fire.&lt;/p&gt;

&lt;p&gt;You stare at the ceiling and ask the only question that matters:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who is actually in charge of these things?&lt;/strong&gt;&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.amazonaws.com%2Fuploads%2Farticles%2F9znuoviswl46ul69oxk9.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%2F9znuoviswl46ul69oxk9.gif" alt="aqu64e" width="360" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yeah. About that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing nobody warned you about
&lt;/h2&gt;

&lt;p&gt;Everyone's talking about agents. Almost nobody's talking about what happens &lt;em&gt;after&lt;/em&gt; you ship them.&lt;/p&gt;

&lt;p&gt;You don't have one agent. You have thirty. Each one has its own MCP tools, its own model, its own access to your systems. One is talking to your DB. One is sending emails. One is calling another agent that's calling another agent. Nobody on your team can answer "who can do what" without opening four repos.&lt;/p&gt;

&lt;p&gt;Then one of them does something dumb at 3 AM and you realize: there's no central place to see it, stop it, or roll it back.&lt;/p&gt;

&lt;p&gt;That's the gap agent gateways fill. The category is barely a category yet — think "API gateways in 2015." Here's what's actually shipping in 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait, what even is an "agent gateway"?
&lt;/h2&gt;

&lt;p&gt;Quick mental model: an agent gateway is the load-bearing wall between your agents and the rest of your infra. LLM routing, MCP tool governance, agent registry, A2A traffic, audit logs. Same energy as &lt;a href="https://istio.io/" rel="noopener noreferrer"&gt;Istio&lt;/a&gt; or &lt;a href="https://konghq.com/" rel="noopener noreferrer"&gt;Kong&lt;/a&gt;, just pointed at agents instead of microservices.&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.amazonaws.com%2Fuploads%2Farticles%2F5nwgbowc56xep7bk6de1.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.amazonaws.com%2Fuploads%2Farticles%2F5nwgbowc56xep7bk6de1.png" alt="image" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the "wait, isn't this just an AI gateway?" question is starting to form in your head, I wrote about exactly that distinction a while back: Link below&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/lovestaco/whats-an-ai-gateway-and-do-you-think-you-need-one-39c1" class="crayons-story__hidden-navigation-link"&gt;What's an AI Gateway and do you think you need one?&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/lovestaco" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F1002302%2F5233b7df-6ee3-46b2-b8d7-1fafe103e8a3.jpg" alt="lovestaco profile" class="crayons-avatar__image" width="800" height="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/lovestaco" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Athreya aka Maneshwar
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Athreya aka Maneshwar
                
              
              &lt;div id="story-author-preview-content-3467743" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/lovestaco" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F1002302%2F5233b7df-6ee3-46b2-b8d7-1fafe103e8a3.jpg" class="crayons-avatar__image" alt="" width="800" height="800"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Athreya aka Maneshwar&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/lovestaco/whats-an-ai-gateway-and-do-you-think-you-need-one-39c1" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 13&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/lovestaco/whats-an-ai-gateway-and-do-you-think-you-need-one-39c1" id="article-link-3467743"&gt;
          What's an AI Gateway and do you think you need one?
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/productivity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;productivity&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/lovestaco/whats-an-ai-gateway-and-do-you-think-you-need-one-39c1" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;37&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/lovestaco/whats-an-ai-gateway-and-do-you-think-you-need-one-39c1#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              2&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  1. &lt;a href="https://www.truefoundry.com/" rel="noopener noreferrer"&gt;TrueFoundry&lt;/a&gt; — the "I have a real job and a real budget" pick
&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.amazonaws.com%2Fuploads%2Farticles%2Fh1f97dmnf5u7nzz1k2no.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.amazonaws.com%2Fuploads%2Farticles%2Fh1f97dmnf5u7nzz1k2no.png" alt="image" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're running agents in an actual enterprise, the kind with a compliance team that asks uncomfortable questions — &lt;a href="https://www.truefoundry.com/" rel="noopener noreferrer"&gt;TrueFoundry&lt;/a&gt; is the grown-up in the room.&lt;/p&gt;

&lt;p&gt;It's the only Gartner-recognized platform in this space. It's processing &lt;strong&gt;10B+ requests per month&lt;/strong&gt; for companies like NVIDIA and Siemens Healthineers. SOC 2, HIPAA, and &lt;strong&gt;ITAR&lt;/strong&gt; compliance out of the box.&lt;/p&gt;

&lt;p&gt;You can deploy it in your VPC or on-prem, which matters approximately 0% to indie hackers and approximately 100% to anyone whose legal team has ever uttered the phrase "data residency." Latency overhead is around &lt;strong&gt;3–4ms&lt;/strong&gt;, which means it's not going to be the bottleneck.&lt;/p&gt;

&lt;p&gt;It does the whole stack: LLM routing, MCP tool governance, agent registration. One control plane.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The con?&lt;/strong&gt; It's a full platform. If all you want is a lightweight proxy because you're hacking on a weekend project, this is overkill. It's an opinionated, batteries-included thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Teams that want one control plane for models, tools, and agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;a href="https://agentgateway.dev/" rel="noopener noreferrer"&gt;AgentGateway.dev&lt;/a&gt; — the open-source bet
&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.amazonaws.com%2Fuploads%2Farticles%2Fef5o778s4tyxz9e3gqy7.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.amazonaws.com%2Fuploads%2Farticles%2Fef5o778s4tyxz9e3gqy7.png" alt="image" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Backed by the Linux Foundation's Agentic AI Foundation. Written in Rust. Supports LLM routing, MCP tool federation, and A2A agent-to-agent communication.&lt;/p&gt;

&lt;p&gt;The architecture is &lt;em&gt;right&lt;/em&gt;. Like, you read the design docs and nod.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But.&lt;/strong&gt; It launched in &lt;strong&gt;April 2026&lt;/strong&gt;. As in, weeks ago. There's no RBAC. No compliance certifications. No prod case studies. You are not going to get fired for picking this in 2027. &lt;/p&gt;

&lt;p&gt;Think of it as the foundation for what agent gateways will look like in a couple years. If you're the kind of person who runs Arch on your work laptop and contributes patches to Envoy on weekends, you'll feel right at home.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Teams who want to contribute to the open standard and are comfortable building governance on top.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;a href="https://kagent.dev/" rel="noopener noreferrer"&gt;Kagent&lt;/a&gt;
&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.amazonaws.com%2Fuploads%2Farticles%2Fh498ohtfsfmmqp5s0kw4.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.amazonaws.com%2Fuploads%2Farticles%2Fh498ohtfsfmmqp5s0kw4.png" alt="image" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your team's response to "we have a new traffic problem" is always "have you considered an Envoy filter," this one's for you.&lt;/p&gt;

&lt;p&gt;Kagent is built on KGateway (which is built on Envoy) and basically extends the service mesh pattern to agent traffic. It handles MCP authorization and is moving toward A2A support.&lt;/p&gt;

&lt;p&gt;The pitch is elegant: you already govern microservice traffic with Istio/Envoy. Why not govern agent traffic the same way? Same mental model, same tooling, same on-call team yelling at the same dashboards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Con:&lt;/strong&gt; very early. Tightly coupled to the K8s ecosystem. If you're not already a service mesh shop, the learning curve is "go take a 3-day course on Envoy filters first."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Platform teams already deep in Kubernetes and Envoy who want agents to be Just Another Workload™.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;a href="https://agatsoftware.com/" rel="noopener noreferrer"&gt;Pragatix&lt;/a&gt; — the "compliance team won't stop emailing me" pick
&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.amazonaws.com%2Fuploads%2Farticles%2Ff0hdvsa82hx8xelrkfj6.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.amazonaws.com%2Fuploads%2Farticles%2Ff0hdvsa82hx8xelrkfj6.png" alt="image" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pragatix doesn't try to be a Swiss Army knife. It picks one job and does it: agent governance. Execution-layer controls. On-prem deployment. Built for regulated industries like finance, healthcare, "we get audited four times a year" energy.&lt;/p&gt;

&lt;p&gt;It's the equivalent of those single-purpose UNIX tools. Doesn't do a million things. Does one thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Con:&lt;/strong&gt; narrow feature set. No LLM routing, no MCP gateway, no observability dashboard. You're going to need to pair it with other tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Security and compliance teams in regulated industries who need agent governance &lt;em&gt;yesterday&lt;/em&gt; and don't care that it doesn't also make coffee.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;a href="https://obot.ai/" rel="noopener noreferrer"&gt;Obot AI&lt;/a&gt; — the MCP-flavored pick
&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.amazonaws.com%2Fuploads%2Farticles%2Fg9lia8w8jtm2jsgozx9r.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.amazonaws.com%2Fuploads%2Farticles%2Fg9lia8w8jtm2jsgozx9r.png" alt="image" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Started life as an open-source MCP gateway. Now adding agent orchestration features on top. Think of it as MCP-first, agents-second.&lt;/p&gt;

&lt;p&gt;The MCP server lifecycle management is genuinely good. Deploying, cataloging, access controlling MCP servers feels like a solved problem here. They also donated the MCP Dev Summit to the Linux Foundation, which is the kind of move that signals "we're playing the long game, not the acquihire game."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Con:&lt;/strong&gt; primarily MCP-focused, not a full agent gateway. No LLM routing. No A2A support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Teams whose pain is specifically "we have 40 MCP servers and no idea who deployed which one", with a bit of agent orchestration on top.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. &lt;a href="https://www.operant.ai/" rel="noopener noreferrer"&gt;Operant AI&lt;/a&gt; — the security nerd pick
&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.amazonaws.com%2Fuploads%2Farticles%2Fhihszqink21qjmud9q41.jpg" 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%2Fhihszqink21qjmud9q41.jpg" alt="image 803" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Operant isn't really a gateway. It's more like the threat intelligence shop for the AI agent world. They published the &lt;em&gt;2026 Guide to Securing MCP&lt;/em&gt; and identified the &lt;strong&gt;"Shadow Escape"&lt;/strong&gt; zero-click exploit vector, which is exactly as terrifying as it sounds.&lt;/p&gt;

&lt;p&gt;If your job involves writing words like "attack surface" with a straight face, you'll like what they're doing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Con:&lt;/strong&gt; monitoring and research, not prevention and governance. You can't put Operant in front of your agents and call it a day. You pair it with an actual gateway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Security teams who want to deeply understand agent attack vectors &lt;em&gt;before&lt;/em&gt; they get told to deploy governance with a 2-week deadline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cheat sheet
&lt;/h2&gt;

&lt;p&gt;Because I know you scrolled here first:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;LLM Routing&lt;/th&gt;
&lt;th&gt;MCP Governance&lt;/th&gt;
&lt;th&gt;Agent Registry&lt;/th&gt;
&lt;th&gt;A2A Support&lt;/th&gt;
&lt;th&gt;Self-Hosted&lt;/th&gt;
&lt;th&gt;Compliance Certs&lt;/th&gt;
&lt;th&gt;Maturity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TrueFoundry&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Roadmap&lt;/td&gt;
&lt;td&gt;VPC/on-prem&lt;/td&gt;
&lt;td&gt;SOC 2, HIPAA, ITAR&lt;/td&gt;
&lt;td&gt;Prod (10B+ req/mo)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AgentGateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Via A2A cards&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Pre-prod&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kagent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Via Envoy&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Planned&lt;/td&gt;
&lt;td&gt;Planned&lt;/td&gt;
&lt;td&gt;K8s only&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Early&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pragatix&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;On-prem&lt;/td&gt;
&lt;td&gt;TBD&lt;/td&gt;
&lt;td&gt;Early&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Obot AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Early-mid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operant AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Security only&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Research phase&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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.amazonaws.com%2Fuploads%2Farticles%2F9vk2tmhqkowkd7u4eqxc.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.amazonaws.com%2Fuploads%2Farticles%2F9vk2tmhqkowkd7u4eqxc.png" alt="image 801" width="360" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So what do I actually pick?
&lt;/h2&gt;

&lt;p&gt;Here's my honest read:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You're at a real company shipping real agents to real users today?&lt;/strong&gt; &lt;a href="https://www.truefoundry.com/" rel="noopener noreferrer"&gt;TrueFoundry&lt;/a&gt;. It's the only thing on this list that's both enterprise-ready and comprehensive. Everything else is either narrow, early, or both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're a platform team that already lives and breathes K8s + Envoy?&lt;/strong&gt; Try Kagent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're regulated to the eyeballs and just need governance?&lt;/strong&gt; Pragatix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're an MCP-heavy shop?&lt;/strong&gt; Obot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're playing the long game and want to bet on open source?&lt;/strong&gt; AgentGateway.dev — with the caveat that you're going to be writing a lot of glue code in the meantime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're on the security team?&lt;/strong&gt; Operant for intel, plus one of the others for actual enforcement.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  So yeah…
&lt;/h2&gt;

&lt;p&gt;The agent gateway space right now is exactly where API gateways were in 2015. Early. Fragmented. A handful of credible options, a bunch of half-baked ones, and a clear sense that &lt;em&gt;something&lt;/em&gt; like this is going to be load-bearing infrastructure for the next decade. &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.amazonaws.com%2Fuploads%2Farticles%2Fpggxihjuriyijpcp2qp1.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.amazonaws.com%2Fuploads%2Farticles%2Fpggxihjuriyijpcp2qp1.png" alt="image 802" width="360" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bookmark this post. Check back in 6 months. I'd bet good money this list is twice as long by then, and at least one of these names will have been acquired by someone with a much bigger logo.&lt;/p&gt;

&lt;p&gt;What are you running in front of your agents right now? Drop it in the comments. I'm curious how everyone else is solving this. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>ai</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Locking, Savepoints, and In-Memory Databases in SQLite</title>
      <dc:creator>Athreya aka Maneshwar</dc:creator>
      <pubDate>Thu, 30 Apr 2026 09:48:57 +0000</pubDate>
      <link>https://forem.com/lovestaco/locking-savepoints-and-in-memory-databases-in-sqlite-2d7n</link>
      <guid>https://forem.com/lovestaco/locking-savepoints-and-in-memory-databases-in-sqlite-2d7n</guid>
      <description>&lt;p&gt;&lt;em&gt;Hello, I'm Maneshwar. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/em&gt;&lt;/p&gt; 

&lt;p&gt;As we go deeper into SQLite, things start getting less about syntax and more about &lt;strong&gt;how the database behaves under real workloads&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Features like triggers and autovacuum shape behavior internally, but now we’re stepping into how SQLite handles &lt;strong&gt;concurrency, transactions, and performance tradeoffs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is where concepts like &lt;strong&gt;table-level locking (or the lack of it), savepoints, and in-memory databases&lt;/strong&gt; become important.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table-Level Locking (Or Why SQLite Feels Different)
&lt;/h2&gt;

&lt;p&gt;One of the most important things to understand about SQLite is this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQLite does &lt;strong&gt;not support table-level locking&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;It uses &lt;strong&gt;file-level locking instead&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means the &lt;strong&gt;entire database file is treated as a single unit&lt;/strong&gt; when it comes to locking.&lt;/p&gt;

&lt;h3&gt;
  
  
  What This Means in Practice
&lt;/h3&gt;

&lt;p&gt;If one process is writing to the database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Other writes are blocked&lt;/li&gt;
&lt;li&gt;Reads may also be restricted depending on the lock state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So unlike larger databases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You cannot have multiple writers working on different tables at the same time&lt;/li&gt;
&lt;li&gt;Concurrency is limited at the file level&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This design keeps SQLite simple and reliable, but it also introduces limitations in high-write scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Clever Workaround: Splitting the Database
&lt;/h3&gt;

&lt;p&gt;If you really need something closer to table-level locking, SQLite gives you a workaround.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Store different tables in &lt;strong&gt;different database files&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Then combine them using the &lt;code&gt;ATTACH&lt;/code&gt; command
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;ATTACH&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="s1"&gt;'orders.db'&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;orders_db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;ATTACH&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="s1"&gt;'users.db'&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;users_db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now your application can treat them like one logical database.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why This Improves Concurrency
&lt;/h3&gt;

&lt;p&gt;Because each file is locked separately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One process can write to &lt;code&gt;users.db&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Another can write to &lt;code&gt;orders.db&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the same time.&lt;/p&gt;

&lt;p&gt;So while SQLite doesn’t support table-level locking directly, you can &lt;strong&gt;simulate it by splitting tables across files&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Tradeoffs
&lt;/h3&gt;

&lt;p&gt;This approach works—but it’s not free.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Multiple database files to manage&lt;/li&gt;
&lt;li&gt;Multiple rollback journals&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;master journal&lt;/strong&gt; for multi-database transactions&lt;/li&gt;
&lt;li&gt;Increased memory usage (each file has its own cache)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, transactions spanning multiple databases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are still ACID&lt;/li&gt;
&lt;li&gt;But can be slower due to coordination overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this is a tradeoff between &lt;strong&gt;concurrency and complexity&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Savepoints: Fine-Grained Control Inside Transactions
&lt;/h2&gt;

&lt;p&gt;Transactions in SQLite are usually all-or-nothing. &lt;/p&gt;

&lt;p&gt;But sometimes you don’t want to roll back everything,you just want to undo part of it.&lt;/p&gt;

&lt;p&gt;That’s where &lt;strong&gt;savepoints&lt;/strong&gt; come in.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is a Savepoint?
&lt;/h3&gt;

&lt;p&gt;A savepoint is a &lt;strong&gt;named checkpoint inside a transaction&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You create one like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;SAVEPOINT&lt;/span&gt; &lt;span class="n"&gt;sp1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now SQLite remembers the current state.&lt;/p&gt;
&lt;h3&gt;
  
  
  Rolling Back Partially
&lt;/h3&gt;

&lt;p&gt;If something goes wrong, you can roll back &lt;em&gt;just part&lt;/em&gt; of your work:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;sp1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Undoes changes made after &lt;code&gt;sp1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Keeps the transaction active&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is very different from a full &lt;code&gt;ROLLBACK&lt;/code&gt;, which cancels everything.&lt;/p&gt;
&lt;h3&gt;
  
  
  Releasing a Savepoint
&lt;/h3&gt;

&lt;p&gt;Once you’re happy with changes, you can finalize them:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;RELEASE&lt;/span&gt; &lt;span class="n"&gt;sp1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This commits that portion of the transaction.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Savepoints Matter
&lt;/h3&gt;

&lt;p&gt;Savepoints are especially useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have complex operations&lt;/li&gt;
&lt;li&gt;You want partial recovery&lt;/li&gt;
&lt;li&gt;You don’t want to restart an entire transaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They give you &lt;strong&gt;granular control&lt;/strong&gt;, which is something basic transactions don’t offer.&lt;/p&gt;
&lt;h3&gt;
  
  
  A Small but Important Detail
&lt;/h3&gt;

&lt;p&gt;Savepoints can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nested&lt;/li&gt;
&lt;li&gt;Reused (same name overrides previous one)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, SQLite keeps extra journal data while savepoints exist, because it needs that information to support partial rollbacks.&lt;/p&gt;
&lt;h2&gt;
  
  
  In-Memory Databases: Maximum Speed, Maximum Risk
&lt;/h2&gt;

&lt;p&gt;Now let’s talk about performance.&lt;/p&gt;

&lt;p&gt;SQLite allows you to create a database that lives entirely in memory:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;sqlite3_open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":memory:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This creates a database with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No files&lt;/li&gt;
&lt;li&gt;No disk I/O&lt;/li&gt;
&lt;li&gt;Everything stored in RAM&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Why It’s So Fast
&lt;/h3&gt;

&lt;p&gt;Because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No disk reads/writes&lt;/li&gt;
&lt;li&gt;No file system overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Operations become extremely fast, making this ideal for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;li&gt;Temporary data&lt;/li&gt;
&lt;li&gt;High-speed processing&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The Limitations
&lt;/h3&gt;

&lt;p&gt;This speed comes with serious tradeoffs.&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Data is Not Persistent
&lt;/h4&gt;

&lt;p&gt;Once the application closes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The entire database is gone&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  2. Not Shareable Across Processes
&lt;/h4&gt;

&lt;p&gt;Each in-memory database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exists only within one connection&lt;/li&gt;
&lt;li&gt;Cannot be accessed by other processes&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  3. Risk of Data Loss
&lt;/h4&gt;

&lt;p&gt;If:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The app crashes&lt;/li&gt;
&lt;li&gt;The system crashes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All data is lost instantly.&lt;/p&gt;
&lt;h4&gt;
  
  
  4. Memory Usage
&lt;/h4&gt;

&lt;p&gt;Everything lives in RAM, so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large datasets require large memory&lt;/li&gt;
&lt;li&gt;Not suitable for heavy storage&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  When Should You Use In-Memory Databases?
&lt;/h3&gt;

&lt;p&gt;They are great for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caching&lt;/li&gt;
&lt;li&gt;Temporary computations&lt;/li&gt;
&lt;li&gt;Unit testing&lt;/li&gt;
&lt;li&gt;Prototyping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are not suitable for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Persistent storage&lt;/li&gt;
&lt;li&gt;Critical systems&lt;/li&gt;
&lt;li&gt;Large-scale datasets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&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%2Fyzvpkxm9mga1pweneahx.png" alt="git-lrc" width="800" height="109"&gt;&lt;/a&gt; &lt;br&gt;
 *AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production. &lt;/p&gt;

&lt;p&gt;git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.* &lt;/p&gt;

&lt;p&gt;Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use. &lt;/p&gt;

&lt;p&gt;⭐ Star it on GitHub: &lt;br&gt;
 &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HexmosTech" rel="noopener noreferrer"&gt;
        HexmosTech
      &lt;/a&gt; / &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;
        git-lrc
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      AI Micro Code Reviews That Run on Commit
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;p&gt;| &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.da.md" rel="noopener noreferrer"&gt;🇩🇰 Dansk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.es.md" rel="noopener noreferrer"&gt;🇪🇸 Español&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fa.md" rel="noopener noreferrer"&gt;🇮🇷 Farsi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fi.md" rel="noopener noreferrer"&gt;🇫🇮 Suomi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ja.md" rel="noopener noreferrer"&gt;🇯🇵 日本語&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.nn.md" rel="noopener noreferrer"&gt;🇳🇴 Norsk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.pt.md" rel="noopener noreferrer"&gt;🇵🇹 Português&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ru.md" rel="noopener noreferrer"&gt;🇷🇺 Русский&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.sq.md" rel="noopener noreferrer"&gt;🇦🇱 Shqip&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.zh.md" rel="noopener noreferrer"&gt;🇨🇳 中文&lt;/a&gt; |&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;img width="60" alt="git-lrc logo" src="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;/a&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;git-lrc&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;AI Micro Code Reviews That Run on Commit&lt;/h2&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.producthunt.com/products/git-lrc?embed=true&amp;amp;utm_source=badge-top-post-badge&amp;amp;utm_medium=badge&amp;amp;utm_campaign=badge-git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt" width="200" src="https://camo.githubusercontent.com/87bf2d4283c1e0aa99e254bd17fefb1c67c0c0d39300043a243a4aa633b6cecc/68747470733a2f2f6170692e70726f6475637468756e742e636f6d2f776964676574732f656d6265642d696d6167652f76312f746f702d706f73742d62616467652e7376673f706f73745f69643d31303739323632267468656d653d6c6967687426706572696f643d6461696c7926743d31373731373439313730383638"&gt;&lt;/a&gt;
 &lt;/p&gt;
&lt;br&gt;
&lt;a href="https://discord.gg/sGdnKwB3qq" rel="nofollow noopener noreferrer"&gt;
  &lt;img alt="Discord Community" src="https://camo.githubusercontent.com/b8f979318aaabc8dec512b9d4e6e2a12431fba3c8a3b8738e1a97a0722d4e4bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d436f6d6d756e6974792d3538363546323f6c6f676f3d646973636f7264266c6162656c436f6c6f723d7768697465"&gt;
&lt;/a&gt; &lt;a href="https://goreportcard.com/report/github.com/HexmosTech/git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Go Report Card" src="https://camo.githubusercontent.com/e74c0651c3ee9165a2ed01cb0f6842c494029960df30eb9c24cf622d3d21bf46/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f4865786d6f73546563682f6769742d6c7263"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml" rel="noopener noreferrer"&gt;&lt;img alt="gitleaks.yml" title="gitleaks.yml: Secret scanning workflow" src="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml" rel="noopener noreferrer"&gt;&lt;img alt="osv-scanner.yml" title="osv-scanner.yml: Dependency vulnerability scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml" rel="noopener noreferrer"&gt;&lt;img alt="govulncheck.yml" title="govulncheck.yml: Go vulnerability check" src="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml" rel="noopener noreferrer"&gt;&lt;img alt="semgrep.yml" title="semgrep.yml: Static analysis security scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml/badge.svg"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer" href="https://github.com/HexmosTech/git-lrc/./gfx/dependabot-enabled.svg"&gt;&lt;img alt="dependabot-enabled" title="dependabot-enabled: Automated dependency updates are enabled" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FHexmosTech%2Fgit-lrc%2FHEAD%2F.%2Fgfx%2Fdependabot-enabled.svg"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;p&gt;AI agents write code fast. They also &lt;em&gt;silently remove logic&lt;/em&gt;, change behavior, and introduce bugs -- without telling you. You often find out in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;git-lrc&lt;/code&gt; fixes this.&lt;/strong&gt; It hooks into &lt;code&gt;git commit&lt;/code&gt; and reviews every diff &lt;em&gt;before&lt;/em&gt; it lands. 60-second setup. Completely free.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;See It In Action&lt;/h2&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;See git-lrc catch serious security issues such as leaked credentials, expensive cloud
operations, and sensitive material in log statements&lt;/p&gt;
&lt;/blockquote&gt;

  
    
    

    &lt;span class="m-1"&gt;git-lrc-intro-60s.mp4&lt;/span&gt;
    
  

  

  


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI agents silently break things.&lt;/strong&gt; Code removed. Logic changed. Edge cases gone. You won't notice until production.&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Catch it before it ships.&lt;/strong&gt; AI-powered inline comments show you &lt;em&gt;exactly&lt;/em&gt; what changed and what looks wrong.&lt;/li&gt;
&lt;li&gt;🔁 &lt;strong&gt;Build a habit,&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>database</category>
      <category>architecture</category>
    </item>
    <item>
      <title>AUTOVACUUM in SQLite: How Your Database Cleans Up After Itself</title>
      <dc:creator>Athreya aka Maneshwar</dc:creator>
      <pubDate>Wed, 22 Apr 2026 04:42:29 +0000</pubDate>
      <link>https://forem.com/lovestaco/autovacuum-in-sqlite-how-your-database-cleans-up-after-itself-4kp6</link>
      <guid>https://forem.com/lovestaco/autovacuum-in-sqlite-how-your-database-cleans-up-after-itself-4kp6</guid>
      <description>&lt;p&gt;&lt;em&gt;Hello, I'm Maneshwar. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/em&gt;&lt;/p&gt; 

&lt;h2&gt;
  
  
  AUTOVACUUM in SQLite: How Your Database Cleans Up After Itself
&lt;/h2&gt;

&lt;p&gt;Up to this point, we’ve looked at how SQLite handles logic (triggers), structure (views), and identity (autoincrement). &lt;/p&gt;

&lt;p&gt;Now we shift focus to something less visible but equally important i.e &lt;strong&gt;how SQLite manages space inside the database file&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Because unlike many systems, SQLite stores everything in a single file. &lt;/p&gt;

&lt;p&gt;And over time, that file doesn’t always behave the way you expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Default Mode: Nothing Gets Smaller Automatically
&lt;/h2&gt;

&lt;p&gt;By default, SQLite runs in &lt;strong&gt;non-autovacuum mode&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;This means that when you delete data or update rows, the database does not immediately shrink.&lt;/p&gt;

&lt;p&gt;Instead, something quieter happens.&lt;/p&gt;

&lt;p&gt;The space that was used by deleted data becomes &lt;strong&gt;free pages&lt;/strong&gt;, and these pages are added to something called a &lt;em&gt;freelist&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;SQLite keeps track of these pages and reuses them later when new data is inserted.&lt;/p&gt;

&lt;p&gt;So internally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The file size stays the same&lt;/li&gt;
&lt;li&gt;Free space exists inside the file&lt;/li&gt;
&lt;li&gt;Future inserts reuse that space&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is efficient, but it also means your database file can grow large and &lt;strong&gt;never shrink back down&lt;/strong&gt;, even if you delete a lot of data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual Cleanup: The VACUUM Command
&lt;/h2&gt;

&lt;p&gt;If you want to actually shrink the database file, you need to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;VACUUM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rebuilds the database&lt;/li&gt;
&lt;li&gt;Removes unused pages&lt;/li&gt;
&lt;li&gt;Returns space to the file system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, there are two important constraints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It cannot run inside a transaction (&lt;code&gt;BEGIN ... END&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;It must be executed manually&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why it’s called &lt;strong&gt;manual vacuuming&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Enter AUTOVACUUM: Automatic Space Reclaiming
&lt;/h2&gt;

&lt;p&gt;SQLite provides a feature called &lt;strong&gt;autovacuum&lt;/strong&gt;, which changes how this process works.&lt;/p&gt;

&lt;p&gt;When autovacuum is enabled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Freed pages are still tracked during a transaction&lt;/li&gt;
&lt;li&gt;But at commit time, SQLite &lt;strong&gt;returns unused space back to the file system automatically&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The database file can shrink on its own&lt;/li&gt;
&lt;li&gt;You don’t need to run &lt;code&gt;VACUUM&lt;/code&gt; manually&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once autovacuum is enabled, the &lt;code&gt;VACUUM&lt;/code&gt; command becomes mostly unnecessary.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Catch: Files Can Only Shrink From the End
&lt;/h2&gt;

&lt;p&gt;Here’s where things get interesting.&lt;/p&gt;

&lt;p&gt;Operating systems generally &lt;strong&gt;cannot remove space from the middle of a file&lt;/strong&gt;. They can only shrink a file from the end.&lt;/p&gt;

&lt;p&gt;So if SQLite frees pages in the middle of the file, it cannot just delete them directly.&lt;/p&gt;

&lt;p&gt;Instead, it has to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Move valid data from the end of the file into free space earlier in the file&lt;/li&gt;
&lt;li&gt;Free up pages at the end&lt;/li&gt;
&lt;li&gt;Then shrink the file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This process is called &lt;strong&gt;relocation&lt;/strong&gt;, and it is essentially a form of internal compaction.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pointer Map Pages: The Hidden Data Structure
&lt;/h2&gt;

&lt;p&gt;To make relocation possible, SQLite needs to track how pages are connected. This is where &lt;strong&gt;pointer-map pages&lt;/strong&gt; come in.&lt;/p&gt;

&lt;p&gt;These are special pages inside the database that store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;em&gt;type&lt;/em&gt; of each page&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;parent page&lt;/em&gt; that references it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each entry is very compact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 byte → type&lt;/li&gt;
&lt;li&gt;4 bytes → parent page number&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows SQLite to quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find relationships between pages&lt;/li&gt;
&lt;li&gt;Update references when pages are moved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this structure, relocating pages safely would be extremely difficult.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Pointer Maps Matter
&lt;/h2&gt;

&lt;p&gt;In a normal database tree, parent pages point to child pages. But during relocation, SQLite needs the reverse—it must find the parent of a page quickly.&lt;/p&gt;

&lt;p&gt;Pointer-map pages provide exactly that:&lt;br&gt;
👉 a fast lookup from child → parent&lt;/p&gt;

&lt;p&gt;This is critical when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Moving pages&lt;/li&gt;
&lt;li&gt;Updating references&lt;/li&gt;
&lt;li&gt;Maintaining database integrity&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Types of Pointer Map Entries
&lt;/h2&gt;

&lt;p&gt;Each page in the database is categorized using a type:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ROOTPAGE&lt;/strong&gt; → top-level page, no parent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BTREE&lt;/strong&gt; → regular internal page with a parent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OVERFLOW (1st page)&lt;/strong&gt; → linked from a data cell&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OVERFLOW (next pages)&lt;/strong&gt; → linked from previous overflow page&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FREEPAGE&lt;/strong&gt; → unused space&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These types help SQLite understand how each page fits into the overall structure.&lt;/p&gt;
&lt;h2&gt;
  
  
  Tradeoffs of AUTOVACUUM
&lt;/h2&gt;

&lt;p&gt;Autovacuum sounds like a clear win, but it comes with tradeoffs.&lt;/p&gt;
&lt;h3&gt;
  
  
  Advantages:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;No need for manual cleanup&lt;/li&gt;
&lt;li&gt;Database file stays compact&lt;/li&gt;
&lt;li&gt;Space is returned to the system automatically&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Disadvantages:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Slightly larger database size (due to pointer-map pages)&lt;/li&gt;
&lt;li&gt;Extra overhead during commits&lt;/li&gt;
&lt;li&gt;More internal complexity&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  When Should You Use AUTOVACUUM?
&lt;/h2&gt;

&lt;p&gt;Autovacuum is useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your database frequently deletes or updates data&lt;/li&gt;
&lt;li&gt;File size matters (e.g., mobile apps, embedded systems)&lt;/li&gt;
&lt;li&gt;You want automatic maintenance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might avoid it when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want maximum performance&lt;/li&gt;
&lt;li&gt;You prefer manual control using &lt;code&gt;VACUUM&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Your data doesn’t change frequently&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Autovacuum is one of those features you rarely think about—until your database file grows far larger than expected.&lt;/p&gt;

&lt;p&gt;By default, SQLite optimizes for reuse, not shrinkage. &lt;/p&gt;

&lt;p&gt;Autovacuum flips that behavior and keeps your file size in check, but it does so by adding internal complexity and overhead.&lt;/p&gt;

&lt;p&gt;Understanding this tradeoff helps you decide whether you want a database that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reuses space efficiently, or&lt;/li&gt;
&lt;li&gt;Actively keeps itself compact&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both approaches are valid. &lt;/p&gt;

&lt;p&gt;The right choice depends on how your application actually uses data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&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%2Fyzvpkxm9mga1pweneahx.png" alt="git-lrc" width="800" height="109"&gt;&lt;/a&gt; &lt;br&gt;
 *AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production. &lt;/p&gt;

&lt;p&gt;git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.* &lt;/p&gt;

&lt;p&gt;Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use. &lt;/p&gt;

&lt;p&gt;⭐ Star it on GitHub: &lt;br&gt;
 &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HexmosTech" rel="noopener noreferrer"&gt;
        HexmosTech
      &lt;/a&gt; / &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;
        git-lrc
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      AI Micro Code Reviews That Run on Commit
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;p&gt;| &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.da.md" rel="noopener noreferrer"&gt;🇩🇰 Dansk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.es.md" rel="noopener noreferrer"&gt;🇪🇸 Español&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fa.md" rel="noopener noreferrer"&gt;🇮🇷 Farsi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fi.md" rel="noopener noreferrer"&gt;🇫🇮 Suomi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ja.md" rel="noopener noreferrer"&gt;🇯🇵 日本語&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.nn.md" rel="noopener noreferrer"&gt;🇳🇴 Norsk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.pt.md" rel="noopener noreferrer"&gt;🇵🇹 Português&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ru.md" rel="noopener noreferrer"&gt;🇷🇺 Русский&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.sq.md" rel="noopener noreferrer"&gt;🇦🇱 Shqip&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.zh.md" rel="noopener noreferrer"&gt;🇨🇳 中文&lt;/a&gt; |&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;img width="60" alt="git-lrc logo" src="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;/a&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;git-lrc&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;AI Micro Code Reviews That Run on Commit&lt;/h2&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.producthunt.com/products/git-lrc?embed=true&amp;amp;utm_source=badge-top-post-badge&amp;amp;utm_medium=badge&amp;amp;utm_campaign=badge-git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt" width="200" src="https://camo.githubusercontent.com/87bf2d4283c1e0aa99e254bd17fefb1c67c0c0d39300043a243a4aa633b6cecc/68747470733a2f2f6170692e70726f6475637468756e742e636f6d2f776964676574732f656d6265642d696d6167652f76312f746f702d706f73742d62616467652e7376673f706f73745f69643d31303739323632267468656d653d6c6967687426706572696f643d6461696c7926743d31373731373439313730383638"&gt;&lt;/a&gt;
 &lt;/p&gt;
&lt;br&gt;
&lt;a href="https://discord.gg/sGdnKwB3qq" rel="nofollow noopener noreferrer"&gt;
  &lt;img alt="Discord Community" src="https://camo.githubusercontent.com/b8f979318aaabc8dec512b9d4e6e2a12431fba3c8a3b8738e1a97a0722d4e4bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d436f6d6d756e6974792d3538363546323f6c6f676f3d646973636f7264266c6162656c436f6c6f723d7768697465"&gt;
&lt;/a&gt; &lt;a href="https://goreportcard.com/report/github.com/HexmosTech/git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Go Report Card" src="https://camo.githubusercontent.com/e74c0651c3ee9165a2ed01cb0f6842c494029960df30eb9c24cf622d3d21bf46/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f4865786d6f73546563682f6769742d6c7263"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml" rel="noopener noreferrer"&gt;&lt;img alt="gitleaks.yml" title="gitleaks.yml: Secret scanning workflow" src="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml" rel="noopener noreferrer"&gt;&lt;img alt="osv-scanner.yml" title="osv-scanner.yml: Dependency vulnerability scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml" rel="noopener noreferrer"&gt;&lt;img alt="govulncheck.yml" title="govulncheck.yml: Go vulnerability check" src="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml" rel="noopener noreferrer"&gt;&lt;img alt="semgrep.yml" title="semgrep.yml: Static analysis security scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml/badge.svg"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer" href="https://github.com/HexmosTech/git-lrc/./gfx/dependabot-enabled.svg"&gt;&lt;img alt="dependabot-enabled" title="dependabot-enabled: Automated dependency updates are enabled" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FHexmosTech%2Fgit-lrc%2FHEAD%2F.%2Fgfx%2Fdependabot-enabled.svg"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;p&gt;AI agents write code fast. They also &lt;em&gt;silently remove logic&lt;/em&gt;, change behavior, and introduce bugs -- without telling you. You often find out in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;git-lrc&lt;/code&gt; fixes this.&lt;/strong&gt; It hooks into &lt;code&gt;git commit&lt;/code&gt; and reviews every diff &lt;em&gt;before&lt;/em&gt; it lands. 60-second setup. Completely free.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;See It In Action&lt;/h2&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;See git-lrc catch serious security issues such as leaked credentials, expensive cloud
operations, and sensitive material in log statements&lt;/p&gt;
&lt;/blockquote&gt;

  
    
    

    &lt;span class="m-1"&gt;git-lrc-intro-60s.mp4&lt;/span&gt;
    
  

  

  


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI agents silently break things.&lt;/strong&gt; Code removed. Logic changed. Edge cases gone. You won't notice until production.&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Catch it before it ships.&lt;/strong&gt; AI-powered inline comments show you &lt;em&gt;exactly&lt;/em&gt; what changed and what looks wrong.&lt;/li&gt;
&lt;li&gt;🔁 &lt;strong&gt;Build a habit,&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>database</category>
      <category>architecture</category>
    </item>
    <item>
      <title>What Building with MCP Taught Me About Its Biggest Gap</title>
      <dc:creator>Athreya aka Maneshwar</dc:creator>
      <pubDate>Mon, 20 Apr 2026 16:58:14 +0000</pubDate>
      <link>https://forem.com/lovestaco/what-building-with-mcp-taught-me-about-its-biggest-gap-idl</link>
      <guid>https://forem.com/lovestaco/what-building-with-mcp-taught-me-about-its-biggest-gap-idl</guid>
      <description>&lt;p&gt;I spent the last few weeks wiring up MCP at my org, stitching a handful of internal tools (GitHub, Slack, Datadog) into a shared layer that multiple teams' AI agents could call into. &lt;/p&gt;

&lt;p&gt;Useful. Powerful. And, about a week in, slightly alarming.&lt;/p&gt;

&lt;p&gt;The same four or five "wait, doesn't MCP handle this?" questions kept coming up. &lt;em&gt;Who's allowed to call this tool? What happens if a tool returns 50MB of data? Where are we logging any of this? How do I give Team A read-only access when Team B needs write?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Turns out: MCP doesn't handle any of it. Not because it's broken, because that's not what it's for. &lt;/p&gt;

&lt;p&gt;MCP standardizes &lt;em&gt;how&lt;/em&gt; agents talk to tools. It says nothing about &lt;em&gt;who&lt;/em&gt; gets to, &lt;em&gt;how much&lt;/em&gt; they can pull, or &lt;em&gt;whether anyone's keeping receipts&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I can't drop my org's internal code into a blog post, so I rebuilt the same shape of problem in a tiny &lt;a href="https://github.com/lovestaco/mcp" rel="noopener noreferrer"&gt;public repo&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Three MCP servers, one Gemini-driven agent, one minimal gateway, all runnable in five minutes.  &lt;/p&gt;

&lt;h2&gt;
  
  
  So, MCP. What is it, again?
&lt;/h2&gt;

&lt;p&gt;A thirty-second version of MCP, straight from the official docs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;MCP (Model Context Protocol) is an open-source standard for connecting AI applications to external systems. Think of it like a USB-C port for AI applications — a standardized way to plug data sources, tools, and workflows into Claude, ChatGPT, or whatever model you're wiring up.&lt;/p&gt;

&lt;p&gt;— &lt;a href="https://modelcontextprotocol.io/docs/getting-started/intro" rel="noopener noreferrer"&gt;modelcontextprotocol.io&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The mental model that finally made it click for me: &lt;strong&gt;MCP standardizes the plug, not the power grid.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Your agent speaks MCP. &lt;/p&gt;

&lt;p&gt;Your tools (GitHub, Slack, Datadog, your database) speak MCP. &lt;/p&gt;

&lt;p&gt;They meet in the middle and everything Just Works.&lt;/p&gt;

&lt;p&gt;Well. Almost everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  The demo: one agent, three MCP servers, a Gemini brain
&lt;/h2&gt;

&lt;p&gt;To make this concrete, I built the smallest possible setup, a repo anyone can clone and run in five minutes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;GitHub MCP server&lt;/strong&gt; that exposes &lt;code&gt;get_readme&lt;/code&gt;, &lt;code&gt;get_latest_commit&lt;/code&gt;, &lt;code&gt;get_repo_files&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Slack MCP server&lt;/strong&gt; that exposes &lt;code&gt;send_message&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;SQLite MCP server&lt;/strong&gt; that exposes &lt;code&gt;log_event&lt;/code&gt;, &lt;code&gt;get_logs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Gemini-driven agent&lt;/strong&gt; that picks a tool, calls it, summarizes the result, and posts to Slack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Five processes, one loop. Here's what that actually looks like on screen:&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.amazonaws.com%2Fuploads%2Farticles%2Fpbi0eek9hy58inl0c05r.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.amazonaws.com%2Fuploads%2Farticles%2Fpbi0eek9hy58inl0c05r.png" alt="All five terminals running together" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Point the agent at a repo and off it goes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;taco@TCSIND-4shZvZXk:~/mcp&lt;span class="nv"&gt;$ &lt;/span&gt;node agent/agent.js
&lt;span class="o"&gt;[&lt;/span&gt;agent] starting one-loop run
&lt;span class="o"&gt;[&lt;/span&gt;agent] chosen tool: github.get_readme
&lt;span class="o"&gt;[&lt;/span&gt;agent] summary: Ragfolio is an AI-powered portfolio template that uses RAG to answer professional questions based on your resume data. It is built with a modern stack including React, FastAPI, and Google Gemini &lt;span class="k"&gt;for &lt;/span&gt;high-performance retrieval and generation.
&lt;span class="o"&gt;[&lt;/span&gt;agent] demo loop &lt;span class="nb"&gt;complete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try a bigger, more famous repo? Same agent, no code change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;taco@TCSIND-4shZvZXk:~/mcp&lt;span class="nv"&gt;$ &lt;/span&gt;node agent/agent.js https://github.com/vercel/next.js
&lt;span class="o"&gt;[&lt;/span&gt;agent] starting one-loop run
&lt;span class="o"&gt;[&lt;/span&gt;agent] target repo: https://github.com/vercel/next.js
&lt;span class="o"&gt;[&lt;/span&gt;agent] objective: Summarize the project highlights &lt;span class="k"&gt;for &lt;/span&gt;a dev audience.
&lt;span class="o"&gt;[&lt;/span&gt;agent] chosen tool: github.get_readme
&lt;span class="o"&gt;[&lt;/span&gt;agent] summary: Next.js is a full-stack React framework designed &lt;span class="k"&gt;for &lt;/span&gt;building high-performance web applications with integrated Rust-based tooling. It extends the latest React features &lt;span class="k"&gt;while &lt;/span&gt;providing optimized build processes and a robust ecosystem &lt;span class="k"&gt;for &lt;/span&gt;enterprise-scale development.
&lt;span class="o"&gt;[&lt;/span&gt;agent] demo loop &lt;span class="nb"&gt;complete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Slack confirms the summaries landed:&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.amazonaws.com%2Fuploads%2Farticles%2Fmb6y6ue587fgev1r3d3s.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.amazonaws.com%2Fuploads%2Farticles%2Fmb6y6ue587fgev1r3d3s.png" alt="Slack showing ragfolio and Next.js summaries" width="800" height="95"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything works. High-fives all around. I'm ready to ship this to teams.&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.amazonaws.com%2Fuploads%2Farticles%2Fu2t5l942efztd9lvmru7.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.amazonaws.com%2Fuploads%2Farticles%2Fu2t5l942efztd9lvmru7.png" alt="The " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then I actually think about what I just built.&lt;/p&gt;

&lt;h2&gt;
  
  
  What MCP quietly does &lt;em&gt;not&lt;/em&gt; give you
&lt;/h2&gt;

&lt;p&gt;MCP is a protocol. That's wonderful and that's also exactly the problem. Out of the box, vanilla MCP has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No auth.&lt;/strong&gt; Anyone who can reach port 4001 can call every tool on the GitHub server. In prod, that's a problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No RBAC.&lt;/strong&gt; Every caller gets every tool, or no tools.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No audit.&lt;/strong&gt; Unless you add logging to every server, by hand, there is no record of who called what. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No guardrails on outputs.&lt;/strong&gt; If a tool returns a 2MB README, your agent happily eats 2MB of its context window. If a tool returns &lt;code&gt;rm -rf /&lt;/code&gt;, your agent happily executes it too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No shared policy layer.&lt;/strong&gt; Every team ends up copy-pasting the same "validate tool name, wrap in &lt;code&gt;{ output, error }&lt;/code&gt;" boilerplate, each with its own subtly different bugs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a knock on MCP. &lt;/p&gt;

&lt;p&gt;USB-C also doesn't come with a surge protector. &lt;/p&gt;

&lt;p&gt;Those are separate products for good reasons. &lt;/p&gt;

&lt;p&gt;But if you're running agents in an environment where the blast radius of "oops" is meaningful, you need that separate product.&lt;/p&gt;

&lt;p&gt;The obvious place for that product to live? A &lt;strong&gt;gateway&lt;/strong&gt;, sitting between every agent and every MCP server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting a tiny gateway in front of everything
&lt;/h2&gt;

&lt;p&gt;In my demo repo, the gateway is a single 90-line Express file (&lt;code&gt;gateway/gateway.js&lt;/code&gt;). It does three things. Together, they cover 80% of the complaints above.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. An allowlist — capability control in one &lt;code&gt;Set&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Every tool call is namespaced (&lt;code&gt;github.get_readme&lt;/code&gt;, &lt;code&gt;slack.send_message&lt;/code&gt;, &lt;code&gt;db.log_event&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;The allowlist is quite literally a JS &lt;code&gt;Set&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TOOL_ALLOWLIST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="nx"&gt;TOOL_NAMES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GITHUB_GET_README&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;TOOL_NAMES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SLACK_SEND_MESSAGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;TOOL_NAMES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_LOG_EVENT&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If an agent (or a prompt-injected-into-misbehavior agent) tries to call &lt;code&gt;github.delete_repo&lt;/code&gt;, it never reaches the GitHub server. &lt;/p&gt;

&lt;p&gt;The gateway refuses in three lines, logs the attempt, and sends back a polite error.&lt;/p&gt;

&lt;p&gt;Notice what this &lt;em&gt;isn't&lt;/em&gt;: a prompt that says "please don't call delete_repo." &lt;/p&gt;

&lt;p&gt;Prompts are suggestions. &lt;/p&gt;

&lt;p&gt;Allowlists are rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. A guardrail — the content contract
&lt;/h3&gt;

&lt;p&gt;Some tools return unbounded blobs. &lt;/p&gt;

&lt;p&gt;READMEs in particular love to be 40KB of badges and marketing copy. &lt;/p&gt;

&lt;p&gt;The gateway has a hardcoded cap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;tool&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;TOOL_NAMES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GITHUB_GET_README&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nx"&gt;serverResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;README content exceeded 5000 characters&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's that guardrail earning its keep on a deliberately gnarly repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;taco@TCSIND-4shZvZXk:~/mcp&lt;span class="nv"&gt;$ &lt;/span&gt;node agent/agent.js https://github.com/juice-shop/juice-shop 
&lt;span class="o"&gt;[&lt;/span&gt;agent] starting one-loop run
&lt;span class="o"&gt;[&lt;/span&gt;agent] target repo: https://github.com/juice-shop/juice-shop
&lt;span class="o"&gt;[&lt;/span&gt;agent] objective: Summarize the project highlights &lt;span class="k"&gt;for &lt;/span&gt;a dev audience.
&lt;span class="o"&gt;[&lt;/span&gt;agent] chosen tool: github.get_readme
&lt;span class="o"&gt;[&lt;/span&gt;agent] first tool call failed: &lt;span class="o"&gt;{&lt;/span&gt;
  message: &lt;span class="s1"&gt;'Guardrail blocked response: README content exceeded 5000 characters'&lt;/span&gt;,
  details: null
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Juice Shop's README is enormous. &lt;/p&gt;

&lt;p&gt;Without the guardrail, my agent would've burned half its context on emoji-laden marketing. &lt;/p&gt;

&lt;p&gt;With the guardrail, the agent got a clean "nope, try something else" and my context window stayed intact.&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.amazonaws.com%2Fuploads%2Farticles%2F8sqbszd33efzo0h3p122.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.amazonaws.com%2Fuploads%2Farticles%2F8sqbszd33efzo0h3p122.png" alt="Gandalf " width="641" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Logging — audit trail for free
&lt;/h3&gt;

&lt;p&gt;Every single call through the gateway i.e success, failure, allowlist rejection, guardrail block  gets recorded to SQLite via the &lt;code&gt;db.log_event&lt;/code&gt; tool. &lt;/p&gt;

&lt;p&gt;Best-effort, fire-and-forget, one &lt;code&gt;await&lt;/code&gt; in the middleware.&lt;/p&gt;

&lt;p&gt;Now when someone asks &lt;em&gt;"what did the agent do yesterday?"&lt;/em&gt; the answer is a query, not a shrug.&lt;/p&gt;

&lt;p&gt;That's it. &lt;/p&gt;

&lt;p&gt;That's the whole governance layer. &lt;/p&gt;

&lt;p&gt;An allowlist, a guardrail, a log  roughly 200 lines of Node, no framework, readable in a single sitting.&lt;/p&gt;

&lt;h2&gt;
  
  
  But a toy gateway is still a toy
&lt;/h2&gt;

&lt;p&gt;Here's where I have to be honest with myself. &lt;/p&gt;

&lt;p&gt;My gateway works for the demo. &lt;/p&gt;

&lt;p&gt;It would not survive contact with a real organization.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The allowlist is &lt;strong&gt;one &lt;code&gt;Set&lt;/code&gt; shared by everyone&lt;/strong&gt;. No per-team, per-agent, per-use-case scoping.&lt;/li&gt;
&lt;li&gt;Guardrails are &lt;strong&gt;hardcoded conditionals&lt;/strong&gt;. Adding a new one means a code change and a redeploy.&lt;/li&gt;
&lt;li&gt;Authentication is &lt;strong&gt;nonexistent&lt;/strong&gt;. Anyone who can &lt;code&gt;curl :3000/mcp&lt;/code&gt; is an agent now.&lt;/li&gt;
&lt;li&gt;Routing is &lt;strong&gt;three &lt;code&gt;localhost&lt;/code&gt; URLs in a map&lt;/strong&gt;. No service discovery, no health checks, no retries.&lt;/li&gt;
&lt;li&gt;Adding a new tool means &lt;strong&gt;editing three files&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Solving each of those is a weekend project. &lt;/p&gt;

&lt;p&gt;Solving all of them, operating them, and keeping them maintained as tools come and go across teams, that's a platform team's full-time job.&lt;/p&gt;

&lt;h2&gt;
  
  
  The feature I wish I'd built first: the Virtual MCP Server
&lt;/h2&gt;

&lt;p&gt;While researching what a grown-up version of this gateway looks like, I came across &lt;strong&gt;TrueFoundry's MCP Gateway&lt;/strong&gt; and specifically their concept of a &lt;strong&gt;Virtual MCP Server&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;It's one of those ideas that's obvious in retrospect and I'm mildly annoyed I didn't think of it first.&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.amazonaws.com%2Fuploads%2Farticles%2Frart7msy3xnpuiedr2bj.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.amazonaws.com%2Fuploads%2Farticles%2Frart7msy3xnpuiedr2bj.png" alt="Expanding-brain / galaxy-brain meme — panel 1: " width="500" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea:&lt;/p&gt;

&lt;p&gt;You have a bunch of real MCP servers, each exposing lots of tools. &lt;/p&gt;

&lt;p&gt;Some tools are safe. &lt;/p&gt;

&lt;p&gt;Some are dangerous. &lt;/p&gt;

&lt;p&gt;Some are fine for one team and a footgun for another.&lt;/p&gt;

&lt;p&gt;Rather than giving teams access to &lt;em&gt;whole servers&lt;/em&gt;, you compose a &lt;strong&gt;Virtual MCP Server&lt;/strong&gt;, a curated, custom, named collection of tools pulled from &lt;em&gt;whichever&lt;/em&gt; upstream servers you want.&lt;/p&gt;

&lt;p&gt;Concretely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your &lt;strong&gt;&lt;code&gt;doc-summary-bot&lt;/code&gt;&lt;/strong&gt; Virtual MCP Server exposes just &lt;code&gt;github.get_readme&lt;/code&gt; and &lt;code&gt;slack.send_message&lt;/code&gt;. That's the full surface area.&lt;/li&gt;
&lt;li&gt;Your &lt;strong&gt;&lt;code&gt;release-bot&lt;/code&gt;&lt;/strong&gt; Virtual MCP Server exposes &lt;code&gt;github.create_release&lt;/code&gt;, &lt;code&gt;github.tag_commit&lt;/code&gt;, and &lt;code&gt;slack.send_message&lt;/code&gt; — but &lt;em&gt;not&lt;/em&gt; &lt;code&gt;github.delete_repo&lt;/code&gt;, even though the upstream GitHub server technically supports it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No new deployments.  &lt;/p&gt;

&lt;p&gt;The virtual server is just configuration on the gateway, and each one gets its own allowlist, its own guardrails, its own auth scope.&lt;/p&gt;

&lt;p&gt;This matters because of the failure mode it quietly prevents. &lt;/p&gt;

&lt;p&gt;Here's a solid demo video explaining &lt;a href="https://youtu.be/cZgc0qxDP2k?si=fm_lv8fRL1F4YaxN" rel="noopener noreferrer"&gt;Virtual MCP Server&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this looks like in a real workflow
&lt;/h2&gt;

&lt;p&gt;Let me walk through the kind of agent I'd actually want to run in production, a &lt;strong&gt;compliance automation bot&lt;/strong&gt;, operating entirely through a TrueFoundry MCP Gateway endpoint:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A PR merges to &lt;code&gt;main&lt;/code&gt;. A webhook wakes the agent.&lt;/li&gt;
&lt;li&gt;The agent calls &lt;code&gt;github.get_diff&lt;/code&gt; via its Virtual MCP Server. &lt;strong&gt;Authenticated&lt;/strong&gt;, not with a bare PAT pasted into an env var, but with a service token the gateway issued and can rotate.&lt;/li&gt;
&lt;li&gt;The diff comes back. The gateway's &lt;strong&gt;guardrail&lt;/strong&gt; notices it's 12,000 lines, well over the "unsupervised review" threshold  and &lt;strong&gt;pauses the run, requesting human approval&lt;/strong&gt; before continuing. (Try getting &lt;em&gt;that&lt;/em&gt; out of a lone MCP server.)&lt;/li&gt;
&lt;li&gt;A reviewer approves. The agent writes the diff plus metadata to MongoDB via &lt;code&gt;db.store_diff&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It opens a Jira ticket via &lt;code&gt;jira.create_issue&lt;/code&gt;, linking back to the diff.&lt;/li&gt;
&lt;li&gt;It posts a summary to Slack via &lt;code&gt;slack.send_message&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Six tool calls. &lt;/p&gt;

&lt;p&gt;Four different upstream MCP servers. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One endpoint.&lt;/strong&gt; Every call authenticated. Every call logged to the audit trail. &lt;/p&gt;

&lt;p&gt;The single dangerous tool the agent isn't supposed to touch, even if a prompt injection convinces it to try it isn't &lt;em&gt;prompted against&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;It's simply &lt;strong&gt;not in the Virtual MCP Server&lt;/strong&gt;, so calling it is a 404, not a judgment call.&lt;/p&gt;

&lt;p&gt;That, to me, is the jump from protocol to platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;MCP gave us a clean, shared language for AI agents to talk to tools. &lt;/p&gt;

&lt;p&gt;That's a big deal, and it's easy to underrate how much of a pain this was &lt;em&gt;before&lt;/em&gt; MCP existed.&lt;/p&gt;

&lt;p&gt;But a shared language isn't a shared policy. &lt;/p&gt;

&lt;p&gt;If you're running more than one agent, or letting more than one team build agents, you will need the thing that sits between "call the tool" and "did we mean to let it call the tool." &lt;/p&gt;

&lt;p&gt;That thing is a gateway.&lt;/p&gt;

&lt;p&gt;You can build a toy version in an afternoon. &lt;/p&gt;

&lt;p&gt;My demo repo is proof. &lt;/p&gt;

&lt;p&gt;But for anything real — auth, RBAC, audit, per-scope capability boundaries, and the Virtual MCP Server trick  you want a platform that treats governance as the product, not the afterthought.&lt;/p&gt;

&lt;p&gt;Take a look at &lt;a href="https://www.truefoundry.com/" rel="noopener noreferrer"&gt;TrueFoundry's MCP Gateway&lt;/a&gt; and the Virtual MCP Server feature if you're at the "I'm giving real agents real tools and someone in security wants to talk to me" stage.&lt;/p&gt;

&lt;p&gt;If you build something interesting on top of either, I'd love to see it. Happy gatewaying.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>ai</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Triggers in SQLite: Automating Logic Inside Your Database</title>
      <dc:creator>Athreya aka Maneshwar</dc:creator>
      <pubDate>Tue, 14 Apr 2026 18:19:58 +0000</pubDate>
      <link>https://forem.com/lovestaco/triggers-in-sqlite-automating-logic-inside-your-database-301b</link>
      <guid>https://forem.com/lovestaco/triggers-in-sqlite-automating-logic-inside-your-database-301b</guid>
      <description>&lt;p&gt;&lt;em&gt;Hello, I'm Maneshwar. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/em&gt;&lt;/p&gt; 

&lt;p&gt;So far, we’ve looked at how SQLite lets you query smarter (subqueries), structure cleaner (views), and control IDs (autoincrement).&lt;/p&gt;

&lt;p&gt;Now we move into something more powerful—something that lets your database react automatically.&lt;/p&gt;

&lt;p&gt;That’s where triggers come in.&lt;/p&gt;

&lt;p&gt;A trigger is code that runs automatically when something happens in your database.&lt;/p&gt;

&lt;p&gt;You don’t call it.&lt;br&gt;
You don’t manually execute it.&lt;br&gt;
It just runs behind the scenes.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Three Parts of a Trigger
&lt;/h2&gt;

&lt;p&gt;Every trigger is built on three things:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Event (When it runs)
&lt;/h3&gt;

&lt;p&gt;This is what activates the trigger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INSERT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UPDATE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2. Condition (Should it run?)
&lt;/h3&gt;

&lt;p&gt;An optional check using a &lt;code&gt;WHEN&lt;/code&gt; clause.&lt;/p&gt;

&lt;p&gt;If the condition is false → trigger does nothing.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Action (What it does)
&lt;/h3&gt;

&lt;p&gt;The actual SQL logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INSERT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UPDATE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SELECT&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Real-World Use Case: Preventing Invalid Data
&lt;/h2&gt;

&lt;p&gt;Imagine you're managing a banking system. &lt;/p&gt;

&lt;p&gt;You don’t want a user’s account balance to go negative accidentally. &lt;/p&gt;

&lt;p&gt;Instead of relying only on application code, you can enforce this rule directly in the database using a trigger.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TRIGGER&lt;/span&gt; &lt;span class="n"&gt;prevent_negative_balance&lt;/span&gt;
&lt;span class="k"&gt;BEFORE&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt;
&lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;RAISE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ABORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Balance cannot be negative'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;What’s happening here?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The trigger fires &lt;strong&gt;before&lt;/strong&gt; the balance is updated.&lt;/li&gt;
&lt;li&gt;It checks if the new balance is less than zero.&lt;/li&gt;
&lt;li&gt;If true, it aborts the operation with an error message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures your data remains consistent no matter where the update originates.&lt;/p&gt;
&lt;h2&gt;
  
  
  Keeping Track: Audit Logs with Triggers
&lt;/h2&gt;

&lt;p&gt;Another powerful use of triggers is maintaining an audit trail. &lt;/p&gt;

&lt;p&gt;For example, tracking changes made to sensitive data like salaries or account details.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TRIGGER&lt;/span&gt; &lt;span class="n"&gt;log_salary_update&lt;/span&gt;
&lt;span class="k"&gt;AFTER&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;employees&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;salary_audit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employee_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old_salary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_salary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;change_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;OLD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;OLD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'now'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now every time a salary is updated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The old and new values are recorded&lt;/li&gt;
&lt;li&gt;You get a timestamp of the change&lt;/li&gt;
&lt;li&gt;No manual logging required!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  When Triggers Go Wrong
&lt;/h2&gt;

&lt;p&gt;While triggers are powerful, they can also introduce complexity if not used carefully.&lt;/p&gt;

&lt;p&gt;Here are a few pitfalls to watch out for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hidden logic&lt;/strong&gt;: Since triggers run automatically, it can be hard to debug unexpected behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance impact&lt;/strong&gt;: Multiple triggers on large datasets can slow down operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursive triggers&lt;/strong&gt;: A trigger that modifies a table may unintentionally fire another trigger, creating loops.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best practice: Keep triggers simple, focused, and well-documented.&lt;/p&gt;

&lt;p&gt;Triggers are like invisible guardians of your database, they watch, react, and enforce rules without being explicitly called. &lt;/p&gt;

&lt;p&gt;When used wisely, they reduce redundancy, improve consistency, and make your system more robust.&lt;/p&gt;

&lt;p&gt;But like any powerful tool, they demand discipline. &lt;/p&gt;

&lt;p&gt;Overuse or misuse can lead to confusion and performance issues. &lt;/p&gt;

&lt;p&gt;The key is balance: use triggers where they shine, and keep your logic transparent and maintainable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&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%2Fyzvpkxm9mga1pweneahx.png" alt="git-lrc" width="800" height="109"&gt;&lt;/a&gt; &lt;br&gt;
 *AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production. &lt;/p&gt;

&lt;p&gt;git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.* &lt;/p&gt;

&lt;p&gt;Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use. &lt;/p&gt;

&lt;p&gt;⭐ Star it on GitHub: &lt;br&gt;
 &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HexmosTech" rel="noopener noreferrer"&gt;
        HexmosTech
      &lt;/a&gt; / &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;
        git-lrc
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      AI Micro Code Reviews That Run on Commit
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;p&gt;| &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.da.md" rel="noopener noreferrer"&gt;🇩🇰 Dansk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.es.md" rel="noopener noreferrer"&gt;🇪🇸 Español&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fa.md" rel="noopener noreferrer"&gt;🇮🇷 Farsi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fi.md" rel="noopener noreferrer"&gt;🇫🇮 Suomi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ja.md" rel="noopener noreferrer"&gt;🇯🇵 日本語&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.nn.md" rel="noopener noreferrer"&gt;🇳🇴 Norsk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.pt.md" rel="noopener noreferrer"&gt;🇵🇹 Português&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ru.md" rel="noopener noreferrer"&gt;🇷🇺 Русский&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.sq.md" rel="noopener noreferrer"&gt;🇦🇱 Shqip&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.zh.md" rel="noopener noreferrer"&gt;🇨🇳 中文&lt;/a&gt; |&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;img width="60" alt="git-lrc logo" src="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;/a&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;git-lrc&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;AI Micro Code Reviews That Run on Commit&lt;/h2&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.producthunt.com/products/git-lrc?embed=true&amp;amp;utm_source=badge-top-post-badge&amp;amp;utm_medium=badge&amp;amp;utm_campaign=badge-git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt" width="200" src="https://camo.githubusercontent.com/87bf2d4283c1e0aa99e254bd17fefb1c67c0c0d39300043a243a4aa633b6cecc/68747470733a2f2f6170692e70726f6475637468756e742e636f6d2f776964676574732f656d6265642d696d6167652f76312f746f702d706f73742d62616467652e7376673f706f73745f69643d31303739323632267468656d653d6c6967687426706572696f643d6461696c7926743d31373731373439313730383638"&gt;&lt;/a&gt;
 &lt;/p&gt;
&lt;br&gt;
&lt;a href="https://discord.gg/sGdnKwB3qq" rel="nofollow noopener noreferrer"&gt;
  &lt;img alt="Discord Community" src="https://camo.githubusercontent.com/b8f979318aaabc8dec512b9d4e6e2a12431fba3c8a3b8738e1a97a0722d4e4bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d436f6d6d756e6974792d3538363546323f6c6f676f3d646973636f7264266c6162656c436f6c6f723d7768697465"&gt;
&lt;/a&gt; &lt;a href="https://goreportcard.com/report/github.com/HexmosTech/git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Go Report Card" src="https://camo.githubusercontent.com/e74c0651c3ee9165a2ed01cb0f6842c494029960df30eb9c24cf622d3d21bf46/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f4865786d6f73546563682f6769742d6c7263"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml" rel="noopener noreferrer"&gt;&lt;img alt="gitleaks.yml" title="gitleaks.yml: Secret scanning workflow" src="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml" rel="noopener noreferrer"&gt;&lt;img alt="osv-scanner.yml" title="osv-scanner.yml: Dependency vulnerability scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml" rel="noopener noreferrer"&gt;&lt;img alt="govulncheck.yml" title="govulncheck.yml: Go vulnerability check" src="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml" rel="noopener noreferrer"&gt;&lt;img alt="semgrep.yml" title="semgrep.yml: Static analysis security scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml/badge.svg"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer" href="https://github.com/HexmosTech/git-lrc/./gfx/dependabot-enabled.svg"&gt;&lt;img alt="dependabot-enabled" title="dependabot-enabled: Automated dependency updates are enabled" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FHexmosTech%2Fgit-lrc%2FHEAD%2F.%2Fgfx%2Fdependabot-enabled.svg"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;p&gt;AI agents write code fast. They also &lt;em&gt;silently remove logic&lt;/em&gt;, change behavior, and introduce bugs -- without telling you. You often find out in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;git-lrc&lt;/code&gt; fixes this.&lt;/strong&gt; It hooks into &lt;code&gt;git commit&lt;/code&gt; and reviews every diff &lt;em&gt;before&lt;/em&gt; it lands. 60-second setup. Completely free.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;See It In Action&lt;/h2&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;See git-lrc catch serious security issues such as leaked credentials, expensive cloud
operations, and sensitive material in log statements&lt;/p&gt;
&lt;/blockquote&gt;

  
    
    

    &lt;span class="m-1"&gt;git-lrc-intro-60s.mp4&lt;/span&gt;
    
  

  

  


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI agents silently break things.&lt;/strong&gt; Code removed. Logic changed. Edge cases gone. You won't notice until production.&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Catch it before it ships.&lt;/strong&gt; AI-powered inline comments show you &lt;em&gt;exactly&lt;/em&gt; what changed and what looks wrong.&lt;/li&gt;
&lt;li&gt;🔁 &lt;strong&gt;Build a habit,&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>architecture</category>
      <category>database</category>
    </item>
    <item>
      <title>What's an AI Gateway and do you think you need one?</title>
      <dc:creator>Athreya aka Maneshwar</dc:creator>
      <pubDate>Mon, 13 Apr 2026 15:52:46 +0000</pubDate>
      <link>https://forem.com/lovestaco/whats-an-ai-gateway-and-do-you-think-you-need-one-39c1</link>
      <guid>https://forem.com/lovestaco/whats-an-ai-gateway-and-do-you-think-you-need-one-39c1</guid>
      <description>&lt;p&gt;It usually starts simple.&lt;/p&gt;

&lt;p&gt;You're building a feature in  your team with an AI feature in the product.&lt;/p&gt;

&lt;p&gt;One API call to OpenAI. Maybe wrapped in a small helper function. You ship a feature. It works. Then things start creeping in.&lt;/p&gt;

&lt;p&gt;Another team wants to use it. Someone adds a second model. Now you’ve got API keys sitting in different repos. &lt;/p&gt;

&lt;p&gt;Nobody’s really tracking usage. Finance asks how much you're spending on AI this month, you don’t have a clear answer which team is using how much. &lt;/p&gt;

&lt;p&gt;Then security shows up asking where prompts and responses are going what are the guardrails list and share it with us.&lt;/p&gt;

&lt;p&gt;And at some point, a provider slows down or goes down, and suddenly your app is stuck waiting on a single dependency you don’t control.&lt;/p&gt;

&lt;p&gt;Now you’ve got:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple teams calling different models&lt;/li&gt;
&lt;li&gt;No centralized control&lt;/li&gt;
&lt;li&gt;No clear cost visibility&lt;/li&gt;
&lt;li&gt;Zero guardrails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is usually the moment people start searching:&lt;br&gt;
&lt;strong&gt;“Do I actually need an AI gateway?”&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What an AI Gateway Actually Is (Without the Buzzwords)
&lt;/h2&gt;

&lt;p&gt;If you’ve worked with backend systems, you already know how an API Gateway works.&lt;/p&gt;

&lt;p&gt;It sits in front of your services and handles things like routing, authentication, rate limiting, and observability,  so your services don’t have to deal with that themselves.&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.amazonaws.com%2Fuploads%2Farticles%2F8m7uq8hrsm7fqx84loen.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.amazonaws.com%2Fuploads%2Farticles%2F8m7uq8hrsm7fqx84loen.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An &lt;a href="https://www.ibm.com/think/topics/ai-gateway" rel="noopener noreferrer"&gt;AI Gateway&lt;/a&gt; works in a very similar way.&lt;/p&gt;

&lt;p&gt;But instead of sitting in front of microservices, it sits in front of your model providers.&lt;/p&gt;

&lt;p&gt;At its core, an AI Gateway is just a layer between your application and the LLM APIs you’re calling.&lt;/p&gt;

&lt;p&gt;Instead of your app directly hitting providers like OpenAI or Anthropic, every request goes through this gateway first.&lt;/p&gt;

&lt;p&gt;That one change unlocks a lot.&lt;/p&gt;

&lt;p&gt;Now you have a single place that can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Route requests across different models&lt;/li&gt;
&lt;li&gt;Handle authentication centrally&lt;/li&gt;
&lt;li&gt;Enforce rate limits&lt;/li&gt;
&lt;li&gt;Track usage and cost at a detailed level (tokens, not just requests)&lt;/li&gt;
&lt;li&gt;Apply guardrails on inputs and outputs&lt;/li&gt;
&lt;li&gt;Give you visibility into what’s actually happening&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most teams don’t start here though.&lt;/p&gt;

&lt;p&gt;They usually go through this progression:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Raw SDKs&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;You use something like the OpenAI SDK. Quick to set up, works great, as long as it’s just one team and one use case.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Simple proxies (like &lt;a href="https://www.litellm.ai/" rel="noopener noreferrer"&gt;LiteLLM&lt;/a&gt;)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;You add a thin layer to route between models. Helps a bit, but governance, security, and cost tracking are still pretty limited.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. AI Gateway&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;This is where things become structured. Instead of every team doing their own thing, you now have a centralized control plane managing how AI is used across your org.&lt;/p&gt;

&lt;p&gt;The key difference isn’t just routing, it’s understanding.&lt;/p&gt;

&lt;p&gt;An API Gateway can tell you:&lt;br&gt;
“this service got 10,000 requests.”&lt;/p&gt;

&lt;p&gt;An AI Gateway can tell you:&lt;br&gt;
“this team used 4M tokens on GPT-4, spent $X, and triggered guardrails 3 times.”&lt;/p&gt;

&lt;p&gt;Without it, your AI usage grows organically (read: chaotically).&lt;br&gt;
With it, you can actually manage it.&lt;/p&gt;

&lt;h2&gt;
  
  
  So… do you actually need one?
&lt;/h2&gt;

&lt;p&gt;This is the part most people overcomplicate.&lt;/p&gt;

&lt;p&gt;You don’t need a framework. You don’t need a 10-step checklist.&lt;/p&gt;

&lt;p&gt;You just need to be honest about how your setup actually looks today, not how you &lt;em&gt;think&lt;/em&gt; it looks.&lt;/p&gt;

&lt;h3&gt;
  
  
  You probably don’t need one (yet)
&lt;/h3&gt;

&lt;p&gt;If your world is still pretty contained, you’re fine.&lt;/p&gt;

&lt;p&gt;One team building one feature, calling one model, with a bill that’s small enough that nobody’s asking questions, this kind of setup doesn’t need extra infrastructure yet. &lt;/p&gt;

&lt;p&gt;Seriously.&lt;/p&gt;

&lt;p&gt;Adding an AI Gateway here is like adding Kubernetes to a side project.&lt;br&gt;
You &lt;em&gt;can&lt;/em&gt; do it. You probably shouldn’t.&lt;/p&gt;

&lt;p&gt;Just ship.&lt;/p&gt;

&lt;h3&gt;
  
  
  You &lt;em&gt;do&lt;/em&gt; need one (or you’re about to)
&lt;/h3&gt;

&lt;p&gt;Now flip it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multiple teams are using LLMs independently&lt;/li&gt;
&lt;li&gt;you’re juggling OpenAI + Anthropic (or thinking about it)&lt;/li&gt;
&lt;li&gt;someone from compliance said words like “HIPAA”, “GDPR”, “SOC 2”, blah, blah, blah...&lt;/li&gt;
&lt;/ul&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.amazonaws.com%2Fuploads%2Farticles%2F7daf5xajvdc4zth09sdg.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.amazonaws.com%2Fuploads%2Farticles%2F7daf5xajvdc4zth09sdg.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;finance asked for a breakdown and you gave them… vibes&lt;/li&gt;
&lt;li&gt;you’ve had that one moment where you thought:
“wait… did we just send something sensitive to an LLM?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And then there’s that subtle moment where you realize something could go wrong.&lt;/p&gt;

&lt;p&gt;Maybe you don’t know exactly what’s being sent in prompts. Maybe logs are incomplete. Maybe you’re not sure how to stop a bad request before it reaches the model.&lt;/p&gt;

&lt;p&gt;That’s usually the signal.&lt;/p&gt;

&lt;p&gt;You don’t feel like you’re running “complex infrastructure,” but the problems you’re dealing with are already infrastructure problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a production AI setup actually looks like
&lt;/h2&gt;

&lt;p&gt;This is where things stop being “a few API calls” and start looking like a system.&lt;/p&gt;

&lt;p&gt;Recently, I came across TrueFoundry while digging into how teams handle this at scale, and it’s a pretty good example of what this setup looks like in practice.&lt;/p&gt;

&lt;p&gt;Instead of every team managing their own keys and integrations, everything goes through one layer. That one change removes a surprising amount of chaos.&lt;/p&gt;

&lt;p&gt;So now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;there’s a &lt;strong&gt;single API key&lt;/strong&gt; internally
(teams don’t touch provider credentials anymore)&lt;/li&gt;
&lt;li&gt;you can set &lt;strong&gt;budgets and rate limits per team&lt;/strong&gt;
so one experiment doesn’t accidentally burn your entire budget&lt;/li&gt;
&lt;li&gt;if OpenAI slows down, you can &lt;strong&gt;fallback to Anthropic automatically&lt;/strong&gt;
instead of your feature just breaking&lt;/li&gt;
&lt;li&gt;every request is &lt;strong&gt;tracked&lt;/strong&gt;
prompt, response, tokens, cost — all of it&lt;/li&gt;
&lt;li&gt;you can add &lt;strong&gt;guardrails&lt;/strong&gt;
PII filtering, prompt injection checks, whatever your security team keeps asking about&lt;/li&gt;
&lt;li&gt;and the whole thing can run in your &lt;strong&gt;own VPC / on-prem&lt;/strong&gt;
so data isn’t flying around random third-party infra&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Performance wise, this isn’t some heavy layer either.&lt;/p&gt;

&lt;p&gt;We’re talking about handling 350+ requests per second on a single vCPU with sub-3ms latency, which means it adds control without slowing things down in any meaningful way.&lt;/p&gt;

&lt;p&gt;Also worth noting, this space is becoming real infra, not just hacks.&lt;/p&gt;

&lt;p&gt;Tools like this are already showing up in places like the &lt;a href="https://www.gartner.com/en/documents/7051698" rel="noopener noreferrer"&gt;Gartner Market Guide for AI Gateways&lt;/a&gt;, which is usually a signal that “okay, this is a category now”.&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.amazonaws.com%2Fuploads%2Farticles%2Fb6wc1frp3j29a6u9j7s4.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.amazonaws.com%2Fuploads%2Farticles%2Fb6wc1frp3j29a6u9j7s4.png" alt=" " width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The boring but real conclusion
&lt;/h2&gt;

&lt;p&gt;Most teams don’t wake up and say:&lt;/p&gt;

&lt;p&gt;“today we implement an AI Gateway”&lt;/p&gt;

&lt;p&gt;They get pushed into it by problems.&lt;/p&gt;

&lt;p&gt;If you read the earlier section and thought:&lt;/p&gt;

&lt;p&gt;“yeah… we’re kinda there already”&lt;/p&gt;

&lt;p&gt;Then you probably are.&lt;/p&gt;

&lt;p&gt;And the tradeoff is simple:&lt;br&gt;
You either spend a bit of time setting up structure now, or you keep paying for it later in the form of confusion, rising costs, and occasional fire drills that nobody enjoys dealing with.&lt;/p&gt;

&lt;p&gt;Pick your pain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it (if you’re already feeling the pain)
&lt;/h2&gt;

&lt;p&gt;At this point, you can keep patching things together… or just try something like &lt;a href="https://www.truefoundry.com/?ref=dev.to"&gt;TrueFoundry&lt;/a&gt; and see what a structured setup actually feels like.&lt;/p&gt;

&lt;p&gt;You can get it running in your own cloud pretty quickly, without needing a long setup process or even a credit card.&lt;/p&gt;

&lt;p&gt;Even if you decide not to stick with it, going through the process once will give you a much clearer picture of what’s missing in your current setup.&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.amazonaws.com%2Fuploads%2Farticles%2Fcytr8655q6xavu7t2kot.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.amazonaws.com%2Fuploads%2Farticles%2Fcytr8655q6xavu7t2kot.png" alt=" " width="600" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>AUTOINCREMENT in SQLite</title>
      <dc:creator>Athreya aka Maneshwar</dc:creator>
      <pubDate>Sun, 12 Apr 2026 17:45:35 +0000</pubDate>
      <link>https://forem.com/lovestaco/autoincrement-in-sqlite-5642</link>
      <guid>https://forem.com/lovestaco/autoincrement-in-sqlite-5642</guid>
      <description>&lt;p&gt;&lt;em&gt;Hello, I'm Maneshwar. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/em&gt;&lt;/p&gt; 

&lt;p&gt;When working with SQLite, generating unique IDs is something you deal with almost immediately. &lt;/p&gt;

&lt;p&gt;Most developers assume that &lt;code&gt;AUTOINCREMENT&lt;/code&gt; is required for this, but SQLite already handles auto-incrementing behavior by default in a slightly different way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Default Auto-Increment Behavior
&lt;/h2&gt;

&lt;p&gt;If you define a column like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;SQLite will automatically assign values to &lt;code&gt;a&lt;/code&gt; whenever you insert &lt;code&gt;NULL&lt;/code&gt; or don’t provide a value at all.&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 sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In most cases, SQLite assigns a value that is &lt;strong&gt;one greater than the current maximum&lt;/strong&gt; in that column. If the table is empty, it starts from &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This makes it feel like standard auto-increment behavior, and for many applications, this is more than enough.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Subtle Catch
&lt;/h2&gt;

&lt;p&gt;The important detail is that SQLite only guarantees &lt;strong&gt;current uniqueness&lt;/strong&gt;, not historical uniqueness.&lt;/p&gt;

&lt;p&gt;If you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Insert rows → 1, 2, 3&lt;/li&gt;
&lt;li&gt;Delete row with ID 3&lt;/li&gt;
&lt;li&gt;Insert again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SQLite &lt;strong&gt;may reuse 3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is not a bug. It is simply how SQLite optimizes ID generation. &lt;/p&gt;

&lt;p&gt;It avoids keeping extra state and just looks at existing values.&lt;/p&gt;

&lt;p&gt;For internal systems, this usually doesn’t matter. But if IDs are exposed outside (like APIs or logs), reuse can create confusion.&lt;/p&gt;
&lt;h2&gt;
  
  
  What AUTOINCREMENT Actually Does
&lt;/h2&gt;

&lt;p&gt;When you explicitly use:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="n"&gt;AUTOINCREMENT&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;SQLite switches to a stricter strategy.&lt;/p&gt;

&lt;p&gt;Now, instead of checking the current max value, it remembers the &lt;strong&gt;largest value ever used&lt;/strong&gt; and always generates a new value greater than that.&lt;/p&gt;

&lt;p&gt;So even if you delete rows, old IDs are never reused.&lt;/p&gt;

&lt;p&gt;This gives you a stronger guarantee:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IDs are unique across the entire lifetime of the table&lt;/li&gt;
&lt;li&gt;No accidental reuse&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Role of sqlite_sequence
&lt;/h2&gt;

&lt;p&gt;To make this work, SQLite maintains a special internal table called &lt;code&gt;sqlite_sequence&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Table name&lt;/li&gt;
&lt;li&gt;Highest ID ever used&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This table is created automatically when you first insert into a table that uses &lt;code&gt;AUTOINCREMENT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each new insert updates this value so SQLite always knows what comes next.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Not Always Use AUTOINCREMENT?
&lt;/h2&gt;

&lt;p&gt;At first glance, &lt;code&gt;AUTOINCREMENT&lt;/code&gt; seems like the safer option. But it comes with tradeoffs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It adds a small performance overhead&lt;/li&gt;
&lt;li&gt;It requires maintaining extra state (&lt;code&gt;sqlite_sequence&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;It prevents reuse, which may not always be necessary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, SQLite has a limit on integer values. If the maximum value is ever reached, further inserts will fail.&lt;/p&gt;

&lt;p&gt;SQLite already gives you auto-incrementing IDs without needing &lt;code&gt;AUTOINCREMENT&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The keyword is only for stricter guarantees, not basic functionality.&lt;/p&gt;

&lt;p&gt;Instead of blindly adding &lt;code&gt;AUTOINCREMENT&lt;/code&gt;, you choose it only when your system actually needs that level of consistency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&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%2Fyzvpkxm9mga1pweneahx.png" alt="git-lrc" width="800" height="109"&gt;&lt;/a&gt; &lt;br&gt;
 *AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production. &lt;/p&gt;

&lt;p&gt;git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.* &lt;/p&gt;

&lt;p&gt;Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use. &lt;/p&gt;

&lt;p&gt;⭐ Star it on GitHub: &lt;br&gt;
 &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HexmosTech" rel="noopener noreferrer"&gt;
        HexmosTech
      &lt;/a&gt; / &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;
        git-lrc
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      AI Micro Code Reviews That Run on Commit
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;p&gt;| &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.da.md" rel="noopener noreferrer"&gt;🇩🇰 Dansk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.es.md" rel="noopener noreferrer"&gt;🇪🇸 Español&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fa.md" rel="noopener noreferrer"&gt;🇮🇷 Farsi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fi.md" rel="noopener noreferrer"&gt;🇫🇮 Suomi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ja.md" rel="noopener noreferrer"&gt;🇯🇵 日本語&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.nn.md" rel="noopener noreferrer"&gt;🇳🇴 Norsk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.pt.md" rel="noopener noreferrer"&gt;🇵🇹 Português&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ru.md" rel="noopener noreferrer"&gt;🇷🇺 Русский&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.sq.md" rel="noopener noreferrer"&gt;🇦🇱 Shqip&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.zh.md" rel="noopener noreferrer"&gt;🇨🇳 中文&lt;/a&gt; |&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;img width="60" alt="git-lrc logo" src="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;/a&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;git-lrc&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;AI Micro Code Reviews That Run on Commit&lt;/h2&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.producthunt.com/products/git-lrc?embed=true&amp;amp;utm_source=badge-top-post-badge&amp;amp;utm_medium=badge&amp;amp;utm_campaign=badge-git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt" width="200" src="https://camo.githubusercontent.com/87bf2d4283c1e0aa99e254bd17fefb1c67c0c0d39300043a243a4aa633b6cecc/68747470733a2f2f6170692e70726f6475637468756e742e636f6d2f776964676574732f656d6265642d696d6167652f76312f746f702d706f73742d62616467652e7376673f706f73745f69643d31303739323632267468656d653d6c6967687426706572696f643d6461696c7926743d31373731373439313730383638"&gt;&lt;/a&gt;
 &lt;/p&gt;
&lt;br&gt;
&lt;a href="https://discord.gg/sGdnKwB3qq" rel="nofollow noopener noreferrer"&gt;
  &lt;img alt="Discord Community" src="https://camo.githubusercontent.com/b8f979318aaabc8dec512b9d4e6e2a12431fba3c8a3b8738e1a97a0722d4e4bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d436f6d6d756e6974792d3538363546323f6c6f676f3d646973636f7264266c6162656c436f6c6f723d7768697465"&gt;
&lt;/a&gt; &lt;a href="https://goreportcard.com/report/github.com/HexmosTech/git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Go Report Card" src="https://camo.githubusercontent.com/e74c0651c3ee9165a2ed01cb0f6842c494029960df30eb9c24cf622d3d21bf46/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f4865786d6f73546563682f6769742d6c7263"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml" rel="noopener noreferrer"&gt;&lt;img alt="gitleaks.yml" title="gitleaks.yml: Secret scanning workflow" src="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml" rel="noopener noreferrer"&gt;&lt;img alt="osv-scanner.yml" title="osv-scanner.yml: Dependency vulnerability scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml" rel="noopener noreferrer"&gt;&lt;img alt="govulncheck.yml" title="govulncheck.yml: Go vulnerability check" src="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml" rel="noopener noreferrer"&gt;&lt;img alt="semgrep.yml" title="semgrep.yml: Static analysis security scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml/badge.svg"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer" href="https://github.com/HexmosTech/git-lrc/./gfx/dependabot-enabled.svg"&gt;&lt;img alt="dependabot-enabled" title="dependabot-enabled: Automated dependency updates are enabled" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FHexmosTech%2Fgit-lrc%2FHEAD%2F.%2Fgfx%2Fdependabot-enabled.svg"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;p&gt;AI agents write code fast. They also &lt;em&gt;silently remove logic&lt;/em&gt;, change behavior, and introduce bugs -- without telling you. You often find out in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;git-lrc&lt;/code&gt; fixes this.&lt;/strong&gt; It hooks into &lt;code&gt;git commit&lt;/code&gt; and reviews every diff &lt;em&gt;before&lt;/em&gt; it lands. 60-second setup. Completely free.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;See It In Action&lt;/h2&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;See git-lrc catch serious security issues such as leaked credentials, expensive cloud
operations, and sensitive material in log statements&lt;/p&gt;
&lt;/blockquote&gt;

  
    
    

    &lt;span class="m-1"&gt;git-lrc-intro-60s.mp4&lt;/span&gt;
    
  

  

  


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI agents silently break things.&lt;/strong&gt; Code removed. Logic changed. Edge cases gone. You won't notice until production.&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Catch it before it ships.&lt;/strong&gt; AI-powered inline comments show you &lt;em&gt;exactly&lt;/em&gt; what changed and what looks wrong.&lt;/li&gt;
&lt;li&gt;🔁 &lt;strong&gt;Build a habit,&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>architecture</category>
      <category>database</category>
    </item>
    <item>
      <title>Subqueries &amp; Views in SQLite: Writing Smarter, Cleaner Queries</title>
      <dc:creator>Athreya aka Maneshwar</dc:creator>
      <pubDate>Sat, 11 Apr 2026 19:52:43 +0000</pubDate>
      <link>https://forem.com/lovestaco/subqueries-views-in-sqlite-writing-smarter-cleaner-queries-5399</link>
      <guid>https://forem.com/lovestaco/subqueries-views-in-sqlite-writing-smarter-cleaner-queries-5399</guid>
      <description>&lt;p&gt;&lt;em&gt;Hello, I'm Maneshwar. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/em&gt;&lt;/p&gt; 

&lt;p&gt;In the previous discussion, we explored how PRAGMA gives you control over SQLite’s internal behavior. &lt;/p&gt;

&lt;p&gt;Now, let’s see how you actually &lt;strong&gt;structure smarter queries&lt;/strong&gt; using &lt;strong&gt;subqueries&lt;/strong&gt; and &lt;strong&gt;views&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;These aren’t just SQL features. &lt;/p&gt;

&lt;p&gt;They’re tools that help you write cleaner logic, reduce duplication, and make your database easier to work with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subqueries: Queries Inside Queries
&lt;/h2&gt;

&lt;p&gt;At its core, a basic SQL query looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;x&lt;/code&gt; → columns&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;y&lt;/code&gt; → tables&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;z&lt;/code&gt; → condition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now here’s where things get interesting:&lt;br&gt;
That &lt;code&gt;z&lt;/code&gt; (the condition) can itself contain another query.&lt;/p&gt;

&lt;p&gt;That’s a &lt;strong&gt;subquery&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  A Simple Subquery Example
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Students&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;sid&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;sid&lt;/span&gt; 
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Admitted_to&lt;/span&gt; 
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;doj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Jan 01, 2000'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;What’s happening here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inner query → finds student IDs admitted on a specific date&lt;/li&gt;
&lt;li&gt;Outer query → fetches names of those students&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The inner query runs first, then feeds results into the outer query.&lt;/p&gt;
&lt;h3&gt;
  
  
  Where You Can Use Subqueries
&lt;/h3&gt;

&lt;p&gt;Subqueries aren’t limited to &lt;code&gt;WHERE&lt;/code&gt;. You can use them in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;WHERE&lt;/code&gt; clause (most common)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FROM&lt;/code&gt; clause (as derived tables)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;HAVING&lt;/code&gt; clause (with grouped data)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They act like &lt;strong&gt;temporary datasets&lt;/strong&gt; inside your query.&lt;/p&gt;
&lt;h3&gt;
  
  
  Correlated Subqueries: When Things Get Dynamic
&lt;/h3&gt;

&lt;p&gt;Now we step into more advanced territory.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;correlated subquery&lt;/strong&gt; is one that depends on the outer query.&lt;/p&gt;
&lt;h4&gt;
  
  
  Example:
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Students&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; 
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Admitted_to&lt;/span&gt; 
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;sid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sid&lt;/span&gt; 
    &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;doj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Jan 01, 2000'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  What’s different here?
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The inner query references &lt;code&gt;Students.sid&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;That means it &lt;strong&gt;cannot run independently&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;It depends on each row from the outer query&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  How Correlated Subqueries Actually Execute
&lt;/h3&gt;

&lt;p&gt;This is where many people misunderstand what’s happening.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;each row&lt;/strong&gt; in &lt;code&gt;Students&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SQLite takes that row’s &lt;code&gt;sid&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Substitutes it into the subquery&lt;/li&gt;
&lt;li&gt;Executes the subquery&lt;/li&gt;
&lt;li&gt;Decides whether to include that row&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So instead of running once, the subquery runs &lt;strong&gt;multiple times&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This makes correlated subqueries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Powerful&lt;/li&gt;
&lt;li&gt;But potentially slower&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  When to Use Subqueries (and When Not To)
&lt;/h3&gt;

&lt;p&gt;Use them when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want clear, readable logic&lt;/li&gt;
&lt;li&gt;You need intermediate filtering&lt;/li&gt;
&lt;li&gt;You’re avoiding complex joins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid them when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance is critical&lt;/li&gt;
&lt;li&gt;A join can do the same job more efficiently&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Views: Virtual Tables That Simplify Everything
&lt;/h2&gt;

&lt;p&gt;If subqueries are about &lt;em&gt;embedding logic&lt;/em&gt;, views are about &lt;em&gt;reusing it&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;view&lt;/strong&gt; is basically a &lt;strong&gt;saved query&lt;/strong&gt; that behaves like a table.&lt;/p&gt;

&lt;p&gt;But here’s the key detail:&lt;/p&gt;

&lt;p&gt;A view does &lt;strong&gt;not store data&lt;/strong&gt;&lt;br&gt;
 It stores only the query definition&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating a View
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;view1&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; 
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sid&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Students&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This doesn’t create a new table.&lt;/p&gt;

&lt;p&gt;Instead, SQLite stores the query definition internally.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using a View
&lt;/h3&gt;

&lt;p&gt;Once created, you can query it like a normal table:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;view1&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;sid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQLite runs the original query&lt;/li&gt;
&lt;li&gt;Then applies your new query on top&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Why Views Exist (And Why You Should Care)
&lt;/h3&gt;

&lt;p&gt;Views solve real problems:&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Simplify Complex Queries
&lt;/h4&gt;

&lt;p&gt;Instead of repeating a long query everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write it once as a view&lt;/li&gt;
&lt;li&gt;Reuse it everywhere&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  2. Hide Complexity
&lt;/h4&gt;

&lt;p&gt;You can expose only what users need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hide joins&lt;/li&gt;
&lt;li&gt;Hide sensitive columns&lt;/li&gt;
&lt;li&gt;Present clean datasets&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  3. Provide Schema Independence
&lt;/h4&gt;

&lt;p&gt;If your base table changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your view may still work unchanged&lt;/li&gt;
&lt;li&gt;Applications using the view stay stable&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Temporary Views
&lt;/h3&gt;

&lt;p&gt;SQLite also allows temporary views:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TEMP&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;temp_view&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; 
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Students&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Exists only during the session&lt;/li&gt;
&lt;li&gt;Automatically deleted when connection closes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;li&gt;Intermediate processing&lt;/li&gt;
&lt;li&gt;Session-based logic&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The Catch: Views in SQLite Are Read-Only
&lt;/h3&gt;

&lt;p&gt;Unlike some databases, SQLite does &lt;strong&gt;not allow direct updates&lt;/strong&gt; on views.&lt;/p&gt;

&lt;p&gt;So these won’t work:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;view1&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;view1&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;view1&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you need updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You must use &lt;strong&gt;triggers&lt;/strong&gt; on the view&lt;/li&gt;
&lt;li&gt;Those triggers then modify base tables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&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%2Fyzvpkxm9mga1pweneahx.png" alt="git-lrc" width="800" height="109"&gt;&lt;/a&gt; &lt;br&gt;
 *AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production. &lt;/p&gt;

&lt;p&gt;git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.* &lt;/p&gt;

&lt;p&gt;Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use. &lt;/p&gt;

&lt;p&gt;⭐ Star it on GitHub: &lt;br&gt;
 &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HexmosTech" rel="noopener noreferrer"&gt;
        HexmosTech
      &lt;/a&gt; / &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;
        git-lrc
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      AI Micro Code Reviews That Run on Commit
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;p&gt;| &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.da.md" rel="noopener noreferrer"&gt;🇩🇰 Dansk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.es.md" rel="noopener noreferrer"&gt;🇪🇸 Español&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fa.md" rel="noopener noreferrer"&gt;🇮🇷 Farsi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.fi.md" rel="noopener noreferrer"&gt;🇫🇮 Suomi&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ja.md" rel="noopener noreferrer"&gt;🇯🇵 日本語&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.nn.md" rel="noopener noreferrer"&gt;🇳🇴 Norsk&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.pt.md" rel="noopener noreferrer"&gt;🇵🇹 Português&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.ru.md" rel="noopener noreferrer"&gt;🇷🇺 Русский&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.sq.md" rel="noopener noreferrer"&gt;🇦🇱 Shqip&lt;/a&gt; | &lt;a href="https://github.com/HexmosTech/git-lrc/readme/README.zh.md" rel="noopener noreferrer"&gt;🇨🇳 中文&lt;/a&gt; |&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;img width="60" alt="git-lrc logo" src="https://camo.githubusercontent.com/948c8f2d5cf41b48985cd364d48c3a2dc9bfbfd42eab3e0a9a1b3e61f5f17ce3/68747470733a2f2f6865786d6f732e636f6d2f66726565646576746f6f6c732f7075626c69632f6c725f6c6f676f2e737667"&gt;&lt;/a&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;git-lrc&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;AI Micro Code Reviews That Run on Commit&lt;/h2&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.producthunt.com/products/git-lrc?embed=true&amp;amp;utm_source=badge-top-post-badge&amp;amp;utm_medium=badge&amp;amp;utm_campaign=badge-git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt" width="200" src="https://camo.githubusercontent.com/87bf2d4283c1e0aa99e254bd17fefb1c67c0c0d39300043a243a4aa633b6cecc/68747470733a2f2f6170692e70726f6475637468756e742e636f6d2f776964676574732f656d6265642d696d6167652f76312f746f702d706f73742d62616467652e7376673f706f73745f69643d31303739323632267468656d653d6c6967687426706572696f643d6461696c7926743d31373731373439313730383638"&gt;&lt;/a&gt;
 &lt;/p&gt;
&lt;br&gt;
&lt;a href="https://discord.gg/sGdnKwB3qq" rel="nofollow noopener noreferrer"&gt;
  &lt;img alt="Discord Community" src="https://camo.githubusercontent.com/b8f979318aaabc8dec512b9d4e6e2a12431fba3c8a3b8738e1a97a0722d4e4bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446973636f72642d436f6d6d756e6974792d3538363546323f6c6f676f3d646973636f7264266c6162656c436f6c6f723d7768697465"&gt;
&lt;/a&gt; &lt;a href="https://goreportcard.com/report/github.com/HexmosTech/git-lrc" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Go Report Card" src="https://camo.githubusercontent.com/e74c0651c3ee9165a2ed01cb0f6842c494029960df30eb9c24cf622d3d21bf46/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f4865786d6f73546563682f6769742d6c7263"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml" rel="noopener noreferrer"&gt;&lt;img alt="gitleaks.yml" title="gitleaks.yml: Secret scanning workflow" src="https://github.com/HexmosTech/git-lrc/actions/workflows/gitleaks.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml" rel="noopener noreferrer"&gt;&lt;img alt="osv-scanner.yml" title="osv-scanner.yml: Dependency vulnerability scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/osv-scanner.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml" rel="noopener noreferrer"&gt;&lt;img alt="govulncheck.yml" title="govulncheck.yml: Go vulnerability check" src="https://github.com/HexmosTech/git-lrc/actions/workflows/govulncheck.yml/badge.svg"&gt;&lt;/a&gt; &lt;a href="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml" rel="noopener noreferrer"&gt;&lt;img alt="semgrep.yml" title="semgrep.yml: Static analysis security scan" src="https://github.com/HexmosTech/git-lrc/actions/workflows/semgrep.yml/badge.svg"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer" href="https://github.com/HexmosTech/git-lrc/./gfx/dependabot-enabled.svg"&gt;&lt;img alt="dependabot-enabled" title="dependabot-enabled: Automated dependency updates are enabled" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FHexmosTech%2Fgit-lrc%2FHEAD%2F.%2Fgfx%2Fdependabot-enabled.svg"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;p&gt;AI agents write code fast. They also &lt;em&gt;silently remove logic&lt;/em&gt;, change behavior, and introduce bugs -- without telling you. You often find out in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;git-lrc&lt;/code&gt; fixes this.&lt;/strong&gt; It hooks into &lt;code&gt;git commit&lt;/code&gt; and reviews every diff &lt;em&gt;before&lt;/em&gt; it lands. 60-second setup. Completely free.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;See It In Action&lt;/h2&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;See git-lrc catch serious security issues such as leaked credentials, expensive cloud
operations, and sensitive material in log statements&lt;/p&gt;
&lt;/blockquote&gt;

  
    
    

    &lt;span class="m-1"&gt;git-lrc-intro-60s.mp4&lt;/span&gt;
    
  

  

  


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI agents silently break things.&lt;/strong&gt; Code removed. Logic changed. Edge cases gone. You won't notice until production.&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Catch it before it ships.&lt;/strong&gt; AI-powered inline comments show you &lt;em&gt;exactly&lt;/em&gt; what changed and what looks wrong.&lt;/li&gt;
&lt;li&gt;🔁 &lt;strong&gt;Build a habit,&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>database</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
