Inspiration
I run a small tech business in Abidjan. Every purchase leaves either a thermal receipt that fades in three weeks or a Mobile Money SMS buried under a hundred others. So I never really knew two things: where my money went, and when I'd hit zero — usually around the 20th of the month. And when I needed credit, I had no way to prove I was solvent: in the WAEMU zone only ~25 % of adults are strictly banked, and financial literacy is among the lowest in the world.
Wariteban ("wari te ban" — money well managed never runs out) is the tool I built for my own Monday mornings. It was submitted in the Taskmaster track because the chore is real, multi-step, and mine.
What it does
- Reads the proof of purchase. A photo of a crumpled receipt or a Wave / Orange Money / MTN screenshot → merchant, amount, date, payment channel, plain-language category. The receipt image is archived in Cloud Storage.
- Keeps the books without asking you to be an accountant. You pick "Rent" or "Transport"; the SYSCOHADA account code is assigned in the background and only surfaces in the ledger export for your accountant.
- Projects your cash. The Anti-Red Radar: D+7 / D+30 forecast, burn rate, days until red, and the single most effective action, with the facts it is based on.
- Works at night, alone. Every day at 05:00 (Africa/Abidjan) Cloud Scheduler → Pub/Sub → Cloud Run runs a sweep of every account. The agent decides: a repayment due in 3 days, an unpaid invoice 88 days old, a tontine falling due, a red balance in 10 days → it writes tasks and pushes a notification. In the demo account this produces six decisions with a single command.
- Answers and then acts. "Can I afford 200,000 XOF?" → a Google ADK agent calls nine deterministic tools on your real data, answers with figures, and proposes an action ("Set 75,500 XOF aside") that becomes a tracked task.
- Proves you're solvent. An explainable Wari Score built only from documented entries — each point tied to a verifiable fact — exportable as an activity statement for a microfinance institution.
- Offline-first PWA under 1 MB precache, built for a low-end Android on 2G/3G, with an outbox that syncs by itself when the network comes back, and per-account mirroring so your books follow you from phone to phone.
How we built it
One rule shaped every decision: the LLM never computes an amount. The model perceives (reads an image) and phrases (talks to the user); every number on screen comes out of a deterministic, tested Python function.
- Gemini 3.5 Flash-Lite via the GenAI SDK with a Pydantic
response_schemareads the image — one call, no free text parsing. - Google ADK (
LlmAgent+InMemoryRunner) on Gemini 3.7 Flash runs the advisor: it plans which of nine Python tools to call and puts the result into words. The action it proposes is derived in Python from the tools it actually called. - A deterministic classifier assigns the accounting account; the model's suggestion is only a last-resort hint, never an override of a matching rule.
- Cloud Run (europe-west1) hosts the FastAPI backend; Firestore holds per-user state; Cloud Storage the receipt vault; Secret Manager the Gemini key and the internal job token; Pub/Sub + Cloud Scheduler drive the nightly sweep (push subscription with OIDC — identity and audience verified); Firebase Auth protects every endpoint (Cloud Run is public, so the ID-token check on FastAPI is the real perimeter); FCM delivers the night's decisions; Firebase Hosting serves the PWA; Cloud Trace receives the ADK spans with prompt content masked.
- The nightly job calls no model at all: it is the part of the system that must be cheap, idempotent (Pub/Sub delivers at least once — we dedupe on
messageId) and exactly reproducible. - Per-user memory: a merchant you correct once is classified correctly forever, and the 25 merchants you visit most are injected into the vision prompt — the cheapest accuracy lever we found.
- 139 offline tests cover the deterministic half; a separate live script exercises the real Gemini calls.
Challenges we ran into
- Costs are driven by output tokens, not images. On Gemini 3.5 Flash, reasoning tokens (billed at output price) weighed 833 tokens per receipt — more than the visible answer. Measuring instead of guessing moved the reader to Flash-Lite (0.61 XOF and 1.9 s per receipt, same amount read on every test document) and the advisor to 3.7 Flash (1.99 XOF a question instead of 4.83, same tools, same figures). Removing the line-item list from the schema cut 44 % of the cost and made extraction more stable.
- Firestore "phantom" parent documents.
users/{uid}never exists as a document when you only write sub-collections, sostream()returned nobody and the nightly sweep silently scanned zero users in production.list_documents()fixed it; a test now pins the semantics. - The temptation to fake it. An early version returned a plausible receipt when the model was unreachable. We removed it: today a model failure is an explicit 503, the credit is refunded, and the receipt stays archived. In a financial tool, a fabricated number is worse than no number.
- Multi-device state. The first sync pushed the phone's profile over the server's and wiped the account on the next device. Now the server is the source of truth: the phone pushes an outbox and pulls the account state at login.
Accomplishments that we're proud of
- A background workflow that is demonstrably autonomous: one
gcloud scheduler jobs run, and six concrete, correct decisions appear in Firestore and on the phone. - A clean LLM / deterministic boundary that judges can verify by reading the code, not by trusting the README.
- "Fail loud, never invent": no fallback data anywhere on the financial path.
- A consent-first corpus: anonymised corrections are only kept when the user opts in (off by default).
- The founder uses it daily.
What we learned
- Measure model cost per task with your own documents before choosing a model; the cheapest model won on accuracy and latency for reading.
- In an agentic system the interesting engineering is in what you don't let the model do.
- Idempotency and at-least-once delivery matter the day your agent starts sending notifications.
- An offline-first PWA and a server-authoritative account are not in tension if the phone is treated as a mirror.
What's next
Account deletion and data export endpoints, signed receipt URLs via IAM signBlob, a per-user Pub/Sub fan-out for the sweep, and the accountant hand-off (monthly ledger + receipt archive) as a scheduled job.
Built With
- cloud-pub-sub
- cloud-scheduler
- cloud-trace
- fastapi
- firebase-auth
- firebase-cloud-messaging
- firebase-hosting
- firestore
- gemini
- gemini-3.5-flash-lite
- gemini-3.7-flash
- google-adk
- google-cloud
- google-cloud-run
- google-genai
- pwa
- pydantic
- python
- react
- secret-manager
- tailwindcss
- typescript
- vite
- workbox


Log in or sign up for Devpost to join the conversation.