Dev.to AI 🤖 Ai 👁 1 📖 2 min read

Daftar Closing Agent: Gemini plans the shop’s day; the phone commits the books

This piece was created for the purpose of entering the All Things Agentic Hackathon. Yemeni and MENA shops still close the day on paper. Balances live in memory. Collections wait until someone remembers who owes. That c

Daftar Closing Agent: Gemini plans the shop’s day; the phone commits the books

This piece was created for the purpose of entering the All Things Agentic Hackathon.

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 — Taskmaster, not a chatbot.

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

What the agent actually does

Mid-day. Voice or text (Mohamed owes 500 sugar). Gemini 3.5 Flash on Vertex, via Google ADK on Cloud Run, emits a proposal. Money hits Drift only after Confirm.

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

Aging ranks who is emailed (min(shortlist, 20)). MIME PDF statements on the ranked Top 5. The rest get a fixed text reminder. Gemini does not pick recipients and does not send mail. Confirm without sending still closes the books; send-batch is never called.

Why this stack (Architectural Discipline)

Ask Choice
Decouple /run = proposals only. Drift commits. SMTP is a sibling FastAPI route, not a FunctionTool.
State Drift + ClosingAgentPhase. Scoped daftarContext. No vector DB — a ledger is not a RAG corpus.
Credentials ID tokens, custom audiences, no allUsers. Gmail App Password in Secret Manager only (gmail-smtp-app-password), never in Flutter.
Failures Confirm-gate lock; Drive skip does not abort close; per-row SMTP; Cloud Run down → ledger intact. Durable send key is device batchId.

One LlmAgent (closing_agent), eight frozen FunctionTools, no send-email tool, no SequentialAgent. Mid-day is one intent hop. Close is device-deterministic after one confirm.

The offline Drift ledger, Drive backup, and Khazna UI are pre-existing substrate (disclosed). The agentic close path — ADK, Gemini 3.5, HITL, Gmail SMTP, Architecture HUD — was built in the Submission Period (3–31 Aug 2026).

Proof of Action

SMTP 250 means Gmail accepted the message. It is not mailbox-delivered and not a webhook. Proof is the inbox (PDF on Top 5, text-only remainder) plus Cloud Logging Message-ID. The HUD shows Sent · last-8; it does not feed the confirm gate.

I did not fake delivery. I did not film WhatsApp as the send.


Device-rendered statement for Omar. On close-the-day, Omar receives a text-only reminder; MIME PDFs are attached for the ranked Top 5.

What I learned

The agent should be a clerk who proposes, 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.

Repo: https://github.com/akrmcodes/daftar-closing-agent · Track: Taskmaster · Individual.

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.