Behind the bot that runs my house
A behind-the-scenes build log of the private Telegram bot that drives my site from the pocket: one bot and a plugin router, an allowlist that is the entire security model, the features it runs today, and what's coming next.
Most of what this site can do is locked behind a login. A household money ledger. A chore board. A to-do spine, a newsletter gate, a trip itinerary, a status page, an agents console. Every one of them is a private admin page that wants a browser, a session, and some clicking around to find. And none of that works in the moment you actually need it. You're standing at the counter with a receipt in your hand. You're on a bus and you watch a deploy go red. So I built a second front door, one that lives where my thumb already is: a private Telegram bot. Here's how it's wired together, what it does now, and where it's headed.
One bot, not fifteen
The temptation with a project like this is to spawn a bot per feature. A money bot. A chores bot. A deploy bot. Pretty soon you're juggling a drawer full of BotFather tokens. I went the other way: one bot, one webhook, one plugin router.
Every Telegram update lands at a single endpoint. The router checks it, then dispatches into a code-defined feature catalog. Each feature registers a slug, maybe a push schedule, command handlers, and a flag for whether it needs callback buttons. Adding a capability means adding a module to the registry. No new infrastructure to stand up.
The catalog pulls double duty. It holds the whole roadmap, and the admin console badges what's actually wired against what's still 'not built yet.' So the console is the plan. I get to see the shape of the finished thing while half of it is still a promise. The bot token sits in the secrets store, rotatable with no redeploy. Feature toggles are just database rows the console flips.
The allowlist is the entire wall
A bot that spends money and runs chores can't be something strangers get to poke at. So the security model is boring on purpose, and it's total. An identity allowlist maps Telegram user ids to roles: admin, household, traveler. Anyone else? Their update gets logged and silently dropped. No reply. No error. Not even a rejection. To anyone who guesses the bot exists, it's invisible.
That silence doubles as the onboarding flow. A new person DMs the bot, nothing happens, but their user id shows up in the console's Log tab. I map them to a role. Their next message just works.
Three more rules hold the line. Features default off - a fresh deploy pushes nothing until I flip a toggle. The webhook fails closed: it checks a secret header in constant time and 503s if the secret is unset, and it acks Telegram in milliseconds, doing the real work afterward so a slow query can't kick off a retry storm. And every actionable button carries an HMAC signature, because callback data is attacker-suppliable by any allowed user. A stale button from a day-old message can't replay an action. Every table is row-level-secured, no anonymous access.
What it actually does
The features fall into four shapes.
Morning pushes. One message carries the day. It folds in overdue and due-today to-dos (bills keep their ๐ณ identity), chores, and a weather line for home. A trip companion pings the traveler with tomorrow's stop. And a site-health canary watches the exact signal the public status page renders, staying quiet until something actually changes.
Capture from the pocket. Snap a receipt and send it. Claude's vision parse reads merchant, amount, category, and date, then drops them into the ledger. You don't type a command. You don't type anything. Prefer manual? /money 12.50 Dunkin logs it and guesses the category off the vendor.
Approve from chat. The Friday newsletter draft and every LinkedIn post arrive with Approve / Discard buttons. Those buttons run the same status-guarded send the admin page uses, so a press from an admin-role identity counts as an admin action, red-line checks and all. File a /hire inquiry and a lead alert fires that instant.
Quick actions. /todo add, /todo list with a โ button per row, /todo done. The chores nudge works the same way: tap an inline checkmark, the chore completes, and the list re-renders in place. Behind it, one pure ordering function feeds the numbered list, the buttons, and the done command. They can't drift apart.
Built in phases, and the review that earned its keep
I shipped this in phases. The catalog carried the parts I hadn't built yet as a visible roadmap, not hidden TODOs. Phase 3 was a load: five household-action features in one pull request. So before merging I sat down and did a real code review on it, multiple angles, no skimming.
Glad I did. It turned up eight real bugs, and two of them were mean. One was an unguarded database call that would have crashed the webhook handler. Here's why that matters: Telegram redelivers anything that doesn't get a clean acknowledgment, so that one crash becomes roughly 24 hours of retry storms. The other? A newsletter approve button left live after a permanent send failure. You'd tap it, it'd look like it worked, and it'd do nothing. All eight fixed in one commit, tests green, same day. Lesson I'm keeping: when the thing holds credentials and moves money, the review isn't polish you add later. It's the build.
What's next
Phase 4 is already sitting in the catalog. First up: an /ask concierge that runs the site's semantic search from inside the chat, so the bot can answer questions about my own work and link straight to the source. Then a note-to-self, where I dump whatever free-form text is in my head and Claude classifies and routes it to the right spine, a to-do, a money note, a draft. And a CRSS flashcard drill for whenever I've got a spare minute.
The bigger goal? Wiring the bot into the rest of the platform's nervous system. The site runs a small fleet of autonomous agents now, a credential steward and supervisor that govern the access estate, plus a roster of audit operators, and they already open incidents and email me when things break. Telegram is the obvious place for that to show up. I want to acknowledge an incident with a tap, see a daily agent-health line next to the chore nudge, get a gate where a risky action waits for me to say yes. The approve-from-chat plumbing already works on newsletters and LinkedIn. Pointing it at the agents is mostly a matter of catalog entries.
The whole thing comes down to something small. Build a command center you actually trust, and put it where you already are. The features were never hard. What was hard was making the front door safe enough to leave unlocked in your pocket.
Get the next one
An occasional note when something genuinely new ships here โ essays, free tools, projects. No schedule, no filler, easy out.
Need something like this built?
I design and ship AI tools, full-stack apps, and data pipelines โ end to end, to production. Tell me the problem in a sentence; I'll give you an honest read on fit within a day.
Work with me โ