<?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: Mehwish afsa</title>
    <description>The latest articles on DEV Community by Mehwish afsa (@mehwishafsa).</description>
    <link>https://dev.to/mehwishafsa</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%2F4145362%2Fefb6efdb-ace9-447c-9e46-5bea63015eb0.png</url>
      <title>DEV Community: Mehwish afsa</title>
      <link>https://dev.to/mehwishafsa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mehwishafsa"/>
    <language>en</language>
    <item>
      <title>I Gave My Code Reviewer Hindsight Memory. It Stopped Nagging.</title>
      <dc:creator>Mehwish afsa</dc:creator>
      <pubDate>Sun, 27 Sep 2026 10:35:18 +0000</pubDate>
      <link>https://dev.to/mehwishafsa/i-gave-my-code-reviewer-hindsight-memory-it-stopped-nagging-29i8</link>
      <guid>https://dev.to/mehwishafsa/i-gave-my-code-reviewer-hindsight-memory-it-stopped-nagging-29i8</guid>
      <description>&lt;p&gt;The third time our AI reviewer told us to convert &lt;code&gt;logger.info("Order %s placed", order_id)&lt;/code&gt; into an f-string, I stopped reading its comments altogether.&lt;/p&gt;

&lt;p&gt;That's the real failure of most AI code review tools. They aren't wrong about Python. They're wrong about &lt;em&gt;us&lt;/em&gt;. They don't know we log with &lt;code&gt;%s&lt;/code&gt; on purpose, that we keep money in integer paise because floats once cost us a reconciliation mismatch, or that one of us keeps forgetting to check &lt;code&gt;None&lt;/code&gt; after a repository lookup. Every pull request, they meet the team for the first time.&lt;/p&gt;

&lt;p&gt;So I built Blockwise, a code reviewer that remembers. It uses &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;Hindsight, an open-source agent memory system&lt;/a&gt;, to learn a team's conventions from past reviews and, more importantly, to learn from every comment a human accepts or rejects.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Blockwise does
&lt;/h2&gt;

&lt;p&gt;Blockwise is a static web app. You pick a pull request, it shows the diff, and you ask for a review. There is a side-by-side mode that runs the same review twice: once as a generic reviewer, once with memory. That view is the whole argument for the project in one screen.&lt;/p&gt;

&lt;p&gt;The loop has three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Recall&lt;/strong&gt; what memory knows that's relevant to this pull request and its author.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review&lt;/strong&gt; the diff with an LLM (I use &lt;code&gt;openai/gpt-oss-120b&lt;/code&gt; on Groq), grounded in those memories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retain&lt;/strong&gt; the human's verdict on each comment, including the reason for a rejection.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To make it concrete, I seeded it with eight review threads from a sample food-delivery backend team, Tiffin. They contain rules like "no database calls inside route handlers" (PR #97), "money is integer paise, use &lt;code&gt;apply_percent&lt;/code&gt;" (PR #99), and two suggestions the team explicitly rejected: f-strings in logging calls (PR #100) and docstrings on test functions (PR #105).&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%2F7uz7gyefrorz4vqcbqwx.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%2F7uz7gyefrorz4vqcbqwx.png" alt=" " width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why memory, and why not just a bigger prompt
&lt;/h2&gt;

&lt;p&gt;My first instinct was to paste a &lt;code&gt;CONVENTIONS.md&lt;/code&gt; into the system prompt. That works for rules someone bothered to write down. It fails for everything that actually matters in code review: the decision made in a PR thread three weeks ago, the reason behind it, and the fact that Ravi has now skipped the same &lt;code&gt;None&lt;/code&gt; check twice.&lt;/p&gt;

&lt;p&gt;That knowledge is scattered across conversations and keeps changing. I didn't want to maintain a document; I wanted the reviewer to pick it up the way a new senior engineer does, by being in the reviews.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hindsight.vectorize.io/" rel="noopener noreferrer"&gt;Hindsight&lt;/a&gt; fits that shape. You &lt;code&gt;retain&lt;/code&gt; raw content, and it extracts facts, links entities (people, files, helper functions), keeps timestamps, and consolidates repeated evidence into observations. You &lt;code&gt;recall&lt;/code&gt; with a question and it fuses semantic, keyword, graph and temporal search. You &lt;code&gt;reflect&lt;/code&gt; to have it reason over everything it knows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teaching it: retain with a mission
&lt;/h2&gt;

&lt;p&gt;The first thing Blockwise does is create a memory bank with a &lt;code&gt;retain_mission&lt;/code&gt;. This steers what Hindsight extracts, and it made a bigger difference than any prompt tweak I tried later:&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;retain_mission&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This bank belongs to a code review agent for one engineering team. Extract team coding conventions, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;architectural rules, the reason behind each rule, suggestions the team rejected and why, and recurring &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mistakes made by specific developers. Keep file paths, helper names and PR numbers. Ignore pleasantries.&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="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PUT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bankPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bank&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each past review is retained as one item: the whole thread, a real timestamp, a &lt;code&gt;document_id&lt;/code&gt; so re-seeding doesn't create duplicates, and tags like &lt;code&gt;author:ravi-kumar&lt;/code&gt; and &lt;code&gt;kind:rejected-suggestion&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The part I care most about is what happens after a review. Every comment has &lt;strong&gt;Accept&lt;/strong&gt; and &lt;strong&gt;Reject&lt;/strong&gt; buttons, and rejecting asks for a one-line reason. That verdict goes straight back into memory:&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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;accepted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`... reviewer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;reviewer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ACCEPTED &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;what&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. This confirms the concern is a real team rule or recurring issue.`&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`... reviewer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;reviewer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; REJECTED &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;what&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Reason: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;". `&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
      &lt;span class="s2"&gt;`The team does not want this suggestion; do not repeat it in future reviews.`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seeding uses async retain because it's a batch. Feedback is retained synchronously, because a rejection that isn't visible to the very next review is worthless. That one-line decision fixed the most annoying bug I had.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remembering: three recalls per pull request
&lt;/h2&gt;

&lt;p&gt;One recall with the PR title wasn't enough. "Apply coupon discounts at checkout" doesn't sound anything like "money is integer paise", even though that's the rule the PR breaks. So Blockwise runs three recalls in parallel:&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;queries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Team conventions and past review decisions relevant to a PR titled "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" `&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
       &lt;span class="s2"&gt;`touching &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;files&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;. Code uses: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;signals&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;.`&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Recurring mistakes and review history for developer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;authorTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&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="na"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Suggestions the team rejected in past code reviews and the reasons given&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;signals&lt;/code&gt; come from a cheap pass over the added lines: &lt;code&gt;session.query&lt;/code&gt; becomes "database session in code", &lt;code&gt;/ 100&lt;/code&gt; becomes "arithmetic on amounts", &lt;code&gt;requests.&lt;/code&gt; becomes "outbound HTTP call". Those phrases give recall something concrete to match, and Hindsight's keyword and graph retrieval pick up exact helper names like &lt;code&gt;apply_percent&lt;/code&gt; that pure embeddings tend to blur.&lt;/p&gt;

&lt;p&gt;Results are merged, deduplicated and numbered &lt;code&gt;M1…Mn&lt;/code&gt;. The review prompt requires the model to cite the refs it relied on, and I filter out any ref that doesn't exist, so the UI never shows a made-up citation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before and after
&lt;/h2&gt;

&lt;p&gt;Here's PR #112, a coupon endpoint that queries the database inside the route handler, computes the discount in floats, and logs with &lt;code&gt;%s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without memory&lt;/strong&gt;, the review looked like a lint report from a stranger: a missing &lt;code&gt;None&lt;/code&gt; check, "add a docstring", and "use f-strings in your logging call". One real issue, two things the team had already rejected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With memory&lt;/strong&gt;, the same model on the same diff flagged the database query as a blocker and cited PR #97. It flagged the float math as a blocker, cited PR #99, and mentioned the July reconciliation mismatch that caused the rule. And it said nothing about the logging call.&lt;/p&gt;

&lt;p&gt;PR #113 is Ravi's refund webhook. It reads a secret with &lt;code&gt;os.getenv&lt;/code&gt;, calls &lt;code&gt;requests.post&lt;/code&gt; without a timeout, skips signature verification, and uses &lt;code&gt;order.id&lt;/code&gt; without checking the lookup. With memory, Blockwise flagged all four, and on the &lt;code&gt;None&lt;/code&gt; check it noted, politely, that the same thing came up in PR #102 and PR #107.&lt;/p&gt;

&lt;p&gt;PR #114 is the one I like most: a clean service with two tests and no docstrings. The generic reviewer asked for docstrings. With memory, Blockwise approved it with zero style comments, because the team had rejected that suggestion in PR #105.&lt;/p&gt;

&lt;p&gt;Then I tested the learning loop directly. On a fresh review I rejected a comment with "Route handlers are documented in the OpenAPI schema, not docstrings". The next review didn't make that suggestion again. That's the moment it stopped feeling like a tool and started feeling like a colleague.&lt;/p&gt;

&lt;p&gt;The Playbook tab calls Hindsight's &lt;code&gt;reflect&lt;/code&gt; and writes the team's review playbook from memory: conventions with reasons and PR numbers, rejected suggestions, and per-person patterns. Nobody wrote that document. It came out of the reviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. The retain mission matters more than the review prompt.&lt;/strong&gt; Once Hindsight extracted "rule + reason + PR number" instead of generic summaries, the review prompt got shorter and the comments got better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Negative memory is the killer feature.&lt;/strong&gt; Remembering what to flag is nice. Remembering what &lt;em&gt;not&lt;/em&gt; to say is what earns back a developer's attention. If I built only one thing again, it would be the Reject-with-reason button.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Recall from several angles.&lt;/strong&gt; Titles don't describe the rules a change breaks. Splitting recall into "what this code touches", "who wrote it" and "what we've rejected" was the biggest quality jump.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Make grounding checkable.&lt;/strong&gt; Forcing the model to cite memory refs, and dropping refs that don't exist, made it easy to trust the gold-highlighted comments and easy to spot when the model was guessing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Be careful with per-person memory.&lt;/strong&gt; "Ravi skips None checks" is useful, but it has to be phrased as help, not blame. I ask the model to mention history briefly and kindly, and I'd want a team's consent before turning it on for real.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;Blockwise runs entirely in the browser today, which keeps it easy to try but means keys live in localStorage. The obvious next step is a small backend with a GitHub webhook, so every PR gets a review and every resolved review thread becomes memory automatically.&lt;/p&gt;

&lt;p&gt;If you're building agents that interact with the same people repeatedly, it's worth reading up on &lt;a href="https://vectorize.io/what-is-agent-memory" rel="noopener noreferrer"&gt;how agent memory differs from RAG&lt;/a&gt;. The difference I felt wasn't that the model got smarter. It's that it finally knew who it was talking to.&lt;/p&gt;

&lt;p&gt;The code is on GitHub: &lt;a href="https://github.com/mehwishafsa/blockwise" rel="noopener noreferrer"&gt;Blockwise repository&lt;/a&gt;, and it's built on &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;Hindsight&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>python</category>
      <category>code</category>
    </item>
  </channel>
</rss>
