<?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: Praneeta Bapanapalli</title>
    <description>The latest articles on DEV Community by Praneeta Bapanapalli (@praneeta_bapanapalli).</description>
    <link>https://dev.to/praneeta_bapanapalli</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%2F4147551%2Fd78f14d0-0e59-4881-9d96-6fe3352d74b1.png</url>
      <title>DEV Community: Praneeta Bapanapalli</title>
      <link>https://dev.to/praneeta_bapanapalli</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/praneeta_bapanapalli"/>
    <language>en</language>
    <item>
      <title>Hindsight Taught My AP Agent Rules Nobody Wrote Down</title>
      <dc:creator>Praneeta Bapanapalli</dc:creator>
      <pubDate>Mon, 28 Sep 2026 17:18:14 +0000</pubDate>
      <link>https://dev.to/praneeta_bapanapalli/hindsight-taught-my-ap-agent-rules-nobody-wrote-down-2dc0</link>
      <guid>https://dev.to/praneeta_bapanapalli/hindsight-taught-my-ap-agent-rules-nobody-wrote-down-2dc0</guid>
      <description>&lt;p&gt;The most expensive sentence in accounts payable is "just ask the controller." Our agent asked the controller about every failed invoice match, including ones the controller had answered the same way forty times.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Precedent&lt;/strong&gt;, an exception-handling agent for accounts payable, to fix that. The interesting part isn't the LLM. It's what happens when you give it &lt;a href="https://vectorize.io/what-is-agent-memory" rel="noopener noreferrer"&gt;Hindsight agent memory&lt;/a&gt; and then change the rules underneath it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: rules that live in people's heads
&lt;/h2&gt;

&lt;p&gt;When an invoice fails a three-way match against the PO and goods receipt, a person decides what to do. Over time they build vendor-specific habits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sunrise Logistics bills freight outside the PO. Approve up to 8%.&lt;/li&gt;
&lt;li&gt;Nizam Facility Services re-issues invoices with an &lt;code&gt;-R&lt;/code&gt; suffix. Reject the duplicate.&lt;/li&gt;
&lt;li&gt;Charminar Print &amp;amp; Pack posts goods receipts late. Hold, don't escalate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is in the ERP. A stateless agent can't know it, so it does the only safe thing: escalate everything. Safe, and useless.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it hangs together
&lt;/h2&gt;

&lt;p&gt;Each invoice goes through four steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;recall&lt;/code&gt; precedent for this vendor and exception from Hindsight.&lt;/li&gt;
&lt;li&gt;The LLM (Groq, &lt;code&gt;gpt-oss-120b&lt;/code&gt;) picks &lt;code&gt;APPROVE&lt;/code&gt;, &lt;code&gt;REJECT&lt;/code&gt;, &lt;code&gt;HOLD&lt;/code&gt; or &lt;code&gt;ESCALATE&lt;/code&gt;, and must cite a precedent.&lt;/li&gt;
&lt;li&gt;Guardrails in code check the answer.&lt;/li&gt;
&lt;li&gt;If a human was involved (escalation, or a correction of a wrong auto-decision), that resolution is &lt;code&gt;retain&lt;/code&gt;ed as a dated memory.&lt;/li&gt;
&lt;/ol&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%2Fogg5fdcb1h5yzeatc1ab.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%2Fogg5fdcb1h5yzeatc1ab.png" alt=" " width="797" height="142"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Retention is just a reviewer note in plain language, with the invoice date as the timestamp:&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;c&lt;/span&gt;&lt;span class="p"&gt;.&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="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bank&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;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retain_async&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recall pulls semantic, keyword, entity-graph and temporal matches, so "Sunrise freight 7%" finds the right notes even when the wording differs:&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;r&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;c&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&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;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_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A before/after example
&lt;/h2&gt;

&lt;p&gt;Take a Sunrise Logistics invoice that is 7% over the PO because of freight.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Without memory:&lt;/strong&gt; the agent sees a variance it has no rule for and escalates. The controller answers "fine, it's freight" for the forty-first time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;With Hindsight:&lt;/strong&gt; &lt;code&gt;recall&lt;/code&gt; returns the earlier reviewer notes about Sunrise freight. The agent approves and cites them. No human is involved.&lt;/li&gt;
&lt;/ul&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%2Fnktgk60cq576b3o0wb68.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%2Fnktgk60cq576b3o0wb68.png" alt=" " width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The through-line: memory must not outrank policy
&lt;/h2&gt;

&lt;p&gt;The first version trusted precedent too much. If a controller approved a large invoice once, the agent happily learned "large is fine." That's how memory turns into a compliance incident.&lt;/p&gt;

&lt;p&gt;So the hard limit lives in code, before the model is called:&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;if&lt;/span&gt; &lt;span class="n"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HARD_LIMIT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Decision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ESCALATE&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;Above policy limit; human sign-off required.&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;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two more rules came from the same lesson. Any non-escalation action must cite a recalled precedent, otherwise it's forced back to &lt;code&gt;ESCALATE&lt;/code&gt;. And unparseable model output escalates rather than guessing. Memory makes the agent more autonomous; these rules keep that autonomy earned rather than assumed.&lt;/p&gt;

&lt;p&gt;I also built decoy vendors with no standing rules. If the agent starts approving their exceptions because a &lt;em&gt;different&lt;/em&gt; vendor's precedent looked similar, that shows up as a wrong auto-resolution in the eval.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I didn't expect: rules change
&lt;/h2&gt;

&lt;p&gt;Halfway through my replay, Deccan Office Supplies' contract changes. Price variance up to 2% used to be fine. Now it's zero tolerance: hold and ask for a credit note.&lt;/p&gt;

&lt;p&gt;An agent with a static rulebook keeps approving. An agent with an append-only pile of notes sees conflicting precedent and has to guess. Hindsight consolidates related facts into observations and updates them as new evidence arrives, keeping history rather than overwriting it. My prompt says the most recent precedent wins, and the retained corrections ("Agent had proposed APPROVE; reviewer corrected it") give it exactly the evidence to switch.&lt;/p&gt;

&lt;p&gt;In the eval this shows up as a dip in the learning curve right after the contract change, followed by recovery as corrected precedent accumulates.&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%2F84lzay229d85byzlt8gr.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%2F84lzay229d85byzlt8gr.png" alt="Learning curve showing the dip after the Deccan contract change and the recovery" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;I replay the same 150-invoice stream through two arms with identical prompts and ERP data: no memory, and Hindsight. The harness writes &lt;code&gt;results.json&lt;/code&gt; and a learning curve.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No memory: &lt;strong&gt;X&lt;/strong&gt; of 150 invoices resolved without a human.&lt;/li&gt;
&lt;li&gt;Hindsight: &lt;strong&gt;Y&lt;/strong&gt; of 150 resolved without a human, with &lt;strong&gt;Z&lt;/strong&gt; wrong auto-resolutions and &lt;strong&gt;0&lt;/strong&gt; policy breaches.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;brief&lt;/code&gt; command shows the same memory through &lt;code&gt;reflect&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; precedent.run brief &lt;span class="nt"&gt;--vendor&lt;/span&gt; &lt;span class="s2"&gt;"Deccan Office Supplies"&lt;/span&gt; &lt;span class="nt"&gt;--bank&lt;/span&gt; &amp;lt;bank&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask it about Deccan and it answers with the old 2% tolerance, the date the contract changed, and the new hold-and-credit-note rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  What didn't work (and limits)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;"Most recent precedent wins" is an instruction in the prompt, not something enforced in code. Right after a rule change the agent can still pick stale precedent until corrections accumulate. That's the dip in the curve.&lt;/li&gt;
&lt;li&gt;Recall is only as good as the reviewer notes. Vague notes produce vague precedent.&lt;/li&gt;
&lt;li&gt;Guardrails catch the cases I thought of. Decoy vendors help, but they don't cover everything.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I'd tell another engineer
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Write the eval before the agent.&lt;/strong&gt; A seeded stream with hidden ground-truth rules made every claim testable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guardrails go in code, not the prompt.&lt;/strong&gt; The limit check runs before the model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make autonomy cite its source.&lt;/strong&gt; "No citation, no action" cut confident wrong answers more than any prompt tweak.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test memory against change, not just recall.&lt;/strong&gt; Remembering is easy. Updating is the hard part.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timestamp everything.&lt;/strong&gt; Passing the invoice date to &lt;code&gt;retain&lt;/code&gt; is what lets recency matter.&lt;/li&gt;
&lt;/ol&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%2F6l85tx4s9ld3ucp8nv3b.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%2F6l85tx4s9ld3ucp8nv3b.png" alt=" " width="800" height="426"&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%2F2n0jkbfcag0bqi1wn02f.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%2F2n0jkbfcag0bqi1wn02f.png" alt=" " width="800" height="420"&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%2Fvr832cv3thj3bb01cs4m.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%2Fvr832cv3thj3bb01cs4m.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code is on GitHub: &lt;a href="https://github.com/honeyharshita/commit-and-chills" rel="noopener noreferrer"&gt;commit-and-chills&lt;/a&gt;. To try the memory layer yourself, start with the &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;Hindsight GitHub repository&lt;/a&gt; and the &lt;a href="https://hindsight.vectorize.io/" rel="noopener noreferrer"&gt;Hindsight documentation&lt;/a&gt;.&lt;/p&gt;

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