<?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: anudeep Grs</title>
    <description>The latest articles on DEV Community by anudeep Grs (@anudeep_grs_7ea26089d2b7c).</description>
    <link>https://dev.to/anudeep_grs_7ea26089d2b7c</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%2F4078538%2F80f2f7f2-43b1-4154-82f1-0bc9ecc22ddc.png</url>
      <title>DEV Community: anudeep Grs</title>
      <link>https://dev.to/anudeep_grs_7ea26089d2b7c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anudeep_grs_7ea26089d2b7c"/>
    <language>en</language>
    <item>
      <title>How I Wired Hindsight Memory into a FastAPI Sales Agent in Under 100 Lines</title>
      <dc:creator>anudeep Grs</dc:creator>
      <pubDate>Tue, 29 Sep 2026 17:09:48 +0000</pubDate>
      <link>https://dev.to/anudeep_grs_7ea26089d2b7c/-how-i-wired-hindsight-memory-into-a-fastapi-sales-agent-in-under-100-lines-4d18</link>
      <guid>https://dev.to/anudeep_grs_7ea26089d2b7c/-how-i-wired-hindsight-memory-into-a-fastapi-sales-agent-in-under-100-lines-4d18</guid>
      <description>&lt;p&gt;&lt;em&gt;Role: Backend Engineer&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Most AI agents I've built have the same flaw. Every conversation starts from scratch. No memory of what worked last time, no awareness of past failures, nothing connecting the current conversation to a similar one from six months ago.&lt;/p&gt;

&lt;p&gt;When we started building DealMind, I decided to fix this at the infrastructure layer rather than bolting something on later. Here's exactly how we wired Vectorize Hindsight into our FastAPI backend to give the sales agent persistent, searchable, cross-deal memory - and what I learned doing it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;Our backend is FastAPI. The Hindsight integration lives in a single file called &lt;code&gt;hindsight_bridge.py&lt;/code&gt; that wraps the three core functions. The import in &lt;code&gt;deal_agent.py&lt;/code&gt; ends up being pretty clean:&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;hindsight_bridge&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;recall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retain&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three functions. That's the entire memory layer. Everything else builds on top of those three.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1 - Retaining Memories
&lt;/h2&gt;

&lt;p&gt;When a deal closes, we retain its transcript into a named Hindsight bank. Each deal gets its own document ID so we can reference and cite exact sources in the coaching output later.&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;retain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;bank_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;historical-deals&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;document_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meridian-deal-summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;deal_transcript_text&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;bank_id&lt;/code&gt; is the memory namespace. We use one bank for all historical deals (&lt;code&gt;historical-deals&lt;/code&gt;) and a separate bank per active deal - so the Acme Corp deal has its own bank (&lt;code&gt;acme-corp-deal&lt;/code&gt;) that only holds call notes from that deal. Keeping them separate matters a lot. It lets us do two very different recalls depending on what we're looking for.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2 - The Recall Pipeline
&lt;/h2&gt;

&lt;p&gt;This is where it gets interesting. Every time a customer says something during a live deal, we fire two recall calls in parallel:&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;# Recall from all past deals
&lt;/span&gt;&lt;span class="n"&gt;history_memories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;recall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;bank_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;historical-deals&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;budget&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_results&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;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Recall from the current deal's own transcripts
&lt;/span&gt;&lt;span class="n"&gt;deal_memories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;recall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;bank_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deal_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;budget&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_results&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;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First recall searches across the entire company's deal history. Second recall searches only the current deal's call notes. We combine both into the Groq prompt so the agent has cross-deal historical context and current-deal context at the same time.&lt;/p&gt;

&lt;p&gt;We also pull out the document IDs of whatever got recalled:&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="n"&gt;recalled_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;doc id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;history_memories&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These come back to the frontend so the UI can show exactly which past deal was recalled for each coaching turn. The user sees &lt;code&gt;meridian-deal-summary (LOST $380K)&lt;/code&gt; and &lt;code&gt;dataflow-deal-summary (LOST $290K)&lt;/code&gt; show up as coloured pills in real time.&lt;/p&gt;

&lt;p&gt;![deal_agent.py - recall() pipeline pulling from historical-deals bank and current deal bank]&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%2Fjzr51vwdfd0a6kftpbdk.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%2Fjzr51vwdfd0a6kftpbdk.png" alt=" " width="799" height="423"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Lines 727-751: Two targeted recall() calls - one for all-time historical deals, one for the current deal's own call transcripts. Both feed into the same Groq prompt.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 3 - Groq Takes Over
&lt;/h2&gt;

&lt;p&gt;The recalled memories go straight into the Groq user prompt:&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="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&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;Customer just said: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"\n\n&lt;/span&gt;&lt;span class="sh"&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;Conversation so far:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;conv_text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&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;Historical deal patterns (won/lost):&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;history_context&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&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;Current deal memories:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;deal_context&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Based on historical patterns, provide coaching for the sales rep.&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;Groq generates a structured JSON response - coaching type, reference deal, the pattern from that deal, the advice, and the exact words the rep should say. The whole thing runs in under a second.&lt;/p&gt;

&lt;p&gt;![deal_agent.py - Groq system prompt and user prompt with memory context injected]&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%2Ftt7bh90gs27vtynct4iq.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%2Ftt7bh90gs27vtynct4iq.png" alt=" " width="799" height="423"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Lines 759-776: The system prompt defines the JSON output schema. The user prompt injects the recalled historical deal patterns directly before asking Groq to generate coaching.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Before and After - What Recall Actually Changes
&lt;/h2&gt;

&lt;p&gt;Without the recalled memories in the prompt, Groq gives you generic advice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"synapse_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"warning"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reference_deal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"General best practice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Price negotiations should involve all stakeholders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"suggestion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Make sure InfoSec is aligned before discussing price"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"coached_reply"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Let me make sure we have full alignment before discussing pricing..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the Meridian Corp memory recalled - the one where we lost $380K because the price was negotiated before InfoSec sign-off - Groq generates something completely different:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"synapse_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"warning"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reference_deal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Meridian Corp - LOST $380K"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rep agreed to a 15% discount in Week 3 before InfoSec gatekeeper Elena Vasquez had been engaged. When Elena joined in Week 5, she blocked the multi-tenant architecture. No leverage left."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"suggestion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Do not discuss pricing until Priya Sharma (InfoSec) has formally signed off."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"coached_reply"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Robert, before we talk numbers I want to make sure Priya has everything she needs from our compliance team."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model is the same. The prompt structure is the same. The only difference is what's in the memory context. That's the whole point.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Honest Lesson Here
&lt;/h2&gt;

&lt;p&gt;We initially tried to do everything with one recall call, high &lt;code&gt;max_results&lt;/code&gt;, pulling everything at once. The coaching got noisy. Too much context made the model unfocused - it would reference irrelevant details and hedge its advice.&lt;/p&gt;

&lt;p&gt;Splitting into two targeted recalls (historical + current deal) and capping at 3 results each fixed this almost immediately. Less context, sharper output. It felt counterintuitive at first but it makes sense in hindsight - the model does better when it has specific, relevant examples rather than a pile of loosely related text.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/grsanudeep42-cmd/dealmind" rel="noopener noreferrer"&gt;https://github.com/grsanudeep42-cmd/dealmind&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Demo video:&lt;/strong&gt; &lt;a href="https://youtu.be/pxUxM-SIMSk" rel="noopener noreferrer"&gt;https://youtu.be/pxUxM-SIMSk&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Resources on Hindsight and agent memory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;https://github.com/vectorize-io/hindsight&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hindsight.vectorize.io/" rel="noopener noreferrer"&gt;https://hindsight.vectorize.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vectorize.io/what-is-agent-memory" rel="noopener noreferrer"&gt;https://vectorize.io/what-is-agent-memory&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Shoutout to &lt;a href="https://code.in" rel="noopener noreferrer"&gt;@Code.in&lt;/a&gt; for running this challenge.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>[Bug Smash] The Amnesiac ORAM: Fixing Oblivious RAM That Forgot Everything</title>
      <dc:creator>anudeep Grs</dc:creator>
      <pubDate>Sat, 15 Aug 2026 07:19:39 +0000</pubDate>
      <link>https://dev.to/anudeep_grs_7ea26089d2b7c/bug-smash-the-amnesiac-oram-fixing-oblivious-ram-that-forgot-everything-1hg8</link>
      <guid>https://dev.to/anudeep_grs_7ea26089d2b7c/bug-smash-the-amnesiac-oram-fixing-oblivious-ram-that-forgot-everything-1hg8</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/bugsmash"&gt;DEV's Summer Bug Smash: Clear the Lineup&lt;/a&gt; powered by &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;I've been working on &lt;strong&gt;Styx OS&lt;/strong&gt; — a custom x86-64 microkernel I'm building completely from scratch. It handles everything from the bootloader up through a capability-based userspace. The whole philosophy behind Styx OS is that you shouldn't even trust your own hardware. So, it packs in features like FIDO2 pre-boot auth, TPM 2.0 attestation, and AES-256-XTS encrypted storage. &lt;/p&gt;

&lt;p&gt;Recently, I decided to tackle an experimental feature: adapting &lt;strong&gt;PathORAM (Oblivious RAM)&lt;/strong&gt; directly to physical USB storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug Fix or Performance Improvement
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Bug: The Amnesiac ORAM&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So here's the idea behind PathORAM: even if your disk is completely encrypted, if an attacker can monitor &lt;em&gt;which&lt;/em&gt; physical sectors you are reading and writing, they can still figure out what you're doing. PathORAM stops this by constantly shuffling data across the disk every single time you access it. To the outside world, your physical access pattern just looks like uniform, random noise.&lt;/p&gt;

&lt;p&gt;I spent hours building the full algorithm. I had the position maps, the path eviction, stash management—everything. I wrote unit tests, and they all passed perfectly. &lt;/p&gt;

&lt;p&gt;Then, I actually looked closely at my memory layout:&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="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;oram_bucket_t&lt;/span&gt; &lt;span class="n"&gt;oram_tree&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ORAM_NUM_NODES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt;      &lt;span class="n"&gt;pos_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ORAM_NUM_LEAVES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yep. The entire ORAM tree—the massive structure that was supposed to be shuffling encrypted blocks on my USB drive—was just a &lt;code&gt;static&lt;/code&gt; array. Sitting in RAM. It wasn't touching my physical storage at all.&lt;/p&gt;

&lt;p&gt;The math was beautiful, but the security? Non-existent. There was no USB bus involved, so there was no access pattern to hide. To make matters worse, because it was in RAM, every "securely stored" byte just vanished into the void the second I rebooted the machine. I had essentially built the world's most cryptographically complex volatile variable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;To actually fix this, I had to rip out the in-RAM array entirely and wire every single read and write through my USB Mass Storage (&lt;code&gt;usb_msc&lt;/code&gt;) driver so it mapped to physical Logical Block Addresses (LBAs).&lt;/p&gt;

&lt;p&gt;You can check out the exact commit where I made the jump from RAM to physical disk here:&lt;br&gt;
&lt;a href="https://github.com/grsanudeep42-cmd/styxos/commit/adee0b7" rel="noopener noreferrer"&gt;grsanudeep42-cmd/styxos commit adee0b7&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a look at the core diff:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;--- a/kernel/oram.c
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/kernel/oram.c
&lt;/span&gt;&lt;span class="p"&gt;@@ -1,15 +1,22 @@&lt;/span&gt;
&lt;span class="gi"&gt;+/* USB sector layout for ORAM */
+#define ORAM_META_LBA    499U   /* single sector: magic + posmap header */
+#define ORAM_BASE_LBA    500U   /* start of tree: ORAM_NUM_NODES * ORAM_Z sectors */
+#define ORAM_POSMAP_LBA  1008U  /* position map: ORAM_NUM_LEAVES * 4 bytes */
+#define ORAM_MAGIC       0x4F52414DU  /* "ORAM" */
+
&lt;/span&gt;&lt;span class="gd"&gt;-static oram_bucket_t oram_tree[ORAM_NUM_NODES];
-static uint32_t      pos_map[ORAM_NUM_LEAVES];
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+/* ── Physical USB I/O for ORAM ────────────────────────────────────────── */
+static void oram_read_block(uint32_t node, uint32_t slot, oram_block_t *out) {
+    uint32_t lba = ORAM_BASE_LBA + node * ORAM_Z + slot;
+    uint8_t  buf[512];
+    usb_msc_read_sector(lba, buf);
+    memcpy(out, buf, sizeof(oram_block_t));
+    g_oram_sector_reads++;
+}
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+static void oram_write_block(uint32_t node, uint32_t slot, const oram_block_t *blk) {
+    uint32_t lba = ORAM_BASE_LBA + node * ORAM_Z + slot;
+    uint8_t  buf[512];
+    memset(buf, 0, 512);
+    memcpy(buf, blk, sizeof(oram_block_t));
+    usb_msc_write_sector(lba, buf);
+    g_oram_sector_writes++;
+}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  My Improvements
&lt;/h2&gt;

&lt;p&gt;Fixing this meant more than just swapping a RAM array for a disk write function. To make it survive a reboot and actually be secure, I had to completely overhaul the architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Persistent Position Maps&lt;/strong&gt;: The position map is now physically written to a dedicated USB sector (&lt;code&gt;ORAM_POSMAP_LBA&lt;/code&gt;) after every access and reloaded when the OS boots. It finally remembers where it put things!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First-Boot Formatting&lt;/strong&gt;: I added a startup check. If the kernel doesn't find the &lt;code&gt;ORAM_MAGIC&lt;/code&gt; marker on the expected sector, it triggers a format phase—filling the disk sectors with dummy blocks and creating a fresh randomized position map.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSPRNG Integration&lt;/strong&gt;: I originally used a seeded LCG (&lt;code&gt;lcg_rand()&lt;/code&gt;) for assigning leaves. But since that's deterministic, an attacker could guess the "random" leaf assignments and predict the access pattern. I swapped it out to use the kernel's cryptographically secure PRNG (&lt;code&gt;csprng_u32()&lt;/code&gt;). &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Tradeoff:&lt;/strong&gt;&lt;br&gt;
To be completely honest, writing the position map to the USB drive on &lt;em&gt;every single access&lt;/em&gt; is a massive I/O bottleneck. I prioritized absolute security and crash-consistency over raw speed. Journaling or batching these writes is the obvious next step, but for now, the bug is smashed and the data actually touches the metal.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
    </item>
  </channel>
</rss>
