<?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: Aaron Raj</title>
    <description>The latest articles on DEV Community by Aaron Raj (@aaron_raj_06).</description>
    <link>https://dev.to/aaron_raj_06</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%2F4150558%2F32198dde-63a8-4397-bef4-b96412be9f56.png</url>
      <title>DEV Community: Aaron Raj</title>
      <link>https://dev.to/aaron_raj_06</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aaron_raj_06"/>
    <language>en</language>
    <item>
      <title>Hindsight Retain and Recall Made Our Incident Agent Actually Useful</title>
      <dc:creator>Aaron Raj</dc:creator>
      <pubDate>Tue, 29 Sep 2026 18:00:51 +0000</pubDate>
      <link>https://dev.to/aaron_raj_06/hindsight-retain-and-recall-made-our-incident-agent-actually-useful-2ep3</link>
      <guid>https://dev.to/aaron_raj_06/hindsight-retain-and-recall-made-our-incident-agent-actually-useful-2ep3</guid>
      <description>&lt;p&gt;&lt;strong&gt;The Problem With Stateless Agents&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An incident agent that forgets everything is just a polished search engine. We found this out early: every new &lt;code&gt;checkout-api&lt;/code&gt; alert sent to a generic LLM produced the same response regardless of what the team had learned about that service over the previous six months. The agent was technically reasoning—it just had no access to the operational context that actually mattered.&lt;/p&gt;

&lt;p&gt;The fix wasn't a better model. It was giving the agent a memory layer built on &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;Hindsight&lt;/a&gt; that retains resolved incident lessons and recalls them when similar signals appear.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Built&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;IncidentIQ is an incident response dashboard where every resolved incident feeds a growing memory store. The stack is TypeScript throughout: a Vite + React frontend, an Express 5 API, PostgreSQL with Drizzle ORM, and Hindsight handling all memory retain and recall operations. The application has four views—Dashboard, New Incident, Before vs. After, and Agent Memory Gallery.&lt;/p&gt;

&lt;p&gt;The memory lifecycle is the central feature. When engineers close an incident, the resolution captures a lesson. Hindsight retains that lesson, scoped to the service. When the next incident arrives for that service, Hindsight recalls the closest matches before the agent responds. The entire application is organized around this two-way flow.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;IncidentIQ system architecture. Hindsight sits alongside PostgreSQL as a dedicated semantic memory layer.&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%2F7iulzxh2fijc0mjxsrll.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%2F7iulzxh2fijc0mjxsrll.jpg" alt="System architecture showing how the React frontend, Express 5 API, PostgreSQL, and Hindsight connect" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Core Technical Story: Building the Retain Path&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The retain path was harder to design than it looked. The obvious approach—storing resolution notes in the same PostgreSQL database and searching them with LIKE queries—failed in testing immediately. A new incident described as "elevated p95 latency" returned no matches for memories about "connection pool exhaustion cascade," even though those two phrases describe the same failure pattern on &lt;code&gt;checkout-api&lt;/code&gt;. Lexical matching can't bridge that gap.&lt;/p&gt;

&lt;p&gt;We needed semantic retrieval, which meant vector indexing. Rather than building that infrastructure ourselves, we integrated &lt;a href="https://vectorize.io/what-is-agent-memory" rel="noopener noreferrer"&gt;Hindsight's agent memory&lt;/a&gt; layer, which handles embedding, indexing, and similarity-ranked retrieval. Our job was to feed it well-structured memories at the right time.&lt;/p&gt;

&lt;p&gt;The memory type defines what Hindsight retains per resolved incident:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx — the Memory type: what gets written to Hindsight on resolution&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// the recall scope key — recalls filter by this field&lt;/span&gt;
  &lt;span class="nl"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Severity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// description of what happened&lt;/span&gt;
  &lt;span class="nl"&gt;lesson&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// the forward-looking instruction for the agent&lt;/span&gt;
  &lt;span class="nl"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// increments on every recall — passive quality signal&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;lesson&lt;/code&gt; field is the most important. It's not a root cause description—it's a forward-looking instruction. "Connection pool exhausted" is a root cause. "Check pool saturation before increasing application timeouts" is a lesson. That distinction changes what the agent does with recalled information.&lt;/p&gt;

&lt;p&gt;The retain call happens inside the resolve handler, immediately after the engineer confirms the resolution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// App.tsx — submitResolve: writes memory to Hindsight on incident close&lt;/span&gt;
&lt;span class="nf"&gt;setMemories&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`mem-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resolveIncident&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="na"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resolveIncident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// scopes all future recalls&lt;/span&gt;
    &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resolveIncident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resolveIncident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lesson&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lesson&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Keep the first guardrail close to the signal.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nf"&gt;showToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Resolved — a new memory is now active&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;The memory is active immediately. There's no delay, no batch processing, no manual sync.&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%2Fky4b9kgpurjhcsy37djs.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%2Fky4b9kgpurjhcsy37djs.jpg" alt="Full memory retain and recall lifecycle: Incident Resolved → 4-Step Modal → retain() → Hindsight Memory Store → New Incident → recall() → Agent Analysis Panel" width="768" height="1376"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The complete retain/recall lifecycle. Both operations are scoped by service name.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Recall Changes the Agent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The recall path executes on every incident intake. The frontend sends the incident signal and service name to the API, which queries Hindsight for the closest matching memories for that service. The results reach the agent as context before any response is generated.&lt;/p&gt;

&lt;p&gt;In the analysis panel, the recall is made visible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AnalysisPanel — shows recall count when memories are retrieved&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;submitted&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"memory-badge"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BrainCircuit&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; 3 memories recalled
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;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 analysis text then uses the recalled context: "This signal matches a known saturation pattern in the service dependency layer. Start by checking the last deploy and the nearest shared resource. Avoid a broad restart until queue and retry behavior is understood."&lt;/p&gt;

&lt;p&gt;That last sentence—"Avoid a broad restart until queue and retry behavior is understood"—is derived from the &lt;code&gt;payments-worker&lt;/code&gt; lesson retained from a previous retry storm incident. The agent isn't guessing. It's referencing a lesson your team specifically paid for.&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%2Fdhtj1lj34a9uupunx495.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%2Fdhtj1lj34a9uupunx495.jpg" alt="Before vs after comparison: generic LLM response (28% quality) vs memory-grounded Hindsight response (92% quality)" width="800" height="447"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Before vs. After comparison view. Same signal, two paths. Memory changes the first response from generic to grounded.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before vs. After&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The comparison view in IncidentIQ makes the behavioral difference explicit.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Before (without memory):&lt;/strong&gt;&lt;/em&gt; Filing a &lt;code&gt;checkout-api&lt;/code&gt; latency incident returns: "Check application logs, restart the affected pods, and increase the timeout if the issue persists." This treats the incident as novel. It doesn't know the service, doesn't reference any prior pattern, and gives no service-specific first move.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;After (with Hindsight memory):&lt;/strong&gt;&lt;/em&gt; The same signal returns: "Pause the retry amplification, then compare connection-pool saturation against the remembered deploy pattern for checkout-api." The agent names the service, references the recalled pattern, and provides a specific testable hypothesis grounded in what the team already learned.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;hits&lt;/code&gt; counter on each memory tracks how many times it has been recalled. A lesson with 14 recall hits tells the next engineer that this pattern recurs—and that the lesson has been validated by repeated use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Learned&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Semantic mismatch kills keyword retrieval.&lt;/strong&gt;&lt;/em&gt; The incident description and the stored memory rarely use identical language. Hindsight's embedding-based retrieval solves this; LIKE queries do not. This was the single most important technical decision in the integration.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;The lesson field needs a different mental model than root cause.&lt;/strong&gt;&lt;/em&gt; Engineers naturally write root causes when prompted to reflect on an incident. Writing a lesson—something forward-looking that shapes the next engineer's first move—requires an explicit prompt. The separate field and label in the resolution modal make this cognitive shift concrete.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;hits is more useful than it looks.&lt;/strong&gt;&lt;/em&gt; A recall hit counter started as an afterthought. It became the clearest signal in the memory gallery for distinguishing recurring patterns from one-offs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Scoping by service reduces precision loss.&lt;/strong&gt;&lt;/em&gt; Global recall produced too many false matches. Service-scoped recall kept recall relevant without requiring more complex filtering logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The retain/recall pattern in &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;Hindsight&lt;/a&gt; is straightforward to integrate but requires careful design of what you retain and when. The lesson/root-cause distinction, the service scope key, and the timing of the retain call were the decisions that determined whether the recall output was useful or noisy. The &lt;a href="https://hindsight.vectorize.io/" rel="noopener noreferrer"&gt;Hindsight documentation&lt;/a&gt; covers the integration surface. The hard part is always designing what you give it to remember.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>api</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
