<?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: anassBld</title>
    <description>The latest articles on DEV Community by anassBld (@anasbuilds997).</description>
    <link>https://dev.to/anasbuilds997</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%2F4079476%2Ff38b0751-2949-421a-81d7-74c78bced305.jpg</url>
      <title>DEV Community: anassBld</title>
      <link>https://dev.to/anasbuilds997</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anasbuilds997"/>
    <language>en</language>
    <item>
      <title>Your AI Agent Doesn't Need More Memory. It Needs Receipts.</title>
      <dc:creator>anassBld</dc:creator>
      <pubDate>Sun, 16 Aug 2026 01:15:21 +0000</pubDate>
      <link>https://dev.to/anasbuilds997/your-ai-agent-doesnt-need-more-memory-it-needs-receipts-1e3m</link>
      <guid>https://dev.to/anasbuilds997/your-ai-agent-doesnt-need-more-memory-it-needs-receipts-1e3m</guid>
      <description>&lt;p&gt;An AI agent can remember a 30-page conversation and still perform the same action twice.&lt;/p&gt;

&lt;p&gt;It sends a request. The connection times out. The agent remembers the goal, the plan, and the tool&lt;br&gt;
call—but not whether the outside system changed. So it tries again.&lt;/p&gt;

&lt;p&gt;That is not a vector-memory problem. It is an action-receipt problem.&lt;/p&gt;
&lt;h2&gt;
  
  
  The missing memory layer
&lt;/h2&gt;

&lt;p&gt;“Agent memory” often means conversation history, retrieved documents, or durable project knowledge.&lt;br&gt;
Those are useful, but they answer questions about what the agent knew—not what happened in another&lt;br&gt;
system.&lt;/p&gt;

&lt;p&gt;I find it useful to separate four layers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;th&gt;Typical retention&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Context&lt;/td&gt;
&lt;td&gt;What did the agent know?&lt;/td&gt;
&lt;td&gt;Task-scoped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plan&lt;/td&gt;
&lt;td&gt;What did it intend to do?&lt;/td&gt;
&lt;td&gt;Until the task is reviewed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attempt&lt;/td&gt;
&lt;td&gt;What request did it submit?&lt;/td&gt;
&lt;td&gt;Until reconciled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effect&lt;/td&gt;
&lt;td&gt;What external change was verified?&lt;/td&gt;
&lt;td&gt;Durable audit record&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first two help reasoning. The last two prevent duplicate emails, repeated publications,&lt;br&gt;
double-created listings, and other expensive “helpful” retries.&lt;/p&gt;

&lt;p&gt;More context does not close this gap. A model can recall the exact request and still not know&lt;br&gt;
whether a server committed it before the connection disappeared.&lt;/p&gt;
&lt;h2&gt;
  
  
  Timeout is not failure
&lt;/h2&gt;

&lt;p&gt;Before submission, failure is simple: nothing was sent, so retrying may be safe.&lt;/p&gt;

&lt;p&gt;After submission, failure is ambiguous. A timeout, connection reset, or unreadable response can&lt;br&gt;
mean either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the platform never received the request; or&lt;/li&gt;
&lt;li&gt;the platform completed it, but the response never reached the agent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Treating both cases as “failed” converts a transport problem into a duplicate-action bug.&lt;/p&gt;

&lt;p&gt;The operation therefore needs a state that most happy-path workflows omit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;planned -&amp;gt; submitted -&amp;gt; succeeded
                    \-&amp;gt; rejected
                    \-&amp;gt; outcome_unknown -&amp;gt; reconciling
                                         \-&amp;gt; succeeded
                                         \-&amp;gt; safe_to_retry
                                         \-&amp;gt; manual_review
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;outcome_unknown&lt;/code&gt; is not an error message to hide. It is durable knowledge about the limit of what&lt;br&gt;
the system can currently prove.&lt;/p&gt;
&lt;h2&gt;
  
  
  What an action receipt records
&lt;/h2&gt;

&lt;p&gt;A receipt should be written before the external request. Otherwise the precise failure that makes&lt;br&gt;
it valuable can also prevent it from existing.&lt;/p&gt;

&lt;p&gt;A small receipt can contain:&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;"operation_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"20260816T012030Z-1fd54b31a2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"operation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"articles.create"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/api/articles"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"submitted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"intent_fingerprint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha256:…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"submitted_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-08-16T01:20:30Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"external_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"authentication_recorded"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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 fingerprint should be calculated from an allowlisted or redacted representation of the intent,&lt;br&gt;
not from secrets. The receipt needs enough identity to recognize the effect later; it does not need&lt;br&gt;
to become a second credentials store.&lt;/p&gt;

&lt;p&gt;This is also different from a log line. Logs describe events. A receipt is an operation record with&lt;br&gt;
a lifecycle. The system updates the same record as its knowledge changes.&lt;/p&gt;
&lt;h2&gt;
  
  
  I added this to a publishing CLI
&lt;/h2&gt;

&lt;p&gt;I tested the pattern in a small CLI that writes to the DEV API. The CLI already previewed mutations,&lt;br&gt;
required explicit confirmation, wrote a private intent file, and never retried a write after a&lt;br&gt;
network failure.&lt;/p&gt;

&lt;p&gt;But the intent file stayed an intent file forever. A successful response did not advance it to&lt;br&gt;
&lt;code&gt;succeeded&lt;/code&gt;, and an ambiguous transport failure did not advance it to &lt;code&gt;outcome_unknown&lt;/code&gt;. The safety&lt;br&gt;
rule existed in the client, while the durable state lagged behind it.&lt;/p&gt;

&lt;p&gt;The corrected shape is deliberately boring:&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;receipt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;record_intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sanitized_request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receipt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;submitted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;submitted_at&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;send_once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ExplicitRejection&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receipt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rejected&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;TransportFailure&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receipt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outcome_unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;receipt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;succeeded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;external_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;completed_at&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;now&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;There is intentionally no retry in that exception path. Tests cover success, explicit rejection,&lt;br&gt;
and ambiguous failure as different receipt states.&lt;/p&gt;

&lt;p&gt;One implementation detail mattered more than I expected: state updates should be atomic. Replacing&lt;br&gt;
the receipt through a private temporary file avoids turning a process interruption into half a JSON&lt;br&gt;
document—the audit system creating its own ambiguous evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reconcile the world, not the agent's story
&lt;/h2&gt;

&lt;p&gt;An unknown outcome is resolved with a read, not another write.&lt;/p&gt;

&lt;p&gt;The reconciler should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Query the external system by its idempotency key or returned identifier when one exists.&lt;/li&gt;
&lt;li&gt;Otherwise perform a bounded search and match the smallest safe intent fingerprint.&lt;/li&gt;
&lt;li&gt;Mark the operation &lt;code&gt;succeeded&lt;/code&gt; if the intended effect exists.&lt;/li&gt;
&lt;li&gt;Mark it &lt;code&gt;safe_to_retry&lt;/code&gt; only when absence is actually provable and the operation permits retry.&lt;/li&gt;
&lt;li&gt;Send every remaining case to &lt;code&gt;manual_review&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is where API design changes the safety envelope. A platform with idempotency keys and exact&lt;br&gt;
read-after-write lookup is much easier to automate safely than one with neither. When the platform&lt;br&gt;
offers no reliable way to prove absence, “I cannot tell” is the correct answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Receipts are evidence, not truth
&lt;/h2&gt;

&lt;p&gt;Receipts solve one narrow problem: what request was attempted, what the transport reported, and&lt;br&gt;
what external effect was later observed.&lt;/p&gt;

&lt;p&gt;They do not prove that the request was wise, that the payload was semantically correct, or that the&lt;br&gt;
verification query inspected the right thing. A perfectly maintained receipt can preserve a bad&lt;br&gt;
decision with excellent fidelity.&lt;/p&gt;

&lt;p&gt;That means receipts belong beside—not instead of—policy checks, human approval for consequential&lt;br&gt;
actions, semantic validation, and negative controls for the verifier itself.&lt;/p&gt;

&lt;p&gt;There are other limits too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;eventual consistency can make a successful effect temporarily invisible;&lt;/li&gt;
&lt;li&gt;two similar operations may not have a unique fingerprint;&lt;/li&gt;
&lt;li&gt;some APIs expose no idempotency key or stable lookup;&lt;/li&gt;
&lt;li&gt;a crashed process can leave a submitted operation that still needs recovery;&lt;/li&gt;
&lt;li&gt;retention and redaction rules must match the sensitivity of the action.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those limits are exactly why &lt;code&gt;manual_review&lt;/code&gt; belongs in the state machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should an agent be allowed to forget?
&lt;/h2&gt;

&lt;p&gt;Scratch context can expire. Old plans can be archived. Failed approaches can become history.&lt;/p&gt;

&lt;p&gt;But an externally visible attempt with an unknown outcome should not be forgotten or summarized&lt;br&gt;
away. Keep it until the world has been reconciled with the agent's intent.&lt;/p&gt;

&lt;p&gt;The practical question is not only, “What does the agent remember?”&lt;/p&gt;

&lt;p&gt;It is: &lt;strong&gt;What can the system prove happened before the agent acts again?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Which external write in your system is hardest to reconcile after a timeout?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>architecture</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
