Xu: Typing 'Lunch 80k' Is the Whole Interface

My personal finance tracker's newest feature is deleting most of its own UI — an LLM chat tab that turns 'lunch 80k' into a drafted transaction waiting for one confirming tap.

Yet Another Finance Tracker (Mine, Though)

Xu (Vietnamese slang for coin/money) is my personal finance tracker, running on the same boring-on-purpose stack as the rest of my household apps: Cloudflare Workers + D1 + Hono + React. One wrangler deploy, no servers, effectively free.

The conventional feature list is what you'd expect, deliberately small:

  • Accounts — cash, bank, e-wallets — each with a computed balance.
  • Transactions — income, expense, and transfers between accounts.
  • Categories with icons, split by expense/income.
  • Monthly summary with per-category breakdown — the only report I ever actually read.
  • An optional password gate via a Worker secret, because personal finance on a public URL should cost attackers at least one guess.

If that's all it were, it wouldn't deserve a blog post. The interesting part is what happened to the input flow.


The Baby Tracker Rule

I recently retired an app because it demanded manual data entry from a tired human. The autopsy produced a rule I now apply everywhere: an app's survival is inversely proportional to its input friction.

Classic finance-tracker input is friction incarnate: open app → tap "+" → pick type → pick account → pick category → enter amount → enter description → save. Seven decisions to record a sandwich. Nobody sustains that; the ledger drifts from reality; the app dies the baby-tracker death.

So Xu got a Chat tab.


The LLM as an Input Method, Not a Chatbot

You type:

lunch 80k

Xu's LLM layer drafts an expense — 80,000₫, category Food, today, default account — and shows it as a pending draft with a confirm button. One tap and it's in the ledger.

It handles edits and deletes conversationally too:

change yesterday's lunch to 90k

…drafts an update to the matching transaction. Multiple operations can come out of one message — "coffee 45k, grab 120k, delete the duplicate dinner" produces three drafts, each individually confirmable.

Two design decisions carry all the weight:

1. The LLM only drafts; it never writes. Every mutation goes through the same confirm step. This changes the trust calculus completely — a hallucinated amount costs one dismissive tap instead of corrupted books. I'd never let a model write directly to a ledger; I'll happily let it fill in forms for me all day. LLM-as-input-method is a much better product pattern than LLM-as-oracle.

2. Bring-your-own inference. The chat tab lights up only if you set an LLM_API_KEY secret — mine points at an OpenAI-compatible endpoint from a local GPU-sharing service, and the model dropdown just mirrors whatever the upstream /v1/models returns. No key, no chat; the app degrades gracefully to classic forms. Total added infrastructure: zero.


Where Xu Sits in the Money Stack

Xu is the personal ledger in a three-app system that's emerged around our household money:

  • Tiền auto-ingests bank notification emails and pushes transactions into Xu via Cloudflare Service Bindings — most of my ledger now arrives with no typing at all.
  • Chia handles the shared/group side of the same expenses.
  • Xu is where it all lands for the monthly "where did it actually go" reckoning.

So the input hierarchy, best to worst: automated email ingestion → one-tap accept → "lunch 80k" → forms. Forms are still there. I haven't opened them in weeks.

The endgame for personal software, I'm increasingly convinced, isn't more features — it's less typing.