AI

Four apps and a Mac Mini under the stairs

· 3 min read
Four apps and a Mac Mini under the stairs

I have a Mac Mini that runs 24/7. It's called stoa — after the Stoa Poikile, the painted porch in Athens where Zeno taught, which is either a nice bit of Stoic branding or evidence I think about this too much. It started life as an experiment in always-on AI agents. Most of that got torn down. What survived, and what I keep actually opening, is humbler: four small apps for running a household, and a page to launch them from.

What's actually running

A dashboard over my own budget. The same over the joint account my wife and I run. A reader for the blogs and news I follow. And a board that tracks everything with an expiry date — car tax, the MOT, insurance, the ISA deadline — so nothing lapses by accident. In front of them sits a launcher: one page that tiles the four and tells me, at a glance, which are up.

The whole thing lives on my private network via Tailscale. It is not on the public internet, it has exactly one user, and it has no SLA. I'll come back to why that's a feature.

Build the boring skeleton once

The four apps look different but they're the same animal underneath: a small job that wakes on a schedule to fetch or recompute things, a SQLite database to hold the results, an optional local AI model for the language bits, and a web layer on top. macOS keeps the whole lot alive across reboots.

I built that skeleton properly for the first app and then mostly stamped it out for the rest. The feed reader and the renewals board are practically siblings — same bones, different content. The first app took most of a weekend; the later ones took about a day each. The boring, reusable skeleton is the actual asset. The features are easy once the plumbing is a solved problem you can copy.

There's even a small handshake between them: the renewals tracker normalises every recurring cost — insurance, subscriptions, the lot — to a figure per year, precisely so it lines up with the way the budget dashboards think about money. Four separate apps, but they agree on what a number means.

Everything fails soft

This is the design rule I'm most pleased with, and it's the one home software usually gets wrong.

The launcher decides whether an app is "up" with the dumbest possible test: it tries to open a network connection to the app's port. If something answers, it's up; if not, it's down and the Open button greys out. There's no health endpoint to maintain and no agent to install — it works for any service that holds a connection open, not just mine.

And every live panel fails soft. A dead network, a busy database, an AI model that isn't answering — none of those take a page down. The affected panel just goes quiet and everything around it carries on. The AI digest is the obvious example: if the local model is asleep, you still get your feed, just without the summary, rather than an error page and a stack trace.

That matters specifically because nobody babysits this. There's no on-call rota for my own house. Software you won't tend has to degrade gracefully, or it dies the first time something it leans on hiccups — and on a home network, something always hiccups.

Read-only where it counts

The two finance apps read my budget files and cannot write to them; anything I add lives in a separate database alongside the originals. I've written separately about why that one rule matters more than it looks — short version: a reporting layer should be downstream of your source of truth and powerless over it.

What this isn't

It's not production software. There are no other users, no uptime target, no roadmap. For years I'd have read that as a list of things missing. I've come round to seeing it as the point: I'm allowed to build something that only has to be good enough for one household, and then stop. No tickets, no scope creep, no second user with opinions.

The launcher itself — the part I was sure was throwaway glue — is the page I open most. Turns out the glue was the product.