ai-bot: A Rust Telegram Bot Is the Front Door to My Money Stack

Xu and Chia both have web UIs. Nobody in my house uses them. The interface everyone actually uses is a small Rust bot that turns Telegram messages into API calls — with an LLM doing the translation.

The Pattern Completes Itself

If you've followed the money-stack posts — Tiền capturing bank email, Chia splitting group expenses, Xu keeping the personal ledger — you may have noticed every arrow eventually points at the same place: Telegram. Alerts arrive there, categorization happens there, weekly summaries land there.

So the final piece was inevitable: ai-bot, a bot that makes Telegram a write interface too. Message the bot in natural language; transactions appear in Xu or Chia. The web UIs still exist. They're for auditing. The bot is for living.


The Shape of It

ai-bot is a small Rust service — my one deviation from the TypeScript-everywhere fleet — with a deliberately boring architecture:

  • Per-app bot configuration: it fronts both Xu and Chia through their public HTTP APIs, each with its own bot token, API URL, and password. The bot is just another API client — no privileged database access, no service bindings, no backdoors.
  • An LLM as the parser: incoming text goes to an OpenRouter model (currently a Gemini Flash variant with a small thinking budget) that converts "taxi về nhà 95k" into a structured transaction — amount, category, account, which app it belongs to.
  • SQLite on disk for conversation state and dedupe. No cloud database for a bot that serves one household.

Why Rust for this one? Honestly: a single static binary that sits at a few megabytes of RAM on an already-crowded container, runs for months, and never needs a node_modules folder was the whole argument. For a bot whose job is "receive webhook, call LLM, call API," the borrow checker is overkill and the operational footprint is the feature.


The Guardrail That Matters

Same rule as Xu's chat tab, enforced at the API boundary this time: the LLM drafts, the human confirms, and the bot only ever calls the same public endpoints a browser would. The blast radius of a bad parse is one wrong API call behind a password — not a corrupted database. Trust in this system comes from the architecture, not from hoping the model reads Vietnamese money slang correctly every time.

(It reads Vietnamese money slang correctly a surprising amount of the time. "95k", "1tr2", "ck cho mẹ 2 triệu" — the parser earns its keep.)


Why Not One Big App?

A fair question at this point in the series: Tiền, Chia, Xu, ai-bot — four services for one household's money. Wouldn't one app be simpler?

It would be simpler to draw. It would be worse to run. Each piece has a different failure domain (the bank-email parser breaking shouldn't take down the ledger), a different change cadence (parsers churn weekly; the ledger schema is frozen), and a crisp API boundary that makes each one small enough for an AI coding agent to hold in context and modify safely — which is how they actually get maintained.

The household doesn't know any of this. The household knows: text the bot, money is handled. That's the entire product.