Central login service: Shipping it - Jenkins, uv and a Debian container - Part 2
~25 min read
Part 1 ended with a login service that passed its tests and ran on my laptop. That's the easy half. A login service that isn't reachable from the other machines in the house isn't a login service, and "reachable" brought a pile of small decisions and an unglamorous run of commits with messages like ci: add uv.lock, fix python missmatch and fix deploy script.
This post is about all of that: the deployment target, the Jenkins pipeline, moving the build to uv, the rsync --delete that
Personal finance aggregator: Building the frontend: React, routing, and a design system - Part 5
~10 min read
For a while, the frontend was one component: log in, see a table of transactions, link a bank from a text input. That was fine for checking the backend actually worked, but it wasn't a tool I wanted to open every day. This post covers turning that single page into a proper multi-page app - Home, Accounts, Transactions, Settings - with real navigation and a design system underneath it, instead of default browser styling on a scattering of <div>s. It's the work of one commit (Add rou
Central login service: One place to type a password - Part 1
~25 min read
Every small tool I build for myself eventually needs a login. A finance tracker, an invoicing app, a dashboard for something plugged in to the wall. The first time, I wrote the whole thing inline: a user table, Argon2 hashing, sessions, a password-change form, two-factor enrolment with recovery codes. It worked, it was even fairly pleasant, and then I looked at the second app on my list and realised I was about to write all of it again.
This series is about the project I built ins
Personal finance aggregator: From script to service - Part 4
~10 min read
The CLI prototype proved the OAuth flow worked. It also had a very short list of things it fundamentally couldn't do: run anywhere but my laptop, keep transaction history instead of overwriting it, or be looked at by anything other than cat transactions.json. This post covers the two commits that fixed all three: init: basic backend/frontend, which turned the script into a FastAPI package with SQLite storage and typed settings, and Add TrueLayer web linking, provider/storage packag
Blog automation: Markdown to Ghost on every merge - Part 1
~9 min read
Every project I build gets a blog series. The finance system has nineteen posts, the identity system has seven, and each one is a markdown file that sits in the repo next to the code it describes. That part is easy to love: the posts are diffable, they live in git, and I can write them in the same editor as the code. The part I got tired of was the other half - copying each post into Ghost, fixing the links by hand, setting a publish date, and then doing it all over again when I cor
Personal finance aggregator: The first prototype: a CLI script that links a bank - Part 3
~10 min read
By this point I had sandbox credentials, a registered redirect URI, and a scope string I'd thought through (see the previous post). What I didn't have was any actual code, and I've learned not to trust an integration design until I've built the ugliest possible version of it and watched it work. So the first real artifact in this project wasn't an API, or a database, or a frontend - it was a single ~180-line script, truelayer_sync.py, that did exactly two things: link <bank> and fe
Personal finance aggregator: Developer access and app setup - Part 2
~10 min read
With TrueLayer picked as the data provider (see the previous post), the next step was the unglamorous part every API integration starts with: get an account, register an application, get credentials, and figure out exactly what permissions to ask for. This post is that setup, written down properly so I don't have to reconstruct it from memory the next time I need to do it again - for a second project, or when the production credentials need rotating.
Signing up and creating an ap
Personal finance aggregator: Choosing a data provider: TrueLayer vs Enable Banking - Part 1
~10 min read
I wanted one place to see everything I was spending, across six accounts at five banks that I actually use day-to-day: a Nationwide current account, a Nationwide credit card, Monzo, Tesco Bank, Virgin Money, and an M&S Bank credit card. None of these banks talk to each other, none of them export in a format the others understand, and I was tired of opening five apps to answer "how much did I actually spend this month." So: a personal finance aggregator. Pull everything into one SQL
If you’ve been following along with the previous posts on managing multiple Git identities and multiple SSH keys, this next step adds a nice layer of polish — verified commits.
You’ve probably noticed some commits on GitHub have a little “Verified” badge next to them.
That badge tells others (and your future self) that GitHub has confirmed the commit really came from you — not someone impersonating your name and email.
Let’s walk through how to set up commit signing for your personal and work
In the last post, we configured Git to automatically use different user names and emails depending on the project directory.
That solved one half of the problem.
But if you use multiple Git accounts — say, one for work, one for personal projects — you’ll also need to make sure Git connects using the right SSH key for each.
Let’s fix that next.
The Problem
By default, Git uses your system-wide SSH key (typically ~/.ssh/id_rsa or ~/.ssh/id_ed25519).
If both your personal and work GitHub accou
If you contribute to both personal and work repositories, you’ve probably run into this:
You commit to a personal project — and realise your work email is all over it.
Or worse, you commit to a company repo using your personal identity.
Git only tracks one author configuration per system by default, but with a little setup, you can make Git automatically choose the right name and email based on the directory you’re working in.
Let’s walk through how to do it cleanly.
🧩 The Problem
By def
Building a Laser Trip Sensor with a Photoelectric Sensor and ESPHome
Presence detection is a cornerstone of home automation. Whether you want lights that automatically switch on when someone walks into a room, or smarter security alerts, presence sensors give your automations real-world context.
While PIR (motion) sensors are common, another interesting option is the photoelectric sensor. These sensors detect when an object breaks a light beam, making them great for detecting someone passing through a doorway, entering a hallway, or triggering an event when some