<?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: Madhan Raj K</title>
    <description>The latest articles on DEV Community by Madhan Raj K (@madhan_rajmadhan_f6030ac).</description>
    <link>https://dev.to/madhan_rajmadhan_f6030ac</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%2F4235433%2F2b2a6955-1da6-4270-8315-5c3444261295.png</url>
      <title>DEV Community: Madhan Raj K</title>
      <link>https://dev.to/madhan_rajmadhan_f6030ac</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/madhan_rajmadhan_f6030ac"/>
    <language>en</language>
    <item>
      <title>The Fix Was Already in Our Postmortems. I Built an On-Call Agent That Actually Remembers It.</title>
      <dc:creator>Madhan Raj K</dc:creator>
      <pubDate>Mon, 09 Nov 2026 17:19:15 +0000</pubDate>
      <link>https://dev.to/madhan_rajmadhan_f6030ac/the-fix-was-already-in-our-postmortems-i-built-an-on-call-agent-that-actually-remembers-it-23ag</link>
      <guid>https://dev.to/madhan_rajmadhan_f6030ac/the-fix-was-already-in-our-postmortems-i-built-an-on-call-agent-that-actually-remembers-it-23ag</guid>
      <description>&lt;p&gt;Here's what surprised me most about incident response. The fix for many outages is already written down, usually in a postmortem from three weeks ago, and the on-call engineer still spends twenty minutes trying the wrong thing first.&lt;/p&gt;

&lt;p&gt;In the synthetic incident history I made for this project, the same payments service fails three times in two months. All three times it looks the same: HTTP 5xx on &lt;code&gt;/v2/charge&lt;/code&gt;, right after a deploy. And in two of those three postmortems, someone writes almost the same sentence: &lt;em&gt;scaling the pods did nothing.&lt;/em&gt; A copilot without memory will suggest scaling the pods again, because nothing tells it that it was already tried.&lt;/p&gt;

&lt;p&gt;So my friend Faraz and I built &lt;strong&gt;RecallOps&lt;/strong&gt;, an incident-response copilot that remembers every past incident. My half of the work was the memory layer: how incidents get stored, how they come back, and how the agent gets better after every resolution. This post is about that part.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/Madhan-raj-k/recall-ops" rel="noopener noreferrer"&gt;https://github.com/Madhan-raj-k/recall-ops&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live site: &lt;a href="https://recall-ops-three.vercel.app" rel="noopener noreferrer"&gt;https://recall-ops-three.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: LLMs are smart, but they start from zero every time
&lt;/h2&gt;

&lt;p&gt;An LLM is good at reasoning about an alert. What it can't know is &lt;em&gt;your&lt;/em&gt; history:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;that &lt;code&gt;payments-api&lt;/code&gt; 5xx after a deploy has meant a bad SDK timeout, a shrunken DB connection pool, and a stale Vault secret,&lt;/li&gt;
&lt;li&gt;that &lt;code&gt;argocd app rollback payments-api&lt;/code&gt; fixed it in minutes,&lt;/li&gt;
&lt;li&gt;that restarting pods only bought two minutes,&lt;/li&gt;
&lt;li&gt;that the payments and DBA teams were the ones who fixed it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stuffing every postmortem into the prompt doesn't scale, and plain vector search over documents loses things like &lt;em&gt;when&lt;/em&gt; something happened, &lt;em&gt;which entities&lt;/em&gt; connect two incidents, and which fix &lt;em&gt;failed&lt;/em&gt;. I wanted real agent memory, not a pile of embeddings. (If the distinction is new to you, Vectorize has a good explainer: &lt;a href="https://vectorize.io/what-is-agent-memory" rel="noopener noreferrer"&gt;What is agent memory?&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Hindsight
&lt;/h2&gt;

&lt;p&gt;I used &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;Hindsight&lt;/a&gt;, an open-source agent memory system from Vectorize. Its API is deliberately small: three verbs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;retain&lt;/strong&gt;: store what happened. Hindsight pulls typed facts and entities out of the text and links them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;recall&lt;/strong&gt;: search it back. It runs semantic, keyword, graph and temporal retrieval in parallel, reranks the results, and cuts them to a token budget.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;reflect&lt;/strong&gt;: an agentic loop that reasons over the whole memory bank and returns a grounded answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those three verbs map almost exactly onto an incident lifecycle: an alert comes in (recall), the engineer needs judgement (reflect), the incident is resolved (retain). The &lt;a href="https://hindsight.vectorize.io/" rel="noopener noreferrer"&gt;Hindsight docs&lt;/a&gt; cover the full model. I used the Python SDK, &lt;code&gt;hindsight-client&lt;/code&gt; 1.2.0, against Hindsight Cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Hindsight sits in the code
&lt;/h2&gt;

&lt;p&gt;I kept every Hindsight call in one file, &lt;code&gt;memory.py&lt;/code&gt;. The rest of the app only sees an &lt;code&gt;IncidentMemory&lt;/code&gt; interface, which made testing much easier (more on that below).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bank design.&lt;/strong&gt; There is one memory bank per on-call organisation (&lt;code&gt;recallops-shopnova-oncall&lt;/code&gt;), not one per service. That was deliberate: the interesting links cross services. A DNS change breaks inventory, or a Redis job evicts carts. When the bank is first used, I configure it with two missions:&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_bank&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bank_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;retain_mission&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;RETAIN_MISSION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;reflect_mission&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;REFLECT_MISSION&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 retain mission tells extraction what matters in a postmortem: the service, symptoms, root cause, the fix that worked, the fix that &lt;em&gt;did not&lt;/em&gt; work, teams, runbooks and time to resolve. It also says to keep exact technical names. The reflect mission makes reflect behave like a senior SRE: cite incident IDs, prefer fixes that worked, warn about the ones that failed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What gets stored.&lt;/strong&gt; Each resolved incident becomes one retained item:&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;def&lt;/span&gt; &lt;span class="nf"&gt;_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;incident&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Incident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;incident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_memory_text&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;incident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;occurred_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context&lt;/span&gt;&lt;span class="sh"&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;postmortem for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;incident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; incident&lt;/span&gt;&lt;span class="sh"&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;document_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;incident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;incident_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;metadata&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;incident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;incident&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tags&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;Three choices here mattered more than I expected:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;timestamp&lt;/code&gt; is when the incident happened&lt;/strong&gt;, not when I stored it, so temporal retrieval can answer "what broke payments last month?"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;document_id&lt;/code&gt; is the incident ID&lt;/strong&gt;, so every recalled fact points back to its source incident.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tags like &lt;code&gt;service:payments-api&lt;/code&gt;&lt;/strong&gt; give me filters for later.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The content itself is a plain narrative ("Root cause: … Fix that worked: … Attempts that did NOT work: …"). I don't do any structuring myself. Extraction is Hindsight's job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recall on every alert.&lt;/strong&gt; When triage runs with memory on:&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;resp&lt;/span&gt; &lt;span class="o"&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;_client&lt;/span&gt;&lt;span class="p"&gt;.&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bank_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;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;types&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;world&lt;/span&gt;&lt;span class="sh"&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;experience&lt;/span&gt;&lt;span class="sh"&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;observation&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_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2048&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="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recall is cut to a token budget rather than a top-k count, and that turned out to be exactly right for an agent. I know how much prompt space I can spare, and Hindsight fills it. The recalled facts, with dates and source incident IDs, go into the Groq LLM prompt and into a "memories recalled" panel, so the engineer can see &lt;em&gt;why&lt;/em&gt; the agent suggests something.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reflect for judgement.&lt;/strong&gt; On top of raw recall, I ask the bank one question: &lt;em&gt;what most likely caused this, what fixed it before, and what should on-call avoid?&lt;/em&gt; That reflect answer is shown to the engineer and passed to the LLM too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The learning loop
&lt;/h2&gt;

&lt;p&gt;This is the part I'm proudest of. After the incident, the engineer fills in a short form: root cause, what fixed it, what didn't. &lt;code&gt;agent.record_resolution()&lt;/code&gt; validates it and retains it straight into the same bank. No retraining and no re-indexing.&lt;/p&gt;

&lt;p&gt;There's a unit test for exactly this loop, and it's the whole idea of the project: the agent gets better because it remembers.&lt;/p&gt;

&lt;p&gt;Then I ran it live against Hindsight Cloud. Before the postmortem, the &lt;code&gt;loyalty-points&lt;/code&gt; alert only recalled loosely related incidents, and the plan guessed "database contention / connection-pool exhaustion (see INC‑1003)". I retained one postmortem through &lt;code&gt;record_resolution()&lt;/code&gt;, and the very next recall, with no waiting, returned it as the top memories. The plan opened with "Postgres lock contention on &lt;code&gt;points_ledger&lt;/code&gt; … (see INC‑20261109‑71C2)" and recommended the replica-and-batching fix.&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%2F0y5670lp4h2i1x26h4tl.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%2F0y5670lp4h2i1x26h4tl.png" alt="Record resolution confirmation" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Same alert, same LLM, same prompt. The only difference is memory:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;PagerDuty SEV1: payments-api 5xx rate 22% on /v2/charge, started 6 minutes after deploy v3.21.0&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These are trimmed quotes from a live run against Hindsight Cloud with &lt;code&gt;openai/gpt-oss-120b&lt;/code&gt; on Groq:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory OFF:&lt;/strong&gt; "Regression introduced in &lt;code&gt;v3.21.0&lt;/code&gt; causing unhandled exceptions in the &lt;code&gt;/v2/charge&lt;/code&gt; handler." Then grep the logs and diff the release. Confidence: "Low – no prior incident data." It's sensible, but it's generic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory ON:&lt;/strong&gt; "Configuration regression introduced in v3.21.0 – e.g., Hikari &lt;code&gt;maximumPoolSize&lt;/code&gt; reduced (as in INC‑1016)", followed by the Stripe timeout (INC‑1001) and stale Vault secret (INC‑1013) hypotheses. It checks &lt;code&gt;maximumPoolSize&lt;/code&gt;, &lt;code&gt;STRIPE_HTTP_TIMEOUT&lt;/code&gt; and the Vault secret version before &lt;code&gt;argocd app rollback payments-api&lt;/code&gt;, and it adds the DBA team. Then the line that matters most: "Avoid: Scaling the payments‑api pods (worsened DB pool exhaustion in INC‑1016). Blind pod restarts (only gave temporary relief in INC‑1001 &amp;amp; INC‑1016)."&lt;/p&gt;

&lt;p&gt;Reflect, on its own, came back with a "What to Avoid (Failed Fixes)" section: "Do NOT scale pods: in both INC-1001 and INC-1016, scaling pods (e.g., from 6 to 12) failed to resolve the issue."&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%2Foeaah755wlhny3rmcz6f.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%2Foeaah755wlhny3rmcz6f.png" alt="Memory OFF vs Memory ON" width="800" height="1300"&gt;&lt;/a&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%2Ff8sw137h1dl529idej16.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%2Ff8sw137h1dl529idej16.png" alt="Hindsight reflect output" width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Built not to fail mid-incident
&lt;/h2&gt;

&lt;p&gt;If Hindsight or Groq fails, triage carries on and shows a warning. Groq calls retry with back-off, and there's a deterministic fallback plan. The 24 unit tests run against a fake Hindsight client, so CI needs no keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  An honest lesson
&lt;/h2&gt;

&lt;p&gt;The first live run taught me something I hadn't expected: recall for the payments alert returned 80 small extracted facts, not 3 incidents. That's Hindsight filling the token budget with granular facts and consolidated observations, which is great for coverage but bloats the prompt. The fix was a one-line cap: &lt;code&gt;MAX_PROMPT_MEMORIES = 30&lt;/code&gt; goes to the LLM, and the UI still shows everything.&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%2Fayyyqpe64idvdmirskz2.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%2Fayyyqpe64idvdmirskz2.png" alt="Memory explorer" width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My first instinct was also to parse "what worked" and "what failed" into neat structured fields myself. I dropped that idea: real postmortems are messy, and hand-written parsing would throw away detail. Retaining the narrative and letting Hindsight extract the facts is the better design. It has a cost, though. Recall returns &lt;em&gt;extracted facts&lt;/em&gt;, not my original lines, so my no-LLM fallback (which looks for "Fix that worked:") is weaker on real Hindsight data than on the offline demo store.&lt;/p&gt;

&lt;p&gt;The bigger limitation is human. Memory is only as good as what gets retained. A postmortem that says "restarted stuff, it worked" teaches the agent nothing. And similar symptoms can have different causes; our payments data has three. RecallOps ranks hypotheses, it doesn't prove one, so the engineer still has to verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Project: &lt;a href="https://github.com/Madhan-raj-k/recall-ops" rel="noopener noreferrer"&gt;https://github.com/Madhan-raj-k/recall-ops&lt;/a&gt; (&lt;code&gt;pip install -r requirements.txt&lt;/code&gt;, &lt;code&gt;python seed.py&lt;/code&gt;, &lt;code&gt;streamlit run app.py&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Hindsight on GitHub: &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;Hindsight docs: &lt;a href="https://hindsight.vectorize.io/" rel="noopener noreferrer"&gt;https://hindsight.vectorize.io/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;What is agent memory: &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;Built with Faraz. The incident data in the repo is synthetic, about a fictional store called ShopNova.&lt;/p&gt;

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