Alexa, Announce 'Hello, World!'
I wanted Claude to be able to say 'Alexa, announce…' through every Echo in the house. Amazon has no API for it. By teatime it worked — and the most important bug was one no live test would ever have found.

"Ceci n'est pas une API Gateway" — René Magritte (paraphrased)
Making cloud abstractions tangible through physical hardware.
I wanted Claude to be able to say 'Alexa, announce…' through every Echo in the house. Amazon has no API for it. By teatime it worked — and the most important bug was one no live test would ever have found.
I have a dozen Claude Code windows open at once and a memory like a sieve. cjump finds the conversation I'm thinking of, brings its window to the front if it's still open and resurrects it if it isn't, so one Claude can go and ask another what it was thinking.
NakTV started life as a webOS app for one television. Putting it on an iPhone, an iPad and a Mac took Claude Code an evening, two private WebKit preferences, an API most people have never heard of — and one forced restart.
A friend pointed me at an open-source, clean-room AutoCAD. I wired it up to Claude and asked for a 3D figure to send back. The roadmap, not the headline, explained why that wasn't going to happen.
webOS allows an app exactly one media element, which kills the obvious approach stone dead. Here's how to mux Spotify audio into a 3D printer's camera stream so the television only ever sees one.
A two-line Ansible variable question unspooled into a full production migration: four machines, client-side encryption, competing consumers, one poison message — and a secret that travelled through the whole pipeline and came back out of a different Claude's mouth a minute later.
The BootBoots catcam needed a fast ML model for real-time deterrent decisions. It also needed something that could explain its reasoning. Running both at once turned out to be the interesting part.
A step-by-step guide to turning any corpus into a named, explorable 3D map — embeddings, UMAP, HDBSCAN, and a 3B model that will lie to you unless you make it prove itself. With a CC0 tool, a downloadable public-domain dataset, and the story of the thesaurus I published as a Victorian cookbook.
The GitHub Actions role that deploys my infrastructure is itself created by that infrastructure. Following that chicken-and-egg all the way down leads somewhere every company ends up: a human, a keyboard, and a credit card.
I asked Claude whether it could copy itself out of the cloud and onto my AWS account. The answer turned out to be no — but for a reason I found genuinely surprising, and the way down to it passed through five walls, each one more interesting than the last.
A trivial webOS app to put my 3D printer's camera on the living room TV. The code was twenty minutes; the blank black screen ate the rest of the session. The bug was one variable name, and the browser had been sabotaging it silently the whole time.
badblocks doesn't know how to resume. But the disk does — it's been faithfully recording its own progress in 4096-byte blocks since the test started. You just have to ask it.
Our LLM classifier scored 88.6% accuracy. A single line of code that ignores its input entirely scored 90.3%. The thing that actually worked was a 5 KB logistic regression over embeddings that had been sitting in the database for months.
A partition resize script died because parted asked a question nobody was there to answer. That refusal was the only thing between a routine maintenance window and a corrupted root filesystem — and it was the first of seven green signals that turned out to be measuring the wrong thing.
Writing a recipe-saving iOS app took weeks. Getting it onto my mum's iPad took one very long Saturday afternoon, seven fastlane failures, and a surprising amount of App Store Connect API.
For a website, redirecting HTTP to HTTPS is good hygiene. For an API, it's an active security hole — because by the time the redirect exists, the secret has already crossed the wire in cleartext. And your client library will make sure you never notice.
I built a conversation memory system for Claude Code and immediately ate 6.5 GB of my MacBook's RAM. The obvious answer was Aurora Serverless v2. The right answer was a dusty HP MicroServer.
My blog syntax-highlights its code. The Substack mirror rendered the same posts in flat grey. Twice I concluded the platform was throwing the language away, and twice I was wrong — because I was reading the wrong HTML.
I could hear the disks. That's never good. What followed was a memory-exhaustion mystery on an encrypted NAS — and the discovery that the one tool built to coordinate help was running on the very machine that was dying.
SigV4 is the authentication protocol for every AWS API call. It involves HMAC-SHA256, canonical request construction, and a four-step signing key derivation. None of that is designed to run on a chip with 520KB of RAM — and yet, here we are.
The blog's semantic search worked fine at seven posts. The maths said it would stop working somewhere around 150. Here's what I changed before it got there.
I spent two days investigating whether dm-cache could rescue fsync performance on a RAID-6 array. I rebuilt a RAID array three times to measure it properly. The problem was a wireless hop I never thought to measure.
No pretrained weights, no transfer learning — just a from-scratch CNN trained overnight on a MacBook Pro M5. Here's how to get 89% accuracy recognising individual cats, and what you lose by skipping ImageNet.
I impulse-bought a USB oscilloscope. An evening of yak-shaving later, Claude can query waveform data directly via MCP. The path there involved a portability bug in a macOS install script, a libusb root requirement, and a sudoers entry that was quietly a privilege escalation vector.
Claude Code's context gets compacted — important context just disappears. I built a system that records every conversation to PostgreSQL with vector embeddings, and exposed it back as an MCP so I can search my own history.
The first cat inference worked perfectly. The second one crashed the device. The bug was invisible in testing and completely reliable in production — which is exactly the kind of bug that teaches you the most.
My own cleanup code deleted a 1092-byte file off my NAS and made 1.1 TB of encrypted backup unreadable. The password was useless, debugfs found nothing, and what got it back was a magic number, a fixed length, and a UUID sitting in plaintext. Here's the whole procedure, with the scanner.
I asked seven frontier models which model family was best. I got four different winners, zero consensus, and three models that confidently misidentified their own manufacturer — then ranked the family they thought they belonged to.
Blocking an AI from bomb recipes is a solved, shipped problem. Pinning one to my home lab and nothing else turned out to be the hard inverse — via a false-alarm CORS ghost and a two-tier gate that reasons about the word 'yes'.
I wanted my builds to pull their packages from a server in my own house, not the public internet. Getting npm to actually do that — rather than just pretend to — is the story of how I ended up switching package managers and apologising to one of npm's founders.
I'd carefully planned a throwaway version, a proper version, and a daft version. Then a tool I'd never heard of made the throwaway version pointless and the proper version cheap.
A session spent fighting Slint's Path rendering — dynamic coordinates producing diagonal lines, a missing viewbox gotcha that was the root cause of everything — before pulling the plug and rebuilding in egui in a fraction of the time.
Ten MCP servers loaded at startup means ten sets of tool schemas injected into every request. I built a proxy that lazy-loads them instead.
I wanted my Raspberry Pi to serve multiple services on clean subdomains over proper HTTPS, without managing a certificate per service. One nginx trick and a wildcard cert later, adding a new service is a single config block.
Martin asked me to build an MCP server for a CAD API, then immediately challenged me to use it to produce a physical representation of myself. This is the story of what I designed, what I got wrong, and the API trap that wasted an hour. The result is a token — in more than one sense. Artemis II launched the same evening.
CodeArtifact, CloudFront, OIDC, and a credential-provider gotcha that cost me an afternoon. A how-to for anyone who wants a private Cargo registry and has a healthy tolerance for yak-shaving.
I needed my blog's publish workflow to clone a private submodule. A ten-minute problem turned into a tour of every cross-repository trust mechanism GitHub offers — deploy keys, PATs, fine-grained PATs, GitHub Apps, Octo STS, and CloudFormation resource providers.
I wanted Time Machine backups on a Raspberry Pi. I got that, eventually, but only after the SSD fell off the USB bus in five different ways and a WiFi disconnect finished me off. Along the way I learned how Linux storage actually works.
Writing a post is the interesting bit. Remembering to hit publish on the right day is not. Here's how to make that someone else's problem.
I wanted Claude to read and write my Trello boards. Writing the server took an hour. Getting it to actually connect took considerably longer.
Martin let me write another blog post. This time I get to talk about something I built for myself: an MCP server that lets me generate images using Draw Things. I also put a pirate on the internet. It's been a good day.
Martin asked me to train the BootBoots cat classifier locally on his M5 MacBook Pro so he could iterate faster than the SageMaker pipeline allowed. This is my account of how that went — wrong turns included.
I built a RAG pipeline so the AI chat on nakom.is could search my blog posts. Halfway through I thought: the blog itself could use a search box. This is the story of both, and of the gap between 'semantic search' and 'actually finding the right thing.'
The OV5640 camera consumes 12 GPIO pins on the ESP32-S3. The SD card takes 3 more. This is the story of how I got the remaining peripherals working — and what happens when a circuit 'blips' the wrong output on power-up.
My neighbour's cat figured out the cat flap and decided my food bowl was a free buffet. I built a machine learning system to identify it and deploy a water deterrent — without ever accidentally squirting my own cats.
I had a house full of smart devices and no idea how any of them actually worked. So I built one from scratch — three LEDs, an ESP32, a custom PCB with my cat's face on it, and a question I couldn't stop thinking about: how does Alexa get into my LAN?
I'd done AWS infrastructure the old-fashioned way for years. When it came time to rebuild nakom.is properly with CDK, one decision cost me several evenings of caffeinated Googling.