<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Enhanciar AI</title>
    <description>The latest articles on DEV Community by Enhanciar AI (@enhanciar_ai_96a4ba4877e3).</description>
    <link>https://dev.to/enhanciar_ai_96a4ba4877e3</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4138003%2F13df6fd7-d125-409f-b532-f900e97f2e64.png</url>
      <title>DEV Community: Enhanciar AI</title>
      <link>https://dev.to/enhanciar_ai_96a4ba4877e3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/enhanciar_ai_96a4ba4877e3"/>
    <language>en</language>
    <item>
      <title>How we stopped re-asking "where did we decide this?"</title>
      <dc:creator>Enhanciar AI</dc:creator>
      <pubDate>Mon, 12 Oct 2026 06:07:25 +0000</pubDate>
      <link>https://dev.to/enhanciar_ai_96a4ba4877e3/how-we-stopped-re-asking-where-did-we-decide-this-1fpk</link>
      <guid>https://dev.to/enhanciar_ai_96a4ba4877e3/how-we-stopped-re-asking-where-did-we-decide-this-1fpk</guid>
      <description>&lt;p&gt;Every team has a question that gets asked about once a week, in a slightly different form each time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Why do we retry this job three times and not five?"&lt;/li&gt;
&lt;li&gt;"Who said we'd stop supporting the old export?"&lt;/li&gt;
&lt;li&gt;"Didn't we already decide this in a call last month?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Usually somebody did decide it. The decision is real. It's just sitting in a Slack thread, a ticket comment, a meeting doc or one person's head. So the team either re-argues it from scratch, or waits for that one person to come back from lunch.&lt;/p&gt;

&lt;p&gt;Here's what actually helped us, roughly in the order we learned it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Write the "why" next to the change, not in a separate doc
&lt;/h2&gt;

&lt;p&gt;Separate decision docs are a lovely idea that nobody opens. What does get read is the stuff people are already looking at: the PR description, the ticket, the commit message.&lt;/p&gt;

&lt;p&gt;So our rule is small. Any change that reverses or picks between options gets one sentence of "why" in the PR description, plus a link to wherever the argument happened. That's it. No template, no ADR folder to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Link the thread, don't summarise it from memory
&lt;/h2&gt;

&lt;p&gt;When you summarise a long Slack discussion from memory, you lose the part that matters later: the objection someone raised and why it was overruled. A link to the actual thread keeps that. One sentence of summary, then the link.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Name the decision so it's searchable
&lt;/h2&gt;

&lt;p&gt;"Fixed retry logic" is unsearchable six months later. "Retry max 3: payment provider rate-limits at 4" is something you can actually find. Put the noun people will type into search in the title.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Treat "who knows about X?" as a bug report
&lt;/h2&gt;

&lt;p&gt;When someone asks "who knows how the billing sync works?", that's a sign the knowledge only lives in a person. We started answering those questions in a public channel, then pasting the answer, with links, into the ticket or README it belongs to. Every repeat question gets cheaper.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Close the loop with the follow-up
&lt;/h2&gt;

&lt;p&gt;Finding the answer is only half the job. The question usually comes with a next step: reply to the customer, open the ticket, update the doc. If the answer and the follow-up live in different places, the follow-up quietly doesn't happen. Write the follow-up while the answer is still on screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

&lt;p&gt;Not a big process change. Mostly: fewer "quick calls" to re-decide things, new people asking the search box before they ask a person, and less "let me check with the one person who knows".&lt;/p&gt;

&lt;p&gt;If you've got a habit that works for this on your team, I'd like to hear it in the comments.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;We build Enhanciar, which does the searching part of this for you across Slack, Gmail, Notion, Drive, Jira and GitHub, with a link to where every answer came from: &lt;a href="https://enhanciar.in" rel="noopener noreferrer"&gt;enhanciar.in&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>documentation</category>
      <category>teamwork</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How I find what breaks before I change a Python function</title>
      <dc:creator>Enhanciar AI</dc:creator>
      <pubDate>Thu, 01 Oct 2026 07:56:25 +0000</pubDate>
      <link>https://dev.to/enhanciar_ai_96a4ba4877e3/how-i-find-what-breaks-before-i-change-a-python-function-19f3</link>
      <guid>https://dev.to/enhanciar_ai_96a4ba4877e3/how-i-find-what-breaks-before-i-change-a-python-function-19f3</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fza4xzpg4corp0x948ymk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fza4xzpg4corp0x948ymk.gif" alt="blastradius demo" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've been bitten by the same bug more times than I'd like to admit. I change a "small" helper in a Python codebase, the tests I thought to run pass, and two days later something three modules away breaks because it called that helper in a way I never knew about.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;grep&lt;/code&gt; helps a little, but it tells you where a &lt;em&gt;name&lt;/em&gt; appears, not what &lt;em&gt;depends&lt;/em&gt; on it. A name like &lt;code&gt;charge&lt;/code&gt; or &lt;code&gt;total&lt;/code&gt; shows up in comments, strings, unrelated classes and dead code. What I actually wanted to know before touching a function was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Who calls this directly, and from which line?&lt;/li&gt;
&lt;li&gt;Who calls &lt;em&gt;those&lt;/em&gt; callers, a couple of hops out?&lt;/li&gt;
&lt;li&gt;Which tests actually reach this code, so I can run those first?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So I wrote a small CLI that answers exactly that. It's called &lt;strong&gt;blastradius&lt;/strong&gt;, it's MIT licensed, and it has no dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;git+https://github.com/enhanciar/blastradius
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need Python 3.10+. It needs no API key and makes no network calls. Everything runs locally on your source code.&lt;/p&gt;

&lt;h3&gt;
  
  
  A tiny example
&lt;/h3&gt;

&lt;p&gt;Say you have this layout. It's a simplified version of the &lt;code&gt;tests/fixtures/shop&lt;/code&gt; fixture in the repo, and the output below comes from that fixture, so the line numbers differ slightly from the snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# shop/money.py
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;apply_tax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.18&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;rate&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;# shop/billing.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;shop.money&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;apply_tax&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Invoice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;total&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;apply_tax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;charge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&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;gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;total&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;# shop/api.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;shop.billing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;charge&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;checkout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;charge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# tests/test_billing.py
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_charge&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You want to change how &lt;code&gt;apply_tax&lt;/code&gt; rounds. Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;blastradius &lt;span class="nb"&gt;.&lt;/span&gt; shop/money.py::apply_tax
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;blastradius: 6 files, 11 definitions, 13 edges (0.00s)

Target: shop/money.py::apply_tax
  defined at shop/money.py:5

Direct callers (1)
  shop/billing.py:12                       Invoice.total  -&amp;gt; apply_tax

Transitive dependents (3, up to 3 hops)
  hop 2  shop/billing.py:15    charge  (via Invoice.total &amp;lt;- apply_tax)
  hop 3  shop/api.py:4     checkout  (via charge &amp;lt;- Invoice.total)
  hop 3  tests/test_billing.py:4     test_charge  (via charge &amp;lt;- Invoice.total)  [test]

Affected tests (1)
  tests/test_billing.py:4  test_charge

Summary: 1 direct, 3 transitive, 3 other files (2 non-test), 1 tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole point. Your rounding change reaches &lt;code&gt;checkout&lt;/code&gt; in your API layer, and &lt;code&gt;test_charge&lt;/code&gt; is the test to run.&lt;/p&gt;

&lt;h3&gt;
  
  
  On a real repo
&lt;/h3&gt;

&lt;p&gt;On &lt;code&gt;psf/requests&lt;/code&gt;, asking about &lt;code&gt;get_netrc_auth&lt;/code&gt; with &lt;code&gt;--depth 2&lt;/code&gt; parses 37 files and 787 definitions in about 0.08 seconds. It finds 5 direct callers, 14 transitive dependents (including &lt;code&gt;Session.request&lt;/code&gt;), and 15 test functions that reach it. That's a much better list than "run everything and hope".&lt;/p&gt;

&lt;h3&gt;
  
  
  Useful flags
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;blastradius &amp;lt;repo&amp;gt; &amp;lt;target&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;--depth&lt;/span&gt; N] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;--json&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;--exclude&lt;/span&gt; PATH] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;--all&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The target can be a bare name (&lt;code&gt;charge&lt;/code&gt;), a method (&lt;code&gt;Invoice.total&lt;/code&gt;), a qualified name (&lt;code&gt;src/billing.py::charge&lt;/code&gt;), or a whole file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--depth&lt;/code&gt; sets how many hops out to walk. The default is 3.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--json&lt;/code&gt; gives machine-readable output for CI, editor plugins or coding agents.&lt;/li&gt;
&lt;li&gt;The exit code is &lt;code&gt;0&lt;/code&gt; if the target is found and &lt;code&gt;1&lt;/code&gt; if it isn't. When it isn't found you get close-match suggestions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also use it as a library:&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;from&lt;/span&gt; &lt;span class="n"&gt;blastradius&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;build_graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;compute_impact&lt;/span&gt;

&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build_graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;path/to/repo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vendor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compute_impact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;billing.py::charge&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;It walks every &lt;code&gt;.py&lt;/code&gt; file and parses it with the standard-library &lt;code&gt;ast&lt;/code&gt; module. It records definitions, calls and imports (including relative imports and aliases), then resolves each call in a fixed order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;self.x()&lt;/code&gt; on the enclosing class&lt;/li&gt;
&lt;li&gt;explicit imports, then &lt;code&gt;module.x()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the same file&lt;/li&gt;
&lt;li&gt;a name that's unique in the repo&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key design choice is this: &lt;strong&gt;if a call is ambiguous, it is dropped, not guessed.&lt;/strong&gt; I'd rather the graph miss an edge than invent one, because a fake caller wastes your time and erodes trust in the tool.&lt;/p&gt;

&lt;p&gt;Then it does a breadth-first walk backwards from your target.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limits (please read)
&lt;/h3&gt;

&lt;p&gt;This is static analysis, so read the output as a strong hint, not proof.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python only&lt;/strong&gt; for now.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic calls are invisible.&lt;/strong&gt; That covers &lt;code&gt;getattr&lt;/code&gt;, callbacks passed as values, dependency injection, decorators that swap functions, and string dispatch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Method calls on objects of unknown type&lt;/strong&gt; (&lt;code&gt;obj.save()&lt;/code&gt;) only resolve when the name is unique or imported. Common names like &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;run&lt;/code&gt; are often dropped.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inheritance isn't followed yet.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests only count if they reach the target through the call graph.&lt;/strong&gt; Tests that go over HTTP or only through fixtures won't show up.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why I built it
&lt;/h3&gt;

&lt;p&gt;I'm building a bigger product (&lt;a href="https://enhanciar.in" rel="noopener noreferrer"&gt;Enhanciar&lt;/a&gt;, a company brain that answers questions with links to sources), and "what does this change affect?" kept coming up. This piece is useful on its own, so I pulled it out and open-sourced it.&lt;/p&gt;

&lt;p&gt;If you try it on your codebase, I'd love to hear where it got something wrong. Missed edges are the most useful bug reports. The repo is &lt;a href="https://github.com/enhanciar/blastradius" rel="noopener noreferrer"&gt;https://github.com/enhanciar/blastradius&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What do you use today before a risky refactor?&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>refactoring</category>
      <category>testing</category>
    </item>
    <item>
      <title>Enterprise AI search can't answer the only question that matters: "why?"</title>
      <dc:creator>Enhanciar AI</dc:creator>
      <pubDate>Tue, 22 Sep 2026 16:53:17 +0000</pubDate>
      <link>https://dev.to/enhanciar_ai_96a4ba4877e3/enterprise-ai-search-cant-answer-the-only-question-that-matters-why-k0e</link>
      <guid>https://dev.to/enhanciar_ai_96a4ba4877e3/enterprise-ai-search-cant-answer-the-only-question-that-matters-why-k0e</guid>
      <description>&lt;p&gt;Every company search tool demos the same way.&lt;/p&gt;

&lt;p&gt;Someone types &lt;em&gt;"what's our refund policy?"&lt;/em&gt;, the AI returns a tidy paragraph with three source chips, the room nods, and procurement starts a twelve-week evaluation.&lt;/p&gt;

&lt;p&gt;Now watch an actual engineer's Tuesday:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Why is checkout rate-limited to 20 requests per second?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That answer is not in a document. It's in an ADR nobody linked, a Slack thread from November that scrolled away, and one line in &lt;code&gt;src/rate_limiter.py&lt;/code&gt;. The three facts only mean something &lt;strong&gt;together&lt;/strong&gt;. Enterprise search finds the file. It does not find the reason.&lt;/p&gt;

&lt;p&gt;This is the gap I want to argue about, because I think the whole category is optimising for the wrong question — and I say that as someone building in it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The category solved retrieval and called it knowledge
&lt;/h2&gt;

&lt;p&gt;Tools like Glean are genuinely good at what they were built for: company-wide search over hundreds of SaaS connectors, with SSO, admin controls and a sales-led contract. If you need one search box over Drive, Jira, Zendesk and Confluence, that is a real and hard problem, and they solved it.&lt;/p&gt;

&lt;p&gt;But engineering questions have a shape those tools don't fit:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What a search tool optimises&lt;/th&gt;
&lt;th&gt;What an engineer actually asks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"Find the document about X"&lt;/td&gt;
&lt;td&gt;"Why is it built this way?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Summarise this page"&lt;/td&gt;
&lt;td&gt;"What breaks if I change this?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Who wrote this doc?"&lt;/td&gt;
&lt;td&gt;"Who would actually know?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documents ranked by relevance&lt;/td&gt;
&lt;td&gt;Facts joined across code, chat, and tickets&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The second column is not a retrieval problem. It's a &lt;strong&gt;graph&lt;/strong&gt; problem plus a &lt;strong&gt;provenance&lt;/strong&gt; problem. Ranking documents better does not get you there, no matter how good the embeddings are.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three things I think the category gets wrong
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. A citation is treated as proof
&lt;/h3&gt;

&lt;p&gt;Every one of these tools shows sources. Almost none of them check that the cited source actually supports the sentence next to it.&lt;/p&gt;

&lt;p&gt;This is not a hypothetical. It's the single most common failure we hit: the model retrieves the right file and then paraphrases something the file does not say. The citation is "valid" — the document is real, the retrieval worked — and the answer is still wrong. Worse, the chip next to it makes the wrong answer &lt;em&gt;more&lt;/em&gt; persuasive.&lt;/p&gt;

&lt;p&gt;We ended up building a checker that re-reads every cited source and grades each claim &lt;code&gt;supported / partial / unsupported / unverifiable&lt;/code&gt;, with a structural (free, AST-based) pass before the model-based one. The part that mattered wasn't the model. It was the rule that &lt;strong&gt;the checker may never say "supported" just because it couldn't run&lt;/strong&gt;. If the oracle has no data or the key is missing, the claim stays &lt;code&gt;unverifiable&lt;/code&gt; and the UI says what was &lt;em&gt;not&lt;/em&gt; checked.&lt;/p&gt;

&lt;p&gt;"Has a citation" and "is true" are different bars. Most tools ship the first and imply the second.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Confidence is mistaken for coverage
&lt;/h3&gt;

&lt;p&gt;Ask any of these systems something genuinely undocumented and you get a fluent paragraph assembled from adjacent noise. Almost none of them say &lt;em&gt;"nobody has written this down."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's the honest answer surprisingly often, and it's actionable in a way a hallucination never is — because the next step is obvious: &lt;strong&gt;go ask the person who knows.&lt;/strong&gt; A system that knows who touched that code and who ingested that repo can name them, ask them in Slack, and file the reply back into the wiki so the next person doesn't have to ask. Not knowing isn't the failure. Pretending not to notice is.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Humans are the only assumed consumer
&lt;/h3&gt;

&lt;p&gt;Most of these products are a search box on a web page. But in 2026 the heaviest consumer of company knowledge isn't a person typing a query — it's the coding agent in your editor, which will otherwise guess.&lt;/p&gt;

&lt;p&gt;If your company brain isn't reachable over MCP from Claude Code or Cursor, your agents are working from vibes while your humans get the good data. That's backwards: the agent is the one that will &lt;em&gt;silently&lt;/em&gt; act on a wrong answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this actually costs you today
&lt;/h2&gt;

&lt;p&gt;The pricing model is the other tell. Per-seat enterprise contracts with inference bundled in mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you pay a markup on tokens you could buy yourself, and&lt;/li&gt;
&lt;li&gt;the vendor is incentivised to answer &lt;em&gt;every&lt;/em&gt; question, because "I don't know" looks like a product defect on a renewal call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bring-your-own-key flips that. If the user pays their own provider directly, the tool has no reason to pad answers, and a verification pass that says "this claim is unsupported" becomes a feature rather than an admission.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where the enterprise tools genuinely win
&lt;/h2&gt;

&lt;p&gt;I'd be a hypocrite to write about honest answers and then strawman the competition, so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Company-wide, non-engineering search.&lt;/strong&gt; If HR, sales and support all need one box over every SaaS tool, buy the enterprise suite. We don't do that and don't plan to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Procurement-shaped orgs.&lt;/strong&gt; SSO, DPAs, admin policy, security review, a name on a contract. That's real work and it's their work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-config.&lt;/strong&gt; Managed models, no keys to think about. BYOK is a tax if nobody on your team wants to hold a key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If all you need is one search box over every SaaS tool your company owns, this post isn't for you. If your hardest questions start with "why is this built this way", it is.&lt;/p&gt;




&lt;h2&gt;
  
  
  The test I'd apply to any of these tools
&lt;/h2&gt;

&lt;p&gt;Before you sign anything, ask the tool one question you already know the answer to — something that required a decision, not just a lookup. &lt;code&gt;Why is X configured this way?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then grade it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Did it give you a &lt;strong&gt;file and a line&lt;/strong&gt;, or a document title?&lt;/li&gt;
&lt;li&gt;Did it surface the &lt;strong&gt;decision&lt;/strong&gt; — the ADR, the incident, the Slack thread — or just the code?&lt;/li&gt;
&lt;li&gt;When you clicked the citation, did the source &lt;strong&gt;actually say&lt;/strong&gt; what the answer claimed?&lt;/li&gt;
&lt;li&gt;Ask it something genuinely undocumented. Did it &lt;strong&gt;say it didn't know&lt;/strong&gt;, or improvise?&lt;/li&gt;
&lt;li&gt;Can your &lt;strong&gt;coding agent&lt;/strong&gt; ask the same question without a browser?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most tools pass 1 and fail 3 and 4. That's the whole thesis of this post.&lt;/p&gt;




&lt;p&gt;We're building &lt;a href="https://enhanciar.in?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=vswhy" rel="noopener noreferrer"&gt;Enhanciar&lt;/a&gt; around those five checks — a company brain for engineering teams, with every answer cited to file:line, every citation re-verified, and the whole thing reachable over MCP. It's waitlist-only right now.&lt;/p&gt;

&lt;p&gt;I'm genuinely interested in disagreement on point 1: &lt;strong&gt;is an unverified citation better than no citation at all?&lt;/strong&gt; I've argued myself into "no — it's worse, because it buys unearned trust." Tell me why I'm wrong.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>devops</category>
    </item>
    <item>
      <title>Your AI cited a real file. It still lied to you.</title>
      <dc:creator>Enhanciar AI</dc:creator>
      <pubDate>Tue, 22 Sep 2026 16:39:32 +0000</pubDate>
      <link>https://dev.to/enhanciar_ai_96a4ba4877e3/how-we-make-an-llm-cite-every-answer-down-to-fileline-and-check-the-citation-is-telling-the-truth-hmj</link>
      <guid>https://dev.to/enhanciar_ai_96a4ba4877e3/how-we-make-an-llm-cite-every-answer-down-to-fileline-and-check-the-citation-is-telling-the-truth-hmj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — A citation proves a document was &lt;em&gt;retrieved&lt;/em&gt;. It does not prove the sentence next to it came from there. We built Enhanciar to (1) force every answer to cite, (2) resolve each citation to a repo file and line, and (3) re-read the cited source and grade each claim &lt;code&gt;supported / partial / unsupported / unverifiable&lt;/code&gt;. The interesting part is not the LLM — it's the free, deterministic checker that runs &lt;em&gt;before&lt;/em&gt; the LLM, and the rule that the verifier must never say "supported" just because it couldn't run.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The problem nobody's RAG demo shows
&lt;/h2&gt;

&lt;p&gt;Every "chat with your codebase" tool now prints little &lt;code&gt;[1] [2]&lt;/code&gt; markers under its answers. Ask one of them &lt;em&gt;"which service handles refunds for cancelled orders?"&lt;/em&gt; and you'll get a confident paragraph, a source link, and a warm feeling.&lt;/p&gt;

&lt;p&gt;Then you click the link and the file doesn't mention refunds.&lt;/p&gt;

&lt;p&gt;This is the failure mode we kept hitting when we tried to use these tools on real engineering teams: &lt;strong&gt;the model cites a real page and then paraphrases something the page does not say.&lt;/strong&gt; Retrieval worked. The citation is "valid". The answer is still wrong, and the citation makes it &lt;em&gt;more&lt;/em&gt; convincing, not less.&lt;/p&gt;

&lt;p&gt;We wanted a tool an engineer could trust on their first day at a company — where "trust" means "I can click through and see the line that backs this sentence, or the tool tells me it couldn't find one."&lt;/p&gt;

&lt;p&gt;Here's how we built it. It's three layers, and the order matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 1 — Make citations mandatory and machine-parseable
&lt;/h2&gt;

&lt;p&gt;We don't index raw files for Q&amp;amp;A. At ingest time we build a &lt;strong&gt;wiki&lt;/strong&gt;: one Markdown page per meaningful unit (a service, a route, a module, a decision), each with frontmatter that records &lt;em&gt;exactly which repo files the page was built from&lt;/em&gt;. Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;entities/cart-service&lt;/span&gt;
&lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;src/services/cart.ts&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;src/routes/cart.ts&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="gh"&gt;# cart-service&lt;/span&gt;
Handles cart mutation and checkout hand-off. Exposes &lt;span class="sb"&gt;`POST /cart/items`&lt;/span&gt; ...

&lt;span class="gu"&gt;## Dependencies&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [[entities/pricing-service]]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Answers are generated &lt;em&gt;over these pages&lt;/em&gt;, and the model is required to cite them with wiki-style handles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Refunds for cancelled orders are handled by the payments worker
[[entities/payments-worker]], which is triggered from the order
state machine [[flows/order-cancellation]].
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We parse those handles out of the finished answer with a boring regex (we tolerate a &lt;code&gt;§ heading&lt;/code&gt; suffix and a trailing &lt;code&gt;.md&lt;/code&gt; because models add them anyway, dedupe, and cap at 16). Every handle resolves to a page, and every page resolves to &lt;code&gt;file(s)&lt;/code&gt; in the repo. So one hop from &lt;code&gt;[[entities/payments-worker]]&lt;/code&gt; gets you to &lt;code&gt;src/workers/payments.ts&lt;/code&gt;, and the AST index we build at ingest gets you to a line.&lt;/p&gt;

&lt;p&gt;That's the "file:line" part. It's the &lt;em&gt;easy&lt;/em&gt; part, and it's where most tools stop.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 2 — Is the page itself true? (the ingest-side check)
&lt;/h2&gt;

&lt;p&gt;Before an answer ever cites a page, the page has to survive a &lt;strong&gt;per-claim verification&lt;/strong&gt; pass. We break each generated page into individual claims and adjudicate each one, &lt;em&gt;cheapest oracle first&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tier 1: the AST oracle (deterministic, free)
&lt;/h3&gt;

&lt;p&gt;A surprising share of claims are &lt;strong&gt;structural&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"this file defines &lt;code&gt;generateMetadata&lt;/code&gt;"&lt;/li&gt;
&lt;li&gt;"this page depends on &lt;code&gt;[[get-meta-details-service]]&lt;/code&gt;"&lt;/li&gt;
&lt;li&gt;"it exposes &lt;code&gt;GET /aboutUs&lt;/code&gt;"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We already extracted all of that with tree-sitter at ingest time. So these claims are settled by &lt;em&gt;lookup&lt;/em&gt; — no model call, no API key, no tokens. If the AST says &lt;code&gt;generateMetadata&lt;/code&gt; is defined at &lt;code&gt;app/layout.tsx:42&lt;/code&gt;, the claim is &lt;code&gt;supported&lt;/code&gt; with evidence &lt;code&gt;{file, line}&lt;/code&gt;. If the symbol doesn't exist anywhere, it's &lt;code&gt;unsupported&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Anything tier 1 can judge, tier 1 judges. Tier 2 never sees it. That's the whole cost story.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tier 2: the LLM critic (costs tokens)
&lt;/h3&gt;

&lt;p&gt;Prose claims — &lt;em&gt;"this service handles refunds for cancelled orders"&lt;/em&gt; — have no structural handle. A model has to re-read the cited source and say whether it supports the sentence. It must return a &lt;strong&gt;quoted span&lt;/strong&gt; and the line it was found at, or it doesn't get to say &lt;code&gt;supported&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The verdict vocabulary
&lt;/h3&gt;

&lt;p&gt;Every claim ends up with exactly one of:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;supported&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;evidence found for the &lt;em&gt;specific&lt;/em&gt; assertion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;partial&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;something related found, but not what was asserted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unsupported&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the cited source was checked and &lt;strong&gt;does not say this&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unverifiable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;nothing could check it — no citation, source gone, checker unavailable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;unverifiable&lt;/code&gt; is load-bearing and is never a synonym for "fine".&lt;/strong&gt; Early on, tier 1 had a bug where it reported every React hook in a repo as &lt;code&gt;unsupported&lt;/code&gt;. The lesson stuck: if the oracle has no data, or the critic has no key, the claim stays &lt;code&gt;unverifiable&lt;/code&gt; and the UI says what was &lt;em&gt;not checked&lt;/em&gt;. Silently marking things &lt;code&gt;supported&lt;/code&gt; because the checker broke would be the worst possible failure of the feature, so every "cannot judge" path returns &lt;code&gt;unverifiable&lt;/code&gt; rather than a guess.&lt;/p&gt;

&lt;h3&gt;
  
  
  We tag, we don't delete
&lt;/h3&gt;

&lt;p&gt;There was a real design fork here: drop unverified claims, or tag them? Tagging won. A wrong verifier that silently destroys real information is far worse than a wrong verifier that mislabels it — a tag is inspectable and reversible. So a page can carry a sentence flagged &lt;code&gt;unsupported&lt;/code&gt; and you can see it, click through, and decide.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 3 — Is the &lt;em&gt;answer&lt;/em&gt; supported by the pages it cites?
&lt;/h2&gt;

&lt;p&gt;Layer 2 settles "is this page true about the code". It does &lt;em&gt;not&lt;/em&gt; settle the failure I opened with: the model cites &lt;code&gt;[[cart-service]]&lt;/code&gt; while paraphrasing something that page doesn't say.&lt;/p&gt;

&lt;p&gt;So we run the &lt;strong&gt;same&lt;/strong&gt; checker a second time, with one substitution: for a wiki page the source is the repo file; for an answer the source is the wiki pages it cites. Same verdict vocabulary, same evidence discipline (quoted span + page + line), same extractor, same free oracle, same paid critic. It is deliberately &lt;em&gt;not&lt;/em&gt; a second verification system.&lt;/p&gt;

&lt;p&gt;Four properties, in the order they matter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It never delays a token.&lt;/strong&gt; Answers stream. Verification runs after the stream closes, from a separate request, and annotates the finished answer in place. Nothing is on the path between a question and its first word.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It flags; it does not retry.&lt;/strong&gt; The obvious move is "retry on mismatch". A blind retry doubles latency and doubles spend on the user's own key to produce a second answer nobody has checked either. Annotating the sentence tells the reader &lt;em&gt;exactly which claim to distrust&lt;/em&gt;, which is what the retry was trying to buy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;unverifiable&lt;/code&gt; ≠ &lt;code&gt;unsupported&lt;/code&gt;.&lt;/strong&gt; A sentence with no citation, a citation to a page that no longer exists, a page too large for the prompt, a checker that couldn't run — all &lt;code&gt;unverifiable&lt;/code&gt;. Only "the cited page was read and does not say this" is &lt;code&gt;unsupported&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure is silent and safe.&lt;/strong&gt; No key, model error, rate limit, timeout, unparseable reply: the answer is already on screen and stays there, and the result says the check didn't run. Nothing is ever marked &lt;code&gt;supported&lt;/code&gt; because the checker broke.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What it looks like from the outside
&lt;/h2&gt;

&lt;p&gt;Ask through the MCP server (Claude Code, Cursor, Claude Desktop all work). Rendered here as plain text — the UI shows the same verdicts as badges:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; which service handles refunds for cancelled orders?

Refunds for cancelled orders are issued by the payments worker
[[entities/payments-worker]] ✅ src/workers/payments.ts:118
when the order state machine emits `order.cancelled`
[[flows/order-cancellation]] ✅ src/orders/machine.ts:64.
Partial refunds are not supported ⚠️ unverifiable — no cited page discusses partial refunds.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two sentences are backed by a file and a line you can open. The third is honestly labelled: the model asserted it, nothing in the cited pages says it, so you don't get a green tick. That third line is the feature.&lt;/p&gt;




&lt;h2&gt;
  
  
  Things we got wrong on the way
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trusting the citation as proof.&lt;/strong&gt; Our first version marked an answer "grounded" if every citation resolved to a real page. That's necessary and nowhere near sufficient.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Letting &lt;code&gt;unverifiable&lt;/code&gt; collapse into &lt;code&gt;supported&lt;/code&gt;.&lt;/strong&gt; Any code path that returns a default verdict when something throws will eventually default to the wrong one. We made the default &lt;code&gt;unverifiable&lt;/code&gt; everywhere and made "supported with no evidence record" impossible by construction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verifying inline.&lt;/strong&gt; Putting the checker in the streaming path made every answer feel slow and bought nothing. Post-stream annotation is strictly better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output truncation masquerading as parser bugs.&lt;/strong&gt; Days lost to "the ingest found 0 pages for this domain" — it was the model's thinking budget eating the output token budget. Worth a whole separate post.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Cost, honestly
&lt;/h2&gt;

&lt;p&gt;Tier 1 is free forever. Tier 2 and answer-verification spend the user's own key (BYOK), once per page at ingest and once per answer if the flag is on — it's &lt;strong&gt;off by default&lt;/strong&gt; precisely because it costs something, and the token counts come back with the verdicts so you can see what you paid for.&lt;/p&gt;




&lt;p&gt;If you're building anything RAG-shaped for engineers: the citation is the &lt;em&gt;start&lt;/em&gt; of trust, not the end. Re-read the source. Grade the claim. Say "I couldn't check this" out loud.&lt;/p&gt;

&lt;p&gt;We're building this as &lt;a href="https://enhanciar.in?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=launch" rel="noopener noreferrer"&gt;Enhanciar&lt;/a&gt; — a company brain for engineering teams that answers with receipts. It's waitlist-only right now; if you want to try it on your repo, the link is on the site. Happy to answer questions about the verifier design in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>llm</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
