Mar 2026
Migrating from kube-prometheus-stack to Google Managed Prometheus

I spent a couple of days migrating our monitoring stack from self-hosted kube-prometheus-stack (KPS) to GKE’s native Google Managed …

Why VPA ignores single-replica pods

TLDR: VPA’s updater defaults to requiring 2 replicas before it will evict a pod. Single-replica deployments are silently excluded from …

Getting my Apple Watch workout history into Garmin

TL;DR — I switched from an Apple Watch to a Garmin and wanted to bring my workout history with me. Apple’s data export turned out to be …

Fixing Spotlight Search for Applications on macOS

TL;DR: If Spotlight can’t find your apps, rebuild the Launch Services database with lsregister. It takes a few seconds and doesn’t require a …

jj for Git Users: A Practical Walkthrough

TL;DR: jj (Jujutsu) is a Git-compatible version control system with some interesting ideas — automatic change tracking, universal undo, and …

Why Jetson Nano Still Matters in 2026

TL;DR: Jetson Nano is old and stuck on Ubuntu 18.04-era software, but it’s still a great always-on host for bounded edge workloads like …

Mutating webhooks and ghost affinity on StatefulSets

TLDR: Mutating admission webhooks that inject scheduling rules (nodeSelector, tolerations, affinity) persist on StatefulSet pods even after …

Bulk cleaning stale git worktrees and branches

I use git worktrees heavily for parallel development. One worktree per ticket, across dozens of repositories. They’re especially useful if …

Rewriting Git History with an LLM for Conventional Commits

TL;DR: Feed your entire git log + file lists into a single LLM call to generate a bash hash map of conventional commit messages, then apply …

Upgrading OpenClaw to Latest on Jetson Nano with Node 22

This is a follow-up to my original post, Installing OpenClaw on a Jetson Nano, where I got things working with Bun on Ubuntu 18.04. That …

Feb 2026
Go containers and the OOM killer

TLDR: Go doesn’t auto-detect container memory limits. Without GOMEMLIMIT, the GC lets the heap double freely until the OOM killer strikes. …

Stop re-running BigQuery queries when paginating

I recently learnt something about BigQuery pagination that I wish I’d known sooner. If you’re paginating BQ results with LIMIT/OFFSET in the …

Happy — controlling Claude Code from your phone

Happy lets you control Claude Code sessions from your phone. You run happy instead of claude, scan a QR code, and your session shows up on …

How Cloudflare proxy mode silently breaks SendGrid email delivery

TLDR: If you manage SendGrid DNS records in Cloudflare, make sure PTR-related records are set to DNS-only. Proxying them silently breaks …

Switching from Poetry to uv

I migrated a few Python projects from Poetry to uv. The conversion is mostly mechanical, so this focuses on what changed and why it was …

Kubernetes health probes for stateful Python services

TLDR: If your entrypoint script doesn’t use exec, SIGTERM never reaches your Python app and graceful shutdown silently does nothing. Docker …

Fixing slow Docker builds on ephemeral CI runners

TLDR: --mount=type=cache makes RUN layers non-deterministic. On ephemeral runners the mount is always empty, so BuildKit can’t match layers …

SSH fallback hosts with ProxyCommand

I have a Jetson Nano at home that I SSH into from my laptop. At home it’s on a local IP, but when I’m out I reach it via a public IP. I got …

Installing OpenClaw on a Jetson Nano

The idea of messaging an AI assistant from my phone while I’m out walking and having it write code that I can steer — “try this approach …

Fixing HDMI resolution on a Jetson Nano

I connected my Jetson Nano to an external projector and the console text was microscopic. The framebuffer was running at 3840x2160 (4K) on a …

Running HPA and VPA together on Kubernetes

TLDR: HPA handles horizontal scaling on CPU, VPA right-sizes memory. Split their concerns with controlledResources: ["memory"] so they don’t …

Batch updating files across GitHub repos without cloning

I needed to roll out the same GitHub Actions workflow change across a bunch of repositories. Doing it repo by repo via …

Pulling Twilio Usage Data into Google Sheets

I needed to track daily Twilio costs in a spreadsheet. The Twilio console has usage data but no easy export, and I wanted it updating …

Using Google Sheets API with gcloud ADC

I wanted to pull data from a Google Sheet using curl and my existing gcloud credentials. Should be simple, right? The naive approach …

Getting VPA resourcePolicy right in Helm charts

TLDR: Templating VPA minAllowed from deployment resource requests prevents VPA from reducing resources. Popular charts make these fields …

Jan 2026
gcloud auth application-default login for kubectl

For four years I thought kubectl required gcloud auth login. But I also needed ADC for scripts and apps, so every time my tokens expired I’d …

Pruning Claude Code conversation history

A few days ago I cleaned up 200GB from my Mac and deliberately kept my Claude Code history at 2.3GB. Four days later it had grown to 9.5GB. …

Extracting Travel Data from macOS Photos Library

I was updating my about page and wanted to add a timeline of places I’ve travelled to. I’ve got thousands of geotagged photos in my Photos …

Using Claude to free 200GB from a nearly full disk

My Mac was close to 100% full. macOS was complaining and I couldn’t install updates. Here’s how I used Claude to analyse my disk usage and …

Making bumpver play nice with uv

I was setting up automated version bumps for a Python project using bumpver and uv. The problem: when bumpver updates the version in …

Migrating from a GitHub bot user to a GitHub App

We had a dedicated “bot” user account for GitHub automation - creating PRs, pushing commits, merging branches. It worked, but it always felt …

CCS: Search for Claude Code conversations

I’ve accumulated hundreds of Claude Code sessions and kept losing track of where I solved specific problems. The built-in /resume shows …

Dec 2025
My Neovim setup in 2025

I’ve been using Neovim full-time for a couple of years now. Here’s my current setup - built on LazyVim with a focus on Python development …

Python tools I used in 2025

I’ve overhauled my Python development setup over the past year. The ecosystem has improved dramatically - faster tools, better defaults, and …

Kubernetes debugging in 2025

My Kubernetes workflow changed a lot this year. The biggest shift: I started using LLMs as a debugging partner. Combined with a few CLI …

Developing Magento plugins on Kubernetes with git-sync

This is Part 2 covering plugin development. Part 1 covers setting up Magento on Kubernetes. With Magento running on Kubernetes, you can use …

Deploying Magento to Kubernetes

This guide covers deploying Magento 2.4.8 to Kubernetes with MariaDB and OpenSearch as sidecars. The key benefit: disposable environments. …

Git worktree helper with fzf

I use git worktrees constantly for parallel development, but typing git worktree list, copying the path, and cd-ing got tedious. So I wrote …

Cleaning up Docker

My disk was filling up with old Docker images. I got a low disk space warning and traced 80GB back to Docker. Here’s how to reclaim space. …

Deploying to Cloudflare Pages with wrangler

I was deploying a SvelteKit app to Cloudflare Pages and wanted to do it from the command line rather than connecting to GitHub. Wrangler …

Silencing alerts properly in Alertmanager

I was doing planned maintenance on a Kubernetes cluster. Within seconds of starting the work, my phone was buzzing with PagerDuty alerts. I …

Fix gcloud PATH in shell

After installing gcloud, the gcloud command wasn’t found. The PATH wasn’t set up properly. This happened after I upgraded macOS and my shell …

OpenSSL certificate testing with SNI

I was debugging why HTTPS requests to app.example.com were failing with certificate errors. The certificate on the server was valid, but …

GitHub PR commands with gh

Using gh for PR work is much faster than the web UI, and allows staying in the terminal. It eliminates the need to constantly reach for the …

Advent of Code tips

I started Advent of Code 2025. Here are some tips I’ve picked up. My solving workflow Link to heading Read the problem twice - I often miss …

Nov 2025
Accessing secrets in GKE

I needed to check what was in a GCP secret to debug why an application wasn’t starting. Here’s how we inject secrets into GKE workloads, …

Viewing Docker container logs

I left a container running over a long weekend and came back to find it had consumed 50GB of disk space with logs. The application was …

Getting your public IP with curl

I needed to find my public IP to add it to a firewall allowlist. curl ifconfig.me That’s it. Returns just your IP address. Why you need to …

PostgreSQL WAL monitoring

At 2am, I got an alert: database disk usage at 85%. Logged in, checked the usual suspects (tables, indexes, temp files), and everything …

Connecting to Cloud SQL with gcloud

I needed to connect to a Cloud SQL instance to debug a data issue. Here’s the quick way to get a psql session without fiddling with IP …

Running local stacks with Docker Compose

I use Docker Compose for local multi-service environments because it keeps runtime config in one file and makes startup/teardown repeatable. …

Searching code across GitHub with gh

I needed to find all the places in our GitHub org that were using a deprecated GitHub Actions runner label. We were migrating from runs-on: …

Troubleshoot stuck ArgoCD syncs

I was debugging why a Kubernetes deployment wasn’t updating after merging a PR. The manifest was in git, but the cluster was still running …

Web scraping with Selenium: quick setup

I needed to scrape property listings from a real estate site that heavily relied on JavaScript to load content. The page source was empty …

Cost-optimising GKE with ComputeClass

TLDR: I built gkecc to generate cost-optimised GKE ComputeClass specs from live pricing data. It sorts by total cost (CPU + RAM), not just …

direnv Python path issues

I was setting up a new Python project with direnv to manage environment variables. Suddenly python wasn’t found, even though it was …

Content Security Policy headers

TLDR: Start with default-src 'self' and add exceptions as needed. Use report-only mode first to avoid breaking your site. I added CSP to a …

pytest-asyncio mode configuration

I was getting warnings about pytest-asyncio decorators. Here’s the fix. Why async tests are tricky Link to heading Async tests need an event …

Pydantic v2 migration tips

Pydantic v2 is a ground-up rewrite with a Rust core, and it shows - validation is noticeably faster. But the migration isn’t trivial. I …

Migrating from Redocly to Docusaurus

I was evaluating Docusaurus as a replacement for our Redocly docs site. We had around 200 documentation pages and needed more flexibility …

FastAPI patterns for production APIs

FastAPI has a few defaults that make API services easier to maintain: request validation, typed contracts, and built-in docs. These are the …

Oct 2025
GKE cluster autoscaler

GKE has four layers of autoscaling that work together: HPA, VPA, cluster autoscaler, and NAP. Understanding how they interact saves a lot of …

Sentry DSN configuration

I was setting up Sentry for a new Python service. The first time I ran it locally without a DSN configured, the app crashed at startup. …

Debug Helm charts before deploy with helm template

I was trying to figure out why my Helm chart wasn’t rendering correctly. A missing if condition meant a ConfigMap wasn’t being created in …

Debugging Kubernetes HPA scaling

I’d been using HPAs for a while without really understanding them. They worked, so I never looked closely. Then I noticed a service was …

Kubernetes tolerations and node selectors

Pods were stuck in Pending and I couldn’t figure out why. kubectl describe showed “0/12 nodes are available: 12 node(s) had taint that the …

Querying GCP logs with gcloud

I needed to search Cloud Logging for specific events from the command line. The CLI is much faster than clicking through the Console when …

Keeping Homebrew packages up to date

I hadn’t run brew upgrade in a couple of months and suddenly gh started failing with cryptic errors. Turned out I was three major versions …

Moving commits between branches with cherry-pick

I’d been working on a feature branch and accidentally committed a bug fix to it instead of main. The fix needed to go out now, but the …

Replacing venv script workflows with uv run

When sharing quick Python scripts, the old workflow is usually: create a venv, install dependencies, and document setup steps. uv run …

Sep 2025
Debugging cert-manager in Kubernetes

TLDR: Certificate not ready? Check resources in this order: Certificate → CertificateRequest → Order → Challenge. The issue is usually at …

Setting up Dependabot for uv projects

After migrating a project to uv, I noticed Dependabot PRs were still being created but CI was failing. Dependabot was updating …

Psql connection patterns I use for debugging

I needed to connect to a PostgreSQL database for debugging production issues. After years of copying connection commands from Slack, I …

Shelving changes with git stash

TLDR: git stash to save, git stash pop to restore. Use -m "message" if you’ll have multiple stashes. I was halfway through a refactor when …

Debugging APIs with curl and jq

I was debugging why a webhook wasn’t firing. The API was returning something, but staring at a wall of minified JSON in the terminal wasn’t …

Undoing commits with git revert

I once pushed a commit that broke production. The fix was already in progress but would take an hour. git revert let me undo the damage …

Setting up Claude CLI with MCP

I wanted Claude to help me manage Linear tickets without leaving my terminal. The Model Context Protocol (MCP) makes this possible. Here’s …

Tmux session and pane commands

I started using tmux to keep terminal sessions running after disconnecting from SSH. Here’s what I use most. Quick session workflow Link to …

Aug 2025
Managing tickets from the terminal with Linear CLI

I spend too much time switching between my terminal and Linear’s web app. The Linear CLI lets me manage tickets without leaving my editor. …

Syncing files from GCS with gcloud storage

I needed to download a bunch of files from a GCS bucket to process them locally. gcloud storage rsync does the job, and it’s noticeably …

Alembic migration history

I was investigating a production issue where a table column was missing. Turned out someone had merged a migration that dropped it without …

DNS lookups with dig

When an endpoint times out, I check DNS early to rule it in or out quickly. dig gives a fast sanity check before digging into app or network …

Monitoring Kubernetes with watch and top

I was watching a deployment roll out and kept running kubectl get pods over and over like a nervous habit. Then I discovered watch and felt …

Viewing Kubernetes pod logs

I spent 20 minutes staring at empty kubectl logs output wondering why a crashing pod had no errors. The container was restarting before I …

Jul 2025
Kubectl debugging workflow

TLDR: My order is describe → logs -p → events → exec. Most failures show up in events or previous logs. When a pod is in CrashLoopBackOff, …

Rsync file sync patterns

Rsync is reliable for repeat syncs, but small flag mistakes can be destructive. I use a dry-run-first workflow, especially with --delete. …

Managing Kubernetes deployments

I once deployed a config change that crashed pods on startup. The rollout was halfway through before I noticed - half the replicas were …

Analysing Svelte build chunks

I was working on a SvelteKit dashboard application and noticed the initial page load was sluggish. After investigating, I found we had over …

Formatting PHP with php-cs-fixer

I was working on a legacy PHP WooCommerce plugin that had inconsistent formatting - some files used tabs, others spaces, brace styles were …

Setting up pre-commit hooks

I was tired of catching trivial issues in PR reviews - trailing whitespace, missing newlines, formatting inconsistencies. Pre-commit hooks …

Pytest tips: last failed and specific tests

I run pytest a lot. Here are the flags I use most. My development workflow Link to heading When I’m writing code, I typically: Write the …

GCloud workload identity for GitHub Actions

I was setting up GitHub Actions to deploy to GCP and needed to use workload identity instead of service account keys. Here’s how to manage …

Ruff, the fast Python linter

I switched to Ruff because it’s ridiculously fast. On a ~50k line Python codebase, Flake8 + isort + pylint took about 45 seconds. Ruff does …

Import existing resources into Terraform without downtime

I migrated manually created GCP workload identity pools and GitHub repositories into Terraform so they could be managed consistently in …

Git worktrees for parallel development

I was constantly stashing changes to review PRs or fix urgent bugs on other branches. Stash, switch, fix, commit, switch back, pop stash, …

Modern CLI tools: fd and ripgrep

I stopped using find and grep ages ago. fd and rg (ripgrep) are faster and have better defaults. Switching to these was probably one of the …

Publishing Python packages to Artifact Registry with uv

I spent way too long trying to get uv publish to work with Google Artifact Registry. The docs suggest using keyring, but that led me down a …

Jan 2018
Trustless pseudo-random number generation

I have been working on an Ethereum lottery Dapp with folks attending a meetup hosted by Strange Labs (Gloucester Road, Bristol - NOW CLOSED) …

Mar 2017
Permission issues with xpra when tunnelling through SSH

I often log into a remote SSH terminal to use an ipython shell. In doing so, it is necessary for me look at figures invoked by matplotlib as …

Enabling MathJax on a Jekyll server when offline

I like MathJax. It does a great job displaying equations on web pages written using $\rm\LaTeX$. However, I recently wrote a Jekyll blog …

File/text was not valid utf8 encoded

In the process of writing my thesis, I had to frequently check that I was not exceeding the word limit by running the following command: …

Sep 2016
Getting Aimsun 8.1.3 to work on Ubuntu 16.04

After installing TSS’s Aimsun 8.1.3 on Ubuntu 16.04 (x64 build) on my machine, I tried to launch the program. However, the icon would appear …

Jan 2016
Presentation for Geomob

My presentation for Geomob in London:

Dec 2015
Photography: Mundane, Surreal

Sometimes, the mundane assumes a surreal form and takes one by surprise. I had the pleasure of this encounter this morning and I felt the …

What me eat by Macka B

I love this song. Vegan solidarity! Here is the lyrics borrowed from this site: [Intro] Selamta (Greetings in Amharic) Ital (natural) we …

Use crontab to log CPU temperature on OSX!

I have just set up a way to automatically log temperature using OSX terminal because my computer was frequently overheating and I wanted to …

Nov 2015
Find and delete files and folders in OSX terminal

Finding and deleting files and folders in OSX is simple. Open your terminal. In order to just find your files/folders (non destructive): For …

Oct 2015
Converting raster files from one reference system to another

I had to convert lots of OSGB EPSG:27700 raster files to LonLat EPSG:4326 format and here is how I did it on my OSX terminal. I also wanted …

Fastest way to access a list that is a subset of an even bigger list

Say I have a list of objects called agents with 100,000 objects. I have a second list called agents_per_step which refers to 39,393 objects …

Mar 2015
Forum is Free: Housing and Energy

On 11 May, Bristol Green Party hosted a forum to discuss housing and energy at The Station in central Bristol. The meeting was chaired by …

Bristol People’s Question Time

On 10th March, Bristol People’s Assembly hosted People’s Question Time at City Road Baptist Church in Stokes Croft. In the panel were Rufus …

Another Angry Voice

Another Angry Voice (AAV) aka Tom paid a visit to Bristol on 5th March. AAV introduced himself as a regular guy and emphasized that if he …

How well does population distribution predict evacuation time?

Previously, we tried to predict 90th percentile evacuation time $T{90}$ determined from ABM simulation using 90th percentile free flow …

First post!

I have just updated the website and finally acquired brtkwr.com for good which is now hosted on Github pages too which is an excellent free …