1. Home
  2. The Lab

The Lab

What I build when
nobody is paying me

The client work on this site is WordPress, because WordPress is usually the right answer for a service business. It's not the extent of what I do, and a portfolio of Divi builds is a poor description of an engineer.

So this is the other half: Python services, native Android written against the framework rather than a toolkit, local language models running on my own hardware, containers, MCP servers, a game engine. Built for me, on my own time, because I wanted the thing to exist.

The two big ones

Where most of the hours went

One is a personal AI platform I've been building for over a year. The other is the plugin and API that lets an assistant work on a live WordPress site — and the reason the client work on this site can move as fast as it does.

Personal AI platform

Hearth

A complete personal AI platform running on my own hardware — gateway service, local models, an agentic loop, voice, vision, and a native Android client. The SMS categoriser that started it's now one feature out of dozens.

Started as
An SMS categoriser
Became
A private AI platform
Test suite
600+ backend tests
PythonSQLiteOllamaAndroid (Java)NSSMWireGuard

Read the full write-up

WordPress plugin + REST API

WP AI Agent

A WordPress plugin and custom REST API that lets an AI assistant work on a live site directly — read pages, build them, publish them — with authentication, a tiered permission model and an audit log. Around 5,900 lines of PHP across 15 files, paired with a deliberately thin Node MCP server.

Scale
~5,900 lines of PHP
Spread over
15 files
Releases
12, to v0.8.3
Client
A thin Node MCP server
PHPWordPress REST APINode.jsMCP

Read the full write-up

Local AI infrastructure

A private AI platform running entirely on hardware I own. No API keys, no per-token bill, nothing leaving the network.

Local model in production

This site's assistant

The assistant on this site runs on a GPU in my office, answering from the pages you're reading. It is the only local model I run that strangers can talk to, and in September somebody spent forty minutes trying to break it. The write-up is what they got through and what finally stopped them.

OllamaCloudflare WorkersNode.jsTailscale

Read the full write-up

Write-up

Running models locally

What a parameter is, why a 7B model is 14 GB before anyone compresses it, and how to work out what your own graphics card can run before downloading twenty gigabytes to find out. Written for someone who has a gaming card and has not tried this yet.

Ollamallama.cppGGUFCUDA

Read the full write-up

Local model runner

claude-local

Runs Claude Code against a model served locally by LM Studio, with no hosted API in the loop. No key, no per-token cost, and no source code leaving the machine — which matters when the code belongs to a client.

Node.jsLM StudioQwen3-Coder 30B
Local command dashboard

AI Hub

A containerised dashboard for driving local models, sitting on Docker with Ollama on the host. The control surface for everything else on this list.

DockerOllamaNode.js
Utility

vram-toggle

Two batch files that free roughly 12 GB of VRAM on an RTX 4090 by pausing the services holding it, unloading anything resident, and putting it all back afterwards. Unglamorous, and I use it constantly.

Windows servicesPowerShell
Voice hardware

Local Voice Assistant

A fully local voice assistant on a Raspberry Pi with a small display, talking to the same gateway everything else uses. Nothing it hears leaves the LAN.

Raspberry PiPythonOllama
Model training

Wake-word training

Training a custom "hey Hearth" wake word from scratch — building the dataset, mixing in room impulse responses and background audio, and evaluating the result.

PythonAudio datasetsModel training
Image pipeline

Local image generation

A Krea 2 Turbo checkpoint running in ComfyUI on the same machine as the rest of my local AI work, driven by a small Python client that turns a one-line brief into a finished, correctly-sized image in about eleven seconds. Built to keep diffusion models on hardware I own — no API key, no per-image bill, nothing leaving the network.

ComfyUIKrea 2 TurboPythonCUDARTX 4090

Native Android

Self-signed, sideloaded, no Play Store. Written to solve a specific problem on a specific phone, with no intention of shipping it to strangers.

Native client

Hearth (Android)

The native Android client for the gateway. Java, framework-only — no AndroidX — with a minimal command-line build. A WebView of the web app plus the native capabilities a browser can't reach.

JavaAndroid SDKNo frameworks
Default SMS app

Hearth SMS

A full replacement for the phone's default messaging app: SMS and MMS, group threads with stitched avatars, search across message text and contacts, gallery attachments auto-compressed to the carrier's real limit read at runtime.

JavaAndroid 15Telephony APIs
Android app

Fitness coach

Built for my brother. Set a current weight, a target and a deadline; it builds a daily diet and workout plan, writes it into Google Calendar, and tracks calories and weight against the goal.

AndroidGoogle Calendar API

Developer tooling

The machinery behind the client work — MCP servers, generators, dashboards and CLIs that turn repeated jobs into one command.

WordPress plugin

Willits Forge Booking

An appointment booking plugin with two-way Google Calendar sync, written for practitioner sites. Its own database table, a custom REST namespace, configurable availability rules, transactional email over SMTP, and a self-service cancellation flow. Currently running on a live client site.

PHPWordPress REST APIGoogle Calendar APISMTPJavaScript
Site generator

Divi 5 Generator

Answers to a short interview in, a complete on-brand Divi 5 site out — page map, brand, copy scaffold and one validated portability export per page.

Node.jsDivi 5JSON schema
AI tool servers

MCP server collection

A set of Model Context Protocol servers that give an AI assistant real hands: WordPress sites, my phone, the television, image generation. Each one is a thin, well-scoped bridge and not a grab-bag of endpoints.

Node.jsMCPREST
Ops dashboard

Fleet dashboard

Polls every site running the agent plugin and reports the fleet: online or not, plugin version drift, WordPress and PHP versions, builder fingerprint. Answers 'is everything up' without opening 30 tabs.

Node.jsRESTDashboard UI

Experiments

Things built to find out whether they could be built.

Mobile RTS

Hero Line Wars

A mobile real-time strategy game in the Warcraft III custom-map tradition — auto-spawning units, army customization, hero-led battalions and bidirectional fog of war. Simulation foundation first, engine second.

UnityC#Game simulation
Benchmarking

LLM baseline harness

A repeatable harness for measuring local models against a fixed prompt set, so 'is the new model actually better' has an answer and not a vibe.

PowerShellJSONLocal models

Why this is on a business website

Because the stack should follow the problem

A developer who only knows WordPress will recommend WordPress for everything, because it is the only tool in the bag. That's not advice, it's a reflex — and you can't tell the difference from the outside until the project is already in trouble.

Knowing what a Python service, a native app, a container or a queue actually costs to build and maintain is what makes “WordPress is the right call here” worth hearing. Most of the time it genuinely is: it wins on total cost of ownership and on content workflow, and I'll say so. When it's not, you get told that instead — and the recommendation comes from someone who has built the alternative, not just read about it.

None of the work on this page was commissioned. It exists because I wanted it to, which is also the honest answer to whether I enjoy this.

Got something that's not a website?

Automation, an internal tool, an integration, an app, a system that needs to talk to another system. Tell me what it's and you'll get an honest read on whether I'm the right person for it.