<?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: Bharath sai Ganipineni</title>
    <description>The latest articles on DEV Community by Bharath sai Ganipineni (@bharath_saiganipineni).</description>
    <link>https://dev.to/bharath_saiganipineni</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%2F4146377%2F3cba0181-d13d-410e-aa3d-0fef694eae85.png</url>
      <title>DEV Community: Bharath sai Ganipineni</title>
      <link>https://dev.to/bharath_saiganipineni</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bharath_saiganipineni"/>
    <language>en</language>
    <item>
      <title>Building a Code Review Agent That Actually Remembers!</title>
      <dc:creator>Bharath sai Ganipineni</dc:creator>
      <pubDate>Mon, 28 Sep 2026 13:31:09 +0000</pubDate>
      <link>https://dev.to/bharath_saiganipineni/building-a-code-review-agent-that-actuallyremembers-3mm3</link>
      <guid>https://dev.to/bharath_saiganipineni/building-a-code-review-agent-that-actuallyremembers-3mm3</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fus42le351e7aq38dto1t.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fus42le351e7aq38dto1t.jpg" alt=" " width="799" height="407"&gt;&lt;/a&gt;&lt;br&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ipwbb6fpje0xu2h9m15.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ipwbb6fpje0xu2h9m15.jpg" alt=" " width="799" height="407"&gt;&lt;/a&gt;&lt;br&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F21ll168qj4g714um0t3g.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F21ll168qj4g714um0t3g.jpg" alt=" " width="799" height="407"&gt;&lt;/a&gt;&lt;br&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhjxopqkpwexobe9200zo.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhjxopqkpwexobe9200zo.jpg" alt=" " width="799" height="407"&gt;&lt;/a&gt;&lt;br&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv72b5zkhb63fc5h7lo8s.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv72b5zkhb63fc5h7lo8s.jpg" alt=" " width="799" height="407"&gt;&lt;/a&gt;&lt;br&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3txx51djzi9bdqptm1wk.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3txx51djzi9bdqptm1wk.jpg" alt=" " width="799" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why code review keeps repeating itself&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Picture a familiar scene. A teammate opens a pull request, and a reviewer leaves the same&lt;br&gt;
comment they left last month: "Please add a timeout to this HTTP call." The fix is easy. The real&lt;br&gt;
problem is that nothing carried the lesson forward.&lt;br&gt;
Linters and automated reviewers have the same weakness. Each run starts fresh, so knowledge&lt;br&gt;
that one person paid for is lost for the next. In this article I walk through how to design a review&lt;br&gt;
system with long-term memory, and the design choices that matter more than the code&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What we are building
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;The system has two screens. The developer screen is where a review happens. The manager&lt;br&gt;
screen shows patterns over time. Behind them sits a simple three-step pipeline:&lt;br&gt;
• Recall: look up what the team already knows about this file and this kind of error.&lt;br&gt;
• Decide: check whether this exact problem has appeared before.&lt;br&gt;
• Save or reuse: if it is new, store it. If it is a repeat, reuse the earlier fix and bump a counter&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqzy7znarhr7n7xdze6no.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqzy7znarhr7n7xdze6no.png" alt=" " width="799" height="257"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design choice 1: use two stores, not one&lt;/strong&gt; __&lt;br&gt;
The tempting approach is a single database table: team, file, error, fix. It is easy to build and easy&lt;br&gt;
to chart. But a table only matches exactly. Two developers will describe the same bug in different&lt;br&gt;
words, and a table will treat them as unrelated.&lt;br&gt;
So I split the work in two. A memory engine (Hindsight, using its retain and recall calls)&lt;br&gt;
handles fuzzy, meaning-based lookup. A small SQLite ledger handles hard numbers. Neither is a&lt;br&gt;
copy of the other, because they answer different questions&lt;br&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu7k6282cypgv8sc96b7j.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu7k6282cypgv8sc96b7j.png" alt=" " width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design choice 2: one memory bank per team&lt;/strong&gt;&lt;br&gt;
You could use one global bank, one per developer, or one per team. A global bank mixes teams&lt;br&gt;
whose rules conflict. A per-developer bank hides knowledge from the people who need it. Coding&lt;br&gt;
standards are agreed by teams, so the team is the right boundary&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ev5omqan1hj84dy5mms.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ev5omqan1hj84dy5mms.png" alt=" " width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;def build_note(team, file_name, problem, rule, fix):&lt;br&gt;
    return (&lt;br&gt;
    )&lt;br&gt;
        f"In {file_name}, team {team} had this problem: {problem}. "&lt;br&gt;
        f"Rule broken: {rule}. Fix that worked: {fix}."&lt;br&gt;
note = build_note(&lt;br&gt;
    "Alpha", "http_client.py",&lt;br&gt;
    "an HTTP request had no timeout and hung the worker",&lt;br&gt;
    "all outbound calls must set a timeout",&lt;br&gt;
    "pass timeout=5 and handle the timeout error",&lt;br&gt;
)&lt;br&gt;
client.retain(bank_id=bank_for("Alpha"), content=note)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design choice 4: search by the signal, not the noise&lt;/strong&gt;&lt;br&gt;
__For recall, I query with the file name plus a short description of the error. I leave the raw code out.&lt;br&gt;
Variable names and whitespace pull results toward code that merely looks similar, while the file&lt;br&gt;
and the failure description describe the actual problem&lt;code&gt;def find_related(client, team, file_name, error):&lt;br&gt;
    query = f"{file_name}: {error}"&lt;br&gt;
    result = client.recall(bank_id=bank_for(team), query=query)&lt;br&gt;
    return [m.text for m in result.results]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Design choice 5: an exact fingerprint for counting**&lt;br&gt;
__Meaning-based search is great for context, but a number on a manager's dashboard should be&lt;br&gt;
exact. If the dashboard says "this issue happened three times", you must be able to defend that.&lt;br&gt;
So I hash the details into a fingerprint:&lt;code&gt;import hashlib&lt;br&gt;
def fingerprint(team, file_name, code, error):&lt;br&gt;
    raw = "|".join([team.strip().lower(), file_name.strip().lower(),&lt;br&gt;
                    code.strip(), error.strip()])&lt;br&gt;
    return hashlib.sha256(raw.encode()).hexdigest(&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import sqlite3&lt;br&gt;
db = sqlite3.connect("ledger.db")&lt;br&gt;
db.execute("""CREATE TABLE IF NOT EXISTS incidents (&lt;br&gt;
    fingerprint TEXT PRIMARY KEY,&lt;br&gt;
    team TEXT, file_name TEXT, repeats INTEGER DEFAULT 1,&lt;br&gt;
    first_seen TEXT DEFAULT CURRENT_TIMESTAMP)""")&lt;br&gt;
def is_repeat(fp):&lt;br&gt;
    row = db.execute("SELECT repeats FROM incidents WHERE fingerprint=?",&lt;br&gt;
                     (fp,)).fetchone()&lt;br&gt;
    return row is not None&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;--Plan for failure from day one&lt;br&gt;
Memory is a network call, and network calls fail. Notice the try/except around the save. If the&lt;br&gt;
memory service is down, the review still finishes and the incident is still written to the local ledger.&lt;br&gt;
A reviewer that says "my memory is unavailable right now" is far better than one that crashes.&lt;br&gt;
Keep credentials in environment variables, never in code, and fail early with a clear message if&lt;br&gt;
one is missing.&lt;br&gt;
The manager view&lt;br&gt;
Because the ledger stores counts, a simple query answers the question managers care about: are&lt;br&gt;
we teaching the same thing over and over?&lt;br&gt;
SELECT file_name, SUM(repeats) AS total&lt;br&gt;
FROM incidents WHERE team = ?&lt;br&gt;
GROUP BY file_name ORDER BY total DESC&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3nu2z9mvj777t0e5xkyb.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3nu2z9mvj777t0e5xkyb.png" alt=" " width="800" height="261"&gt;&lt;/a&gt;**&lt;/p&gt;

&lt;p&gt;Make the memory visible&lt;br&gt;
If you ask engineers to trust a system that remembers things, show your work. Display which&lt;br&gt;
search was run and how many memories came back. Turning "trust the agent" into "check the&lt;br&gt;
agent" makes adoption much easier.&lt;/p&gt;

&lt;p&gt;The bigger takeaway is that the interesting part of an agent that remembers is rarely the remembering. It's deciding what deserves to be remembered, who gets to retrieve it, and how you'll explain it when it's wrong. If you're building something similar, the Hindsight repository is the place to start.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A Special thanks to pragnasri yellanki, mithin sai mojjada, and Sreevallika Balagonda.&lt;/em&gt;&lt;/p&gt;

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