The problem
Bank apps tell you what you have, not what is draining away. Spreadsheets need discipline nobody sustains, and neither can see across every account and card at once. The people it is built for make that sharper: someone sending money home each month, someone on income that lands when it lands, someone chipping away at an overdraft and three cards.
What it does
Connects UK current accounts and credit cards over Open Banking, categorises transactions automatically, then does what bank apps do not: detects recurring payments, predicts the next renewal, flags quiet price rises, spots overlapping services and ranks fixable problems with an estimated monthly saving against each.
How it's built
The recurring-payment detector uses no AI at all
It groups debits by canonical merchant, collapses same-day split charges, and only calls something recurring when the cadence is genuinely regular — at least 60% of gaps in the same bucket as the median, not merely a monthly median — and the amount is stable within 20%. Precision over recall, deliberately: a false match here is a false money claim.
A canonicaliser for UK bank descriptions
TrueLayer and many banks return no merchant name, so a parser derives a stable grouping key from the raw description: stripping embedded transaction dates, card BINs, gateway prefixes, Faster Payment reference tails, numeric refs fused onto the merchant token, TLDs and legal suffixes. That one key powers subscription grouping, duplicate detection and the categorisation cache.
Vercel dispatches, a worker on a dedicated box executes
Jobs are fired at a Hono worker with a ten-second ack budget; it returns 202 and runs the bank sync and the full categorisation drain with no serverless ceiling. Two details worth noticing: a keepalive because the serverless Postgres driver drops during long idle gaps, and a drain loop that stops early when a pass makes no progress rather than hammering a rate-limited provider.
A chat that can only ever read your own rows
Ask Genwel runs a bounded tool loop over four schema-validated tools, built by a factory that closes over the user id — so a tool cannot be pointed at another account and the model never supplies an identity. The system prompt sits in the messages array so a single cache breakpoint lands after the tool schemas, which is what makes prompt caching actually pay rather than cost a write surcharge.
One entitlement resolver across two payment rails
Stripe on web and RevenueCat on mobile both write one subscriptions table, and every gated feature resolves from the database rather than a live provider call — so a card purchase and an in-app purchase answer identically. Free is modelled as the absence of an active row rather than a stored plan.
The hard part
The flagship feature shipped wrong, and the fix is the story. An audit against a real bank account found the subscriptions screen claiming "18 recurring · £6,367/mo", inflated by around £5,400 of things that were not subscriptions: a monthly payment to an individual surfaced as a £1,600 "mortgage" that had "gone up, check you’re on the best deal", plus school fees, council tax, car finance, and one energy supplier counted twice under two descriptions. The cause was precise — the detector trusted an AI category, and the same payee flipped between BILLS and TRANSFER month to month, while merchant keys for a person varied every month so key-based exclusion leaked. Moving exclusion onto the raw description and adding the cadence-regularity test took it to £848/mo and 12 genuine subscriptions. Calling someone’s mortgage a subscription that has gone up is a credibility-killer, which is why the detector is now so conservative.
Stack
- Next.js
- React Native
- Expo
- TrueLayer Open Banking
- Prisma
- Neon
- RevenueCat
- Stripe
Built, shipped and maintained by me. Try Genwel, or see the rest of the work.
