<?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: Fadil</title>
    <description>The latest articles on DEV Community by Fadil (@fadillaoegi).</description>
    <link>https://dev.to/fadillaoegi</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%2F1201376%2F15e68b6a-cdc8-47e7-8c1d-a4119e3d3a94.jpeg</url>
      <title>DEV Community: Fadil</title>
      <link>https://dev.to/fadillaoegi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fadillaoegi"/>
    <language>en</language>
    <item>
      <title>Mandate: Giving AI Agents a Memory for Your Money Rules</title>
      <dc:creator>Fadil</dc:creator>
      <pubDate>Tue, 03 Nov 2026 03:24:02 +0000</pubDate>
      <link>https://dev.to/fadillaoegi/mandate-giving-ai-agents-a-memory-for-your-money-rules-2akk</link>
      <guid>https://dev.to/fadillaoegi/mandate-giving-ai-agents-a-memory-for-your-money-rules-2akk</guid>
      <description>&lt;p&gt;&lt;em&gt;Built for **Total Recall — Tatum × Walrus&lt;/em&gt;&lt;em&gt;, Consumer Finance Apps track.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo video (2:39):&lt;/strong&gt; &lt;a href="https://youtu.be/sRa2cWtP8ok" rel="noopener noreferrer"&gt;https://youtu.be/sRa2cWtP8ok&lt;/a&gt; ·&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/fadillaoegi/mandate-walrusxtatum" rel="noopener noreferrer"&gt;https://github.com/fadillaoegi/mandate-walrusxtatum&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: every agent starts from zero
&lt;/h2&gt;

&lt;p&gt;AI agents are starting to pay for things on their own. With protocols like &lt;strong&gt;x402&lt;/strong&gt;, an agent can call an API, get an&lt;br&gt;
&lt;code&gt;HTTP 402 Payment Required&lt;/code&gt;, pay a few cents in USDC and receive the data, all without a human in the loop.&lt;/p&gt;

&lt;p&gt;That is great until you hire your second agent, or restart the first one. Each agent starts from zero:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it doesn't know &lt;strong&gt;your budget&lt;/strong&gt; (fifty cents per item? two dollars a day?),&lt;/li&gt;
&lt;li&gt;it doesn't know &lt;strong&gt;which vendors let you down&lt;/strong&gt; last week,&lt;/li&gt;
&lt;li&gt;it doesn't know &lt;strong&gt;what it already bought&lt;/strong&gt;, so it happily buys the same report twice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you end up with two bad options: approve every purchase by hand, or let agents spend without any real control.&lt;/p&gt;
&lt;h2&gt;
  
  
  The idea: your money rules as portable memory
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Mandate&lt;/strong&gt; keeps the owner's spending rules and purchase history as &lt;strong&gt;memory on Walrus&lt;/strong&gt;. Any agent you authorise with&lt;br&gt;
a &lt;strong&gt;delegate key&lt;/strong&gt; reads the same memory, in any session. Agents pay with &lt;strong&gt;x402 on Sui&lt;/strong&gt;, and Mandate independently&lt;br&gt;
checks each signed transaction's &lt;strong&gt;execution status through Tatum&lt;/strong&gt;. A pending receipt reserves the purchase and&lt;br&gt;
budget until the chain result is known, so an unavailable read does not invite a duplicate payment.&lt;/p&gt;

&lt;p&gt;In one sentence: &lt;em&gt;your money rules, remembered by every agent you hire.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What it looks like
&lt;/h2&gt;

&lt;p&gt;The dashboard walks through six steps (you can watch them in the video):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set the rules.&lt;/strong&gt; Max $0.50 per item, $2.00 per day, ShadyData blocked. Saving writes a &lt;em&gt;rule&lt;/em&gt; memory to Walrus.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The first agent has to ask.&lt;/strong&gt; The Research Agent has no history, so every purchase lands in the owner inbox. I
approve OpenStats (paid over x402, verified via Tatum), reject DataHarbor as &lt;em&gt;too expensive&lt;/em&gt;, and reject + flag
QuickFacts for stale data. Each answer becomes a memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A new session remembers.&lt;/strong&gt; Working memory is wiped. The agent recalls from Walrus and decides five cases alone:
a duplicate is refused, OpenStats is trusted, QuickFacts is flagged, DataHarbor is above my &lt;em&gt;learned&lt;/em&gt; price ceiling,
ShadyData is blocked. Zero questions to me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Another agent obeys too.&lt;/strong&gt; The Shopping Agent was never taught anything. It reads the same memory through the
delegate key and follows the rules immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never trust the merchant.&lt;/strong&gt; A greedy merchant's 402 asks $0.25 for an item I approved at $0.15. The agent refuses to
sign, nothing is charged. At the right price it pays, and Mandate reads the transaction through Tatum: the chain, not
the merchant, determines the execution status.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The owner controls access.&lt;/strong&gt; The dashboard's Revoke action clears sessions and blocks agents in this
application. It does not remove the delegate from the Walrus dashboard. Actual delegate removal is a separate
operation; Mandate also cuts off sessions when a normal relayer request returns HTTP 401.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  How Walrus Memory is used
&lt;/h2&gt;

&lt;p&gt;Every meaningful thing that happens is written as &lt;strong&gt;one immutable memory event&lt;/strong&gt; with the Walrus Memory SDK&lt;br&gt;
(&lt;code&gt;@mysten-incubation/memwal&lt;/code&gt;) against the &lt;strong&gt;Mainnet&lt;/strong&gt; relayer:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mandate_set&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;max $0.50 / item, $2.00 / day, blocked: ShadyData&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;owner_verdict&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;rejected DataHarbor $0.45 — &lt;em&gt;too expensive&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vendor_flag&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;QuickFacts flagged: stale data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;purchase_recorded&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bought os-rainfall-yield from OpenStats for $0.25, tx &lt;code&gt;9RtU…&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;purchase_status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;that tx is &lt;strong&gt;verified&lt;/strong&gt; (or &lt;strong&gt;failed&lt;/strong&gt;) according to Tatum&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each memory is a readable sentence plus a small JSON payload, so it works both for semantic recall and for exact&lt;br&gt;
parsing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[mandate:v1] Owner rejected $0.45 purchase of dh-market-deep-dive from DataHarbor: too expensive || {"kind":"owner_verdict",...}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a session starts, the agent &lt;strong&gt;recalls&lt;/strong&gt; the namespace and rebuilds its knowledge by folding events in time order.&lt;br&gt;
Because Walrus memories are append-only, a correction is never an edit: it is a new event (for example a&lt;br&gt;
&lt;code&gt;purchase_status: failed&lt;/code&gt; after the chain disagreed with a receipt).&lt;/p&gt;

&lt;p&gt;Two practical lessons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Writes are slow, so the app is asynchronous.&lt;/strong&gt; A Walrus write takes about 20 seconds. The agent knows a new memory
immediately; the write runs in the background (&lt;code&gt;pending → stored&lt;/code&gt;) with an &lt;strong&gt;idempotency key&lt;/strong&gt;, so retries never
duplicate the same write. A new session waits for pending writes, then recalls from Walrus. The recorded run
stored all 13 memories successfully; a failed write remains visibly failed and can be retried.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access rejection needs no polling.&lt;/strong&gt; If a normal recall or write returns &lt;code&gt;401&lt;/code&gt;, Mandate clears active sessions.
An unregistered key was tested and rejected. Removing a previously registered delegate was not tested, and an
already-running process cannot notice an external removal until its next authenticated request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the recorded run, &lt;strong&gt;13 memories&lt;/strong&gt; were stored on Walrus Mainnet in namespace &lt;code&gt;mandate-demo-run10&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Tatum is used
&lt;/h2&gt;

&lt;p&gt;Mandate uses Tatum as its &lt;strong&gt;source of truth for payments&lt;/strong&gt;. After an agent pays, Mandate does not believe the&lt;br&gt;
merchant's &lt;code&gt;X-PAYMENT-RESPONSE&lt;/code&gt;; it reads the transaction from Sui through &lt;strong&gt;Tatum's gRPC gateway&lt;/strong&gt; and stores &lt;em&gt;that&lt;/em&gt;&lt;br&gt;
execution status in memory. &lt;em&gt;Audit receipts&lt;/em&gt; re-checks each remembered transaction's status against the chain;&lt;br&gt;
when a known chain result disagrees with memory, a correction event is written.&lt;/p&gt;

&lt;p&gt;A practical lesson: the first JSON-RPC read path did not work in our environment, so we implemented a native&lt;br&gt;
&lt;strong&gt;gRPC&lt;/strong&gt; adapter. Tatum's Mainnet and Testnet gRPC gateways worked in the recorded checks, with transaction reads&lt;br&gt;
around 50–260 ms. The reader sits behind a &lt;code&gt;ChainReader&lt;/code&gt; port, keeping the application independent of the transport.&lt;/p&gt;

&lt;h2&gt;
  
  
  How agents pay: x402 with guardrails
&lt;/h2&gt;

&lt;p&gt;Payments use the x402 &lt;code&gt;exact&lt;/code&gt; scheme on Sui (&lt;code&gt;@t2000/sui-x402&lt;/code&gt;): the merchant answers &lt;code&gt;HTTP 402&lt;/code&gt; with terms, the agent&lt;br&gt;
signs a &lt;strong&gt;gasless USDC transfer&lt;/strong&gt;, and the merchant settles it. Before signing, Mandate's agent checks the merchant's&lt;br&gt;
terms against what the policy approved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;amount&lt;/strong&gt; must equal the approved price,&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;recipient&lt;/strong&gt; must be the vendor's known address,&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;network&lt;/strong&gt; must match.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anything else is refused &lt;em&gt;before&lt;/em&gt; a signature exists. One challenge allows one payment, so replays are refused too.&lt;/p&gt;

&lt;p&gt;In the recorded run, four x402 payments settled on &lt;strong&gt;Sui Testnet&lt;/strong&gt; and each was verified through Tatum, for example&lt;br&gt;
&lt;code&gt;Ht7Du4hHcm3e9DGA2bDMNttdjuPK3BedPFBYDM9aYdeE&lt;/code&gt; (the $0.15 purchase made right after the greedy 402 was refused).&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning over time
&lt;/h2&gt;

&lt;p&gt;"Learning" in Mandate is deliberately simple and explainable: it is &lt;strong&gt;deterministic policy over remembered events&lt;/strong&gt;,&lt;br&gt;
not a model guessing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;approval&lt;/strong&gt; makes a vendor &lt;em&gt;trusted within limits&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;A rejection marked &lt;strong&gt;too expensive&lt;/strong&gt; sets a shared &lt;em&gt;price ceiling&lt;/em&gt;: the current policy rejects later requests
at or above the lowest price rejected this way, across vendors.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;flag&lt;/strong&gt; marks a vendor as bad for every agent.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;receipt&lt;/strong&gt; makes the item a duplicate, unless the chain later says the payment failed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The recorded dashboard comparison shows &lt;strong&gt;14 purchase requests&lt;/strong&gt; and &lt;strong&gt;3 owner prompts&lt;/strong&gt;. Its no-memory baseline&lt;br&gt;
evaluates each request with empty knowledge, which produces an owner prompt for each request; this is a policy&lt;br&gt;
comparison, not a separate live control experiment. Later sessions and the second agent use recalled events to&lt;br&gt;
decide without asking again. The current demo tasks are scripted and policy decisions are deterministic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture in one paragraph
&lt;/h2&gt;

&lt;p&gt;Clean Architecture in TypeScript: a pure domain (policy and memory events) behind ports (&lt;code&gt;MemoryStore&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;ChainReader&lt;/code&gt;, &lt;code&gt;PaymentRail&lt;/code&gt;, &lt;code&gt;DelegateAccess&lt;/code&gt;), with adapters for Walrus Memory, Tatum gRPC, the x402 rail and a&lt;br&gt;
labelled demo merchant. Express API, React + Vite + Tailwind dashboard in a pixel style, PostgreSQL for app data only.&lt;br&gt;
&lt;strong&gt;37 automated tests&lt;/strong&gt; run without any keys (&lt;code&gt;npm install &amp;amp;&amp;amp; npm test&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Payments in the demo run on &lt;strong&gt;Sui Testnet&lt;/strong&gt; (test USDC). Memories are on &lt;strong&gt;Walrus Mainnet&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The merchant and its vendors are our own demo services, clearly labelled; agent task plans are scripted.&lt;/li&gt;
&lt;li&gt;The managed Walrus Memory relayer sees plaintext, so the demo uses sample data only.&lt;/li&gt;
&lt;li&gt;Chain verification currently checks execution status for the signed digest. Independently matching the transfer's
token, amount, recipient and payer against the approved purchase remains a hardening task.&lt;/li&gt;
&lt;li&gt;Recall is semantic and bounded (up to 100 hits per query, with extra queries at the cap), so this is a small
demo rather than a guarantee of complete recovery for an arbitrarily large purchase history.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;A language model as the agent's &lt;em&gt;planner&lt;/em&gt; (it may only suggest purchases; the policy still decides), more vendors,&lt;br&gt;
spending reports for the owner, and moving the payment rail to Mainnet once it is safe to do so.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Watch the demo:&lt;/strong&gt; &lt;a href="https://youtu.be/sRa2cWtP8ok" rel="noopener noreferrer"&gt;https://youtu.be/sRa2cWtP8ok&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Read the code:&lt;/strong&gt; &lt;a href="https://github.com/fadillaoegi/mandate-walrusxtatum" rel="noopener noreferrer"&gt;https://github.com/fadillaoegi/mandate-walrusxtatum&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;On-chain evidence:&lt;/strong&gt; &lt;a href="https://github.com/fadillaoegi/mandate-walrusxtatum/blob/main/docs/VERIFICATION.md" rel="noopener noreferrer"&gt;Recorded verification and guided walkthrough&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built for Total Recall — Tatum × Walrus.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>walrus</category>
      <category>sui</category>
      <category>ai</category>
      <category>web3</category>
    </item>
  </channel>
</rss>
