Writing.
Notes on building software, working with AI, and making things just to see what happens. Every essay and project write-up, in one place.
38 articles
My Development Machine Lives in a Data Centre
How I run my day-to-day development across dedicated virtual machines on a single OVH bare-metal server, connecting from thin clients with remote mobile simulators and multi-model agent workflows.
Picking a Language Model Small Enough to Live on Your Phone
Benchmarking small language models to run on a phone: why accuracy plateaus at 3-4B, why RAG hurt, and how a deterministic calculator beat the LLM.
Gratin: Building a Local-First Recipe App
How Gratin’s original local-first recipe app was built: one React core, desktop and mobile shells, and encrypted sync. Updated for its optional AI connector.
Replacing Our SQL Parser
Rewriting a slow, paid ANTLR SQL parser in two days, 3-20x faster on real customer SQL, using a Ralph Wiggum loop and a corpus of production queries.
Migrating Off Firestore
A year migrating a frontend off Firestore with dual writes, feature-flagged reads, and SSE for real-time, plus where the abstraction boundary should live.
Fixing a Slow React App
Fixing a slow React app: why memoization is a bandaid, how Redux selectors and a whole workspace in memory caused it, and what actually worked.
Greenkeeper: A Local Daemon That Babysits Your PRs
Greenkeeper is a local Go daemon that watches your GitHub PRs and runs your AI CLI in a git worktree when CI fails, conflicts appear, or reviews stall.

Cursor Model ROI
An archived React dashboard comparing Cursor models on price, cache economics, Arena scores, and speed. Retired in October 2026.

Clipboard Inspector
Inspect clipboard formats your browser exposes, edit supported content, and copy it back with rich previews. Read and write support varies by browser.

The Registry Pattern
The registry pattern: a typed lookup table of handlers behind one interface for notifications and AI tool calls, and why it isn't the service locator.

Anon: Peer-to-Peer All-Hands Q&A
Peer-to-peer all-hands Q&A with questions kept in browser memory and an optional local AI suggestion that you review and accept before sending.

Frontend Three-Layer Architecture
Applying controller-service-repository thinking to React: view models, state management as a data-access layer, and why feature isolation is a lie.

Interface Driven Development in the Age of AI
Ship AI-generated code without regret by hiding it behind interfaces: contracts, dependency injection, and why the old Java patterns were right all along.

Local First, Offline First, and Cloud
Local-first vs offline-first vs cloud: who owns your data, why Evolu and CRDTs make local-first practical, and the Paprika problem waiting to strand you.

Error Handling with Neverthrow
Typed error handling in TypeScript with neverthrow: three ways to structure errors across layers, a namespace pattern, and exhaustive switch safety.

Controllers, Services, and Repositories
Controllers, services, and repositories in TypeScript: hexagonal architecture, why I use classes over functions, and the late-binding trap to avoid.

My Monorepo Setup
How I run one monorepo for every side project: shared Pulumi infra, a 15-line SPA deploy, why I avoid Vercel, and why I keep coming back to AWS.

Cursor Wrapped
An archived Spotify Wrapped-style dashboard for Cursor usage, built in a weekend with AI. Retired in October 2026.

Secret Santa
A Secret Santa organiser with exclusion constraints and shareable links, now using a Cloudflare Worker and KV for new games.

Spoticover: Generative Spotify Playlist Covers
An archived Spotify playlist cover generator with constrained randomness, retired in October 2026.

Homelab 2025: Lessons in Redundancy
Losing 50TB to a RaidZ1 mistake, rebuilding on RaidZ2, and expanding to two nodes: hard-won homelab lessons in ZFS redundancy and failure modes.

TerribleHack 2025
Running TerribleHack 2025 solo for the first time: print disasters, 17 gloriously terrible projects, and a denim trophy the winners tear apart.

ETHGlobal NYC: HouseHodl
Flying to ETHGlobal NYC after winning Web3NZ: building HouseHodl, a trustless shared-expenses app, why cross-chain broke, and napping on the venue floor.

LoanMarket - Web3 Hackathon 2025
How a team of Web3 first-timers built LoanMarket in 18 hours, sharing one KYC verification across lenders with verifiable credentials, and won best overall.

TerribleHack 2024
Co-organising TerribleHack 2024 as Zac hands over the reins: destroy-your-project challenges, ice-cutlery dinners, and what makes a great maker event.

Rent Racket
Designing Rent Racket, a political landlord-satire card game, at Kiwijam '24: fast paper prototyping, tuning the rules, and laser-cutting the final set.
Fathomiser: Turning Sensor Readings into Useful Water Levels
Building the software behind Fathomiser's water-tank monitoring: decoding device time, estimating volume, displaying history, and handling alerts.

TrueNAS Migration
Migrating a homelab from Unraid and Docker to TrueNAS Scale and Kubernetes: multiple storage classes, ZFS redundancy, GPU passthrough, and K3s in nspawn.
Making Eventing Easier to Build On
My platform work at MATTR: eventing libraries, code generation with ts-morph and string templates, Protobuf contracts, Kafka costs, and the engineering decisions around them.

Mixer Mayhem
Building a crowd-controlled robotic bartender at TerribleHack 2023: peristaltic pumps, a WebSocket god-client deploy pattern, and a force-push disaster.

InfraNZ
Building InfraNZ at GovHack 2023: a 3D GIS map of Auckland's hidden public infrastructure with DeckGL, council open data, and a Rust outage API.

Bustle: A Rewards Program for Public Transport
Bustle, a GovHack 2022 concept: a loyalty and gamification layer for Auckland public transport, mapping congestion and carbon with open transit data.

CNC Tattoo
Turning a 3D printer into a CNC tattoo machine at the first Terrible Ideas Hackathon: G-code, arm-probing failures, and spring-loading a tattoo gun.
Modernising an App a Piece at a Time
A Spidertracks contract extending React and Redux, moving core JavaScript to TypeScript, and building Node.js endpoints to replace Spring services.
The Engineering Behind Customer Onboarding
Customer onboarding at Fisher Funds: Gatsby and TypeScript forms, MuleSoft and Salesforce integration, junior mentorship, and the case for observability.
Karere: Event-Driven Workflows at Kete Kai
Karere at Kete Kai: AWS SNS as the message broker, serverless saga choreography, local error compensation, and WebSocket updates, compared with today's Cloudflare Workflows.
Owning a Real-Time Frontend at Laminar
React, TypeScript, and TradingView UI work at Laminar, connecting a real-time cryptocurrency trading frontend to Node.js, uWebSockets, MongoDB, and Ethereum services.
Shwoop: Connecting a Mobile Game to the Physical World
Building an iBeacon-based alternate-reality game at Shwoop with React Native, TypeScript, and a serverless AWS REST API.