Gautham Krishna

Aviyal

AI reads your bank SMS and shows where your money actually goes — calm, automatic spending awareness

Aviyal

Aviyal is a South Indian dish of many different vegetables brought together into one thing. The app does the same: scattered transactions from different banks and cards, combined into one honest picture of where your money actually goes. It reads your transaction SMS automatically, uses AI to turn that mess into trustworthy data, and keeps you conscious of your spending with a calm daily pulse — no logging, no nagging, no guilt.

Role: Design & DevelopmentStack: Expo, React Native, SupabaseAI: OpenAI (parsing + insight)

The problem

Most people's spending is an accident of "what I bought when I had money." The tools meant to fix that all fail the same way: bank apps are reactive dashboards you only open when you remember, manual trackers ask you to log everything until you quit, and savings apps turn into anxiety machines you eventually mute.

Aviyal lives in the missing middle — automatic enough that you never quit, calm enough that you never mute it, and honest enough that you trust it.

The dashboard

The home screen is a calm, single-glance picture of the month. The AI-written Magic Insight sits at the top, followed by the verified balance, the investment portfolio, a spend ring per category, and the month's totals.

Aviyal home dashboard: the Magic Insight card, account balance with credit-card outstanding, investment portfolio, six per-category spend rings, and the month's spend and income with a daily bar chart
  • Magic Insight — the AI's nightly read on your money, in plain language: "3 of today's 4 transactions were for food. You only have ₹3,000 left this month to spend for food."
  • Account balance — a real, verified figure, with the credit-card outstanding broken out separately.
  • Investment portfolio — value, P&L, and active SIPs, pulled from Zerodha Kite.
  • Spend analysis — a ring per category showing how much of each budget is used. EMIs & Investment is already at 102%, flagged calmly rather than in alarm red.
  • The month so far — total spend against income, with a daily bar chart and a "last synced" stamp so you always know the data is current.

How it works

The server can't read your SMS, so the hard part is getting trustworthy data off the phone with zero manual logging — and then turning a day of messy bank texts into numbers and a sentence worth reading. A custom native Expo module, sms-extractor, reads recent bank SMS from the device inbox, filtered to known bank senders. Those messages flow through Supabase Edge Functions where two language models do the work rules can't: one parses and categorises, the other writes the daily insight.

Aviyal AI pipeline — from bank SMS to the daily Magic InsightFrom bank SMS to the daily Magic InsightBank SMSon your phonesms-extractorcustom native modulesync-sms → raw_smsstored verbatim · deduped on device + message idparse-sms · gpt-4o-miniextract · categorise · flag what's uncertaintransactionsverified · categorised · flagged ones go to a review piledaily-insight · gpt-5aggregates (never raw transactions) → narrative + detailDashboardMagic Insight · spend ringsDaily pushthe calm pulseTwo models, two jobs — a small one for accurate extraction, a stronger one for the words.

AI workflows

Aviyal uses language models for the two jobs that rules alone do badly: reading messy bank SMS and writing something worth reading. Each job gets a different model, picked for the work — and the choice of model is itself a design decision.

1. Parsing & categorisation — gpt-4o-mini

Bank SMS are inconsistent, noisy, and full of near-misses: mandate notices, statement reminders, "EMI is due" alerts, loan offers, marketing. Every night the parse-sms function hands a whole day's raw messages to gpt-4o-mini with a strict JSON schema and gets back structured results:

  • Separates real money movement from noise — debits and credits versus informational messages, which are recorded as "ignored" with a reason rather than silently dropped.
  • Extracts the details — amount, direction, merchant, reference number, the institution (derived only from the sender id, never from a bank name written inside the body), the transaction time with the correct +05:30 offset, and the post-transaction available balance.
  • Assigns exactly one category from a fixed set — income, EMIs, investment, food, people, shopping, entertainment, other — each defined for the model so "Swiggy" lands in food and a Zerodha transfer lands in investment.
  • Flags what it isn't sure about. When a category is uncertain or a charge looks like a duplicate, the model sets a flag and that transaction goes to a review pile instead of skewing the numbers. This is the Truth principle in code: honest about confidence beats confidently wrong.

A small model here is deliberate. Structured extraction doesn't need a frontier model, and a job that runs every single night should cost almost nothing to run.

2. The Magic Insight — gpt-5

Writing the daily pulse is the opposite problem — it needs judgement and a voice — so it gets the stronger model. After parsing, parse-sms fire-and-forgets the daily-insight function, which runs on fresh data and produces the card at the top of the dashboard.

Crucially, the model never sees raw transactions. It receives a compact, pre-aggregated metrics blob:

  • today's per-category spend, with the single merchant that dominated each category
  • last-7-day spend per category, capped at the start of the billing cycle so a new month isn't polluted by the old one
  • budgets with cycle-to-date spend and, for discretionary categories, a projected end-of-cycle total at the current pace — so it can warn before a budget is blown, not after
  • billing-cycle day context, the savings goal, and the Zerodha Kite portfolio
  • the last two insights, so it never repeats the same observation two days running

The prompt tells it how to find the angle — pick the most actionable observation in priority order: a category projected over budget first, then a notable weekly trend, then an unusually concentrated single-day spend, then tight-versus-comfortable headroom, then savings-goal progress. It returns two fields with a strict schema — a roughly 40-word narrative for the card and a longer detail — and the narrative goes out as the day's single push notification.

The voice is enforced in the prompt, and the voice is the product: calm and plain like a thoughtful friend, never shaming, specific to the rupee and the merchant, and honest when unsure. "Swiggy made up ₹890 of your ₹1,200 food spend" — never "⚠️ overspending alert."

The daily rhythm

The server can't read SMS, so it can't pull the data — it nudges the phone to push, on a schedule run by Postgres pg_cron with pg_net (all times IST):

Aviyal daily cron schedule in ISTThe daily rhythm (IST)11:00trigger-syncsilent push → phone syncs20:00trigger-syncsecond silent push21:00check-syncnudge if the phone went quiet22:30parse-sms → daily-insightAI parses the day, writes the insightTwo pushes keep the data current; one nightly parse turns it into truth and a sentence.
  • 11:00 & 20:00 — trigger-sync. Sends a silent FCM data push. The app's background task wakes, reads the day's bank SMS, and POSTs them to /sync-sms — always, even with zero new messages, so the server records a heartbeat and can tell a quiet day apart from a phone that never checked in.
  • 21:00 — check-sync. If the phone hasn't reported today, a gentle nudge goes out — so a broken sync never passes silently before the night's parse.
  • 22:30 — parse-sms. Parses the day's raw_sms into transactions with the parsing model, reconciles each institution's balance, then fire-and-forgets daily-insight to write the Magic Insight on freshly-parsed numbers.

Design principles

Aviyal should feel like a calm, reliable companion you check like the weather — informed, never anxious. If a screen makes you feel judged, watched, or stressed, it's wrong, no matter how accurate it is. Five principles guide every decision:

  • Calm beats clever. Muted, steady visuals over alarming reds and urgent badges. "Nothing needs your attention" is a good state, shown proudly.
  • Automatic beats manual. Default to showing, not asking. Every required tap is a place someone quits, so taps are treated as expensive.
  • Truth beats polish. Accurate numbers on a plain layout beat a beautiful screen with guessed data. The app — and the AI — is honest about its own uncertainty.
  • Specific beats generic. "Cancel this subscription → ₹649/month" beats "reduce spending." Every insight points at one concrete, doable action.
  • Questions beat declarations. "This renews tomorrow — still using it?" beats "You waste money on subscriptions." The app informs; you decide.

No gamification, no streaks, no comparison, no upsell — anything that distracts from real awareness or quietly erodes trust is deliberately left out.

Engineering notes

  • Expo + React Native with expo-router, Reanimated, and react-native-svg for the spend rings, bar chart, and pulse swiper.
  • Custom native module (sms-extractor) with Swift and Android implementations, packaged as a local Expo module — the piece that makes "automatic" possible.
  • Supabase for auth, Postgres storage (raw_sms, transactions, accounts, insights), and a suite of Deno Edge Functions for syncing, parsing, insights, and the Zerodha Kite portfolio integration.
  • OpenAI drives both AI jobs — gpt-4o-mini for structured SMS extraction and gpt-5 for the Magic Insight — each called with a strict JSON schema for reliable, typed output.
  • pg_cron + pg_net run the daily schedule server-side; expo-task-manager and expo-notifications handle the background sync wake and the daily push.

Status

Aviyal is a personal tool, built bottom-up. The scariest unknowns — a working custom SMS-reading module and good-enough SMS coverage — are validated, and the product is built in honest phases: Truth (a trustworthy transaction list), then Insight (the auto-categorised dashboard and Magic Insight you see above), then Awareness (the daily notification habit). Each phase ships something usable on its own, and the bar for "done" is strict: the numbers in the app match the bank statement to the rupee.