<?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: Akrm Al-Qubati</title>
    <description>The latest articles on DEV Community by Akrm Al-Qubati (@akrmcodes).</description>
    <link>https://dev.to/akrmcodes</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%2F4097636%2F00673ce0-3dd2-4199-9de3-c079f38bb2b4.png</url>
      <title>DEV Community: Akrm Al-Qubati</title>
      <link>https://dev.to/akrmcodes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/akrmcodes"/>
    <language>en</language>
    <item>
      <title>Daftar Closing Agent: Gemini plans the shop’s day; the phone commits the books</title>
      <dc:creator>Akrm Al-Qubati</dc:creator>
      <pubDate>Thu, 27 Aug 2026 14:59:40 +0000</pubDate>
      <link>https://dev.to/akrmcodes/daftar-closing-agent-gemini-plans-the-shops-day-the-phone-commits-the-books-5bgl</link>
      <guid>https://dev.to/akrmcodes/daftar-closing-agent-gemini-plans-the-shops-day-the-phone-commits-the-books-5bgl</guid>
      <description>&lt;h1&gt;
  
  
  Daftar Closing Agent: Gemini plans the shop's day; the phone commits the books
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;This piece was created for the purpose of entering the All Things Agentic Hackathon.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yemeni and MENA shops still close the day on paper. Balances live in memory. Collections wait until someone remembers who owes. That chore is the friction I built for — &lt;strong&gt;Taskmaster&lt;/strong&gt;, not a chatbot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Daftar Closing Agent&lt;/strong&gt; (وكيل إغلاق الدفتر) treats the &lt;strong&gt;merchant's business day&lt;/strong&gt; as the long-running task. Each Cloud Run &lt;code&gt;POST /run&lt;/code&gt; is fast on purpose. Cloud Run may scale to zero. The durable work sits on the phone in &lt;strong&gt;Drift&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the agent actually does
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Mid-day.&lt;/strong&gt; Voice or text (&lt;code&gt;Mohamed owes 500 sugar&lt;/code&gt;). &lt;strong&gt;Gemini 3.5 Flash&lt;/strong&gt; on &lt;strong&gt;Vertex AI&lt;/strong&gt;, via &lt;strong&gt;Google ADK&lt;/strong&gt; on &lt;strong&gt;Cloud Run&lt;/strong&gt;, emits a proposal. Money hits Drift only after &lt;strong&gt;Confirm&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Close.&lt;/strong&gt; One plan. One tap: &lt;strong&gt;Confirm &amp;amp; Send Statements&lt;/strong&gt;. Then a device-owned ritual: Drift &lt;code&gt;localDay&lt;/code&gt; summary → Google Drive backup → FIFO aging → Collections Desk → &lt;code&gt;POST /v1/email/send-batch&lt;/code&gt; → &lt;code&gt;smtp.gmail.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Aging ranks who is emailed (&lt;code&gt;min(shortlist, 20)&lt;/code&gt;). MIME &lt;strong&gt;PDF statements&lt;/strong&gt; go to the ranked &lt;strong&gt;Top 5&lt;/strong&gt;. The rest get a fixed text-only reminder. Gemini does not pick recipients and does not send mail. &lt;strong&gt;Confirm without sending&lt;/strong&gt; still closes the books; &lt;code&gt;send-batch&lt;/code&gt; is never called.&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%2Frpwxybgudq74gg96zsrm.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%2Frpwxybgudq74gg96zsrm.png" alt="Contest architecture: Merchant and Flutter HITL on the left path; Cloud Run ADK agent and eight frozen tools; Drift source of truth to Drive backup and aging desk; send-batch to smtp.gmail.com; Architecture HUD observes SMTP" width="800" height="1127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1. Contest architecture. Gemini proposes; the merchant confirms; Drift commits. &lt;code&gt;POST /v1/email/send-batch&lt;/code&gt; is a sibling FastAPI route — not an ADK tool. The Architecture HUD observes SMTP; it does not feed the confirm gate.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this stack (Architectural Discipline)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Official ask&lt;/th&gt;
&lt;th&gt;What Daftar does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Decouple&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/run&lt;/code&gt; emits proposals only. Drift commits money. SMTP is a sibling FastAPI route, not a FunctionTool.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Drift + device &lt;code&gt;ClosingAgentPhase&lt;/code&gt;. Scoped &lt;code&gt;daftarContext&lt;/code&gt;. No vector database — a debt ledger is a financial source of truth, not a RAG corpus.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Credentials&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cloud Run IAM + ID tokens with custom audiences. No &lt;code&gt;allUsers&lt;/code&gt;. Gmail App Password in Secret Manager only (&lt;code&gt;gmail-smtp-app-password&lt;/code&gt;), never in Flutter.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Failures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Confirm-gate lock per &lt;code&gt;proposalId&lt;/code&gt;. Drive skip does not abort close. Per-row SMTP &lt;code&gt;failed&lt;/code&gt; / &lt;code&gt;skipped&lt;/code&gt;. Cloud Run down → ledger intact. Durable send key is device &lt;code&gt;batchId&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One &lt;code&gt;LlmAgent&lt;/code&gt; named &lt;code&gt;closing_agent&lt;/code&gt;. &lt;strong&gt;Eight frozen FunctionTools.&lt;/strong&gt; No send-email tool. No &lt;code&gt;SequentialAgent&lt;/code&gt;. Mid-day capture is one intent-dependent hop. The close ritual is device-deterministic after one plan confirm.&lt;/p&gt;

&lt;p&gt;The offline Drift ledger, Drive backup, and Khazna UI are &lt;strong&gt;pre-existing substrate&lt;/strong&gt; (disclosed). The agentic close path — ADK, Gemini 3.5, HITL, Gmail SMTP, Architecture HUD — was built during the Submission Period (3–31 August 2026).&lt;/p&gt;

&lt;h2&gt;
  
  
  Proof of Action
&lt;/h2&gt;

&lt;p&gt;SMTP &lt;strong&gt;250&lt;/strong&gt; means Gmail &lt;strong&gt;accepted&lt;/strong&gt; the message. It is not mailbox-delivered, not a read receipt, and not a delivery webhook. Gmail SMTP has none. I did not fake &lt;code&gt;delivered&lt;/code&gt;. I did not film WhatsApp as the send.&lt;/p&gt;

&lt;p&gt;Proof is Cloud Logging &lt;code&gt;daftar.agent.email&lt;/code&gt; (unique &lt;strong&gt;Message-ID&lt;/strong&gt; + &lt;strong&gt;250&lt;/strong&gt;) plus the recipient inbox: MIME PDF on the ranked Top 5, text-only remainder by design.&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%2F0z66t4w4jlkbi297tinl.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%2F0z66t4w4jlkbi297tinl.png" alt="Google Cloud Logging: jsonPayload event daftar.agent.email, smtpCode 250, status sent, masked recipient, Message-ID at gmail.com, Cloud Run stdout on project daftar-closing-agent" width="799" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2. Cloud Run logs on project &lt;code&gt;daftar-closing-agent&lt;/code&gt;. &lt;code&gt;smtpCode: 250&lt;/code&gt; and &lt;code&gt;status: sent&lt;/code&gt; are server accept. &lt;code&gt;toMasked&lt;/code&gt; keeps the inbox private. This is not proof the mailbox received the mail.&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%2Feirk805w5691160guz59.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%2Feirk805w5691160guz59.png" alt="Daftar statement PDF for Omar in USD: FIFO invoices for rice, sugar, and groceries; net balance −150.00 USD" width="800" height="1136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3. Device-rendered statement for **Omar&lt;/em&gt;* (integer USD cents, shown as dollars). On &lt;strong&gt;close-the-day&lt;/strong&gt;, Omar is in the &lt;strong&gt;text-only remainder&lt;/strong&gt;. MIME PDFs attach only for the ranked Top 5 (for example Mohamed). Gemini does not choose who gets a PDF.*&lt;/p&gt;

&lt;p&gt;The on-device Architecture HUD shows the same close: model &lt;code&gt;gemini-3.5-flash&lt;/code&gt;, tool &lt;code&gt;propose_closing_plan&lt;/code&gt;, HITL rail (Propose → Confirm → Commit → Rank), and &lt;code&gt;Sent ·&lt;/code&gt; Message-ID last-8. The HUD observes; it does not confirm money or send mail.&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%2Ffwm7jwpprxolha9on0r8.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%2Ffwm7jwpprxolha9on0r8.jpg" alt="Architecture HUD over Day closed: Cloud Run gemini-3.5-flash, propose_closing_plan, HITL rail, Sent Message-ID last-8, 13 tasks sealed, Drive backup, 7 overdue" width="800" height="1653"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 4. After close. Thirteen ritual tasks sealed, backup on Drive, seven overdue in the send set. &lt;code&gt;Sent ·&lt;/code&gt; is Message-ID last-8, matching logs. Today's Drift &lt;code&gt;localDay&lt;/code&gt; on this frame is two small debts (USD 3.50) — the sample-store today strip, not the filmed Mohamed $500 capture.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;The agent should be a clerk who &lt;strong&gt;proposes&lt;/strong&gt;, not a cashier who writes the books. For an offline merchant, the phone is the system of record. Frozen tools are cheaper to reason about than a ninth “just send it” tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/akrmcodes/daftar-closing-agent" rel="noopener noreferrer"&gt;github.com/akrmcodes/daftar-closing-agent&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Hackathon:&lt;/strong&gt; &lt;a href="https://allthingsagentichackathon.devpost.com/" rel="noopener noreferrer"&gt;All Things Agentic&lt;/a&gt; · &lt;strong&gt;Track:&lt;/strong&gt; Taskmaster · &lt;strong&gt;Individual&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>googlecloud</category>
      <category>ai</category>
      <category>flutter</category>
      <category>gemini</category>
    </item>
  </channel>
</rss>
