Honey Gate Wrench

When harvesting honey I use several five gallon buckets. The buckets I use have small gates in them to allow honey to pour out.

The internal nut is hexagonal and can be a headache to tighten or loosen by hand. I remove them for cleaning and storage.

So I designed a simple 55mm honey gate wrench that I 3D printed.

The files are on Thingiverse.

ashlight – air quality monitor gadget

We have had a PurpleAir PA-II on our back porch for years. It works fine. The problem is that checking it requires going online to look at a map to find ours.

PurpleAir air quality map of the Los Angeles metropolitan area showing US EPA PM2.5 AQI 10-minute readings, with most sensors displaying yellow circles (moderate air quality, AQI 51-100) and one red circle near downtown LA showing a hazardous reading of 123.


What I wanted was a small device that is green when the air is fine and turns other colors when it’s worse. Here in LA between smog, wildfires, structure fires, and fireworks, the air quality is all over the place.

No specific numbers needed, just a color that gives us a good sense of what’s in the air.

So I built one. I called it Ashlight.

The details

The device is about as simple as it gets, a 16-LED WS2812B ring driven by an ESP32-C3 SuperMini, running ESPHome. It polls the PurpleAir over the home network every few minutes, computes the AQI, and shows the result as a color.

Nothing leaves the house. No cloud service, no API key. The PurpleAir has a local JSON endpoint that’s simple to query.

If the internet goes down, the light keeps working, good for a device whose job is to tell you about a wildfire.

Building it seemed pretty straightforward: Get parts, write a little code, test it, make an enclosure.

The parts are crazy cheap. The ESP32 was ~$4 and the LED ring was ~$5. A capacitor and resistor for the minimum of circuit board protection.

Wiring diagram showing an ESP32-C3 SuperMini connected to a 16x WS2812B LED ring, with 5V and GND power lines, a 1000μF capacitor across the ring's power supply, and GPIO3 connected to the ring's DI (data input) through a 330Ω resistor placed at the ring end.


My soldering is an abomination, mainly because I didn’t want to build it on a breadboard. The resistor and capacitor are just kind of floating in the air.

A small microcontroller PCB held in helping-hand clips with red, green, and black wires soldered to it, positioned in front of an X-Tronic 3020-XTS soldering iron controller displaying 417°C.


I leaned on Claude for the coding. After flashing the ESP32 with ESPHome, Home Assistant was able to see it easily.

We made the color a gradient, shifting into the next color as the AQI increased instead of six distinct steps: green -> yellow -> orange -> red -> purple -> maroon. I set it to shift to lowest brightness at night to avoid lighting up the room.

I did learn that the PurpleAir sensor is also running a tiny processor and doesn’t always respond to the HTTP request for JSON. Evidently, when it’s uploading every two minutes to the PurpleAir map, it ignores everything else. The code is set to be OK with this and retry as needed.

After getting it up and running, I found that the ESP32-C3 SuperMini’s onboard wifi antenna is bad. Not marginally bad, bad bad.

The signal strength was so bad the device was unusable when in the dining room.

I was pretty frustrated, but found Peter Neufeld’s blog on adding a small antenna.

The fix is a sweet hack: solder a 31 mm piece of wire to the existing antenna endpoints. 31 mm is a quarter wavelength of the 2.4 GHz wifi signal.

I tinned a wire, bent it into shape, and soldered it onto the ESP32.

Amazingly, it worked with the Ashlight residing in the dining room.

A small microcontroller PCB held in helping-hand clips with red, green, and black wires soldered to it, with a makeshift wifi antenna soldered to it.


If I were doing this over, I’d get an ESP32 with the U.FL connector for an external antenna and a small flexible patch antenna. Lesson learned.

For the enclosure, I couldn’t find something online that fit the bill, so I built something in Tinkercad.

A Tinkercad 3D design workspace displaying several orange cylindrical containers, a pink small box, two red rectangular shapes, and an orange torus (donut-shaped) object arranged on a blue grid workplane.


I wanted to use a translucent PLA, but the closest I had on hand was some glow-in-the-dark PLA. A little more finicky to print with, but it ended up working out. It’s a super simple enclosure with a hole for the USB-C cable to bring in power. Here are the STLs I designed.

The lid is just a friction fit, but holds together nicely.

A glowing green 3D-printed cylindrical object with a hollow toroidal top containing LED lights, sitting on a striped fabric surface in a dimly lit room beside a smart speaker.


Ashlight is in the dining room, glowing a pale yellow-green. In the morning, Michele and I read the paper and drink coffee there, so it tells us what to expect at a glance.

Here’s a short video about the process.

ashlight – air quality monitor gadget

An ambient lamp that shows outdoor air quality as a color. It polls a PurpleAir PA-II on the local network, computes AQI, and renders the result on a 16-LED ring. Code is on GitHub at github.com/cruftbox/ashlight.

Code is on GitHub at github.com/cruftbox/ashlight.

The README has the full wiring, AQI math, and considerably more detail than anyone needs but that Claude feels is essential.

orbis – another DIY smart home controller

I saw another inexpensive ESP32 device on Aliexpress and decided to see if it would work well as a smart home controller like Tessera.

The ESP32 display has wifi and Bluetooth, is about 1 3/4 inches in diameter, and has a roughly 240×240 screen.

The code conversion was fairly simple, mainly focused on the display and putting in swipe functionality. Claude did the heavy lifting.


Didn’t turn out as useful as the square panel Tessera I built previously.

The round form factor made designing a stand for it more difficult. When I did get something to work, it just didn’t have a good tactile feel and felt like a chore to use. Also, getting a stand design that allowed me to plug in and route a USB-C cable for power was a bit of a headache.

I made a short video about the controller.

Made another smart home controller #esp32 #smarthome #diy

Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube.


Not every project is an amazing success. Some are just trying something new.

All the code is here: https://github.com/cruftbox/orbis

LLM-Friendly Preview – a plugin to let AI review WordPress drafts

tl;dr: https://github.com/cruftbox/llm-friendly-preview

I’ve gotten into the habit of asking AI assistants like Claude, ChatGPT, and Gemini to review my draft posts before I hit publish. A second pair of eyes catches typos, confusing phrasing, and the occasional bad take. The problem was getting them to actually see the draft.

WordPress’s Public Post Preview plugin, my previous go-to, generated preview URLs that a human could click in their own browser, but AI assistants would balk at the link token style. The work around was creating a PDF of the preview and handing that off. That was clunky, took time, and I am lazy.

So I built my own plugin: LLM Friendly Preview. The idea is simple, generate a URL that looks and behaves like a completely normal public page (real theme templates, real styling, no ?preview=1), but is gated by a long, random, single-use token instead of a login session.

From the post editor, I click Generate LLM Review Link, and it hands me something like:


That link works for 3 days and then expires automatically. I can regenerate it or revoke it outright from the same panel, and it’s auto-revoked the moment the post actually gets published, so there’s no lingering way to view a draft that isn’t a draft anymore.

Under the hood it’s all standard WordPress: a rewrite rule, a token stored in protected post meta, time comparison for validation, rate-limiting by IP, and cache-busting headers so no caching plugin accidentally serves up unpublished content to a stranger.

Which LLMs actually work

Here’s where it got interesting. Once the plugin was live, I gave the same link to every the popular models to see who could actually fetch it.

Working: Claude, Gemini, Meta AI, Mistral, Kimi, DeepSeek, Qwen, Grok, HuggingChat, and Ernie Bot all fetch and read the page without issue.

Not working: ChatGPT, Perplexity, and Microsoft Copilot all fail to open the link.

ChatGPT’s failure is the one I actually tracked down: its web-retrieval system rejects newly generated URLs containing private tokens before it even makes an HTTP request. That’s not a bug in WordPress, the plugin, or the response headers. I confirmed the exact same URL returns a clean 200 with the correct content when fetched directly, even spoofing ChatGPT’s own user-agent string. It’s a deliberate caution built into ChatGPT’s URL-safety layer, and it’s exactly the kind of link this plugin is designed to produce: anonymous, temporary, and impossible to guess. Perplexity and Copilot weren’t diagnosed as thoroughly, but the failure pattern looks similar.

For everything else, it works exactly like I wanted: paste a link -> get a review.

All the code is here: https://github.com/cruftbox/llm-friendly-preview

yolodeck – Stream Deck plug-in for Claude

tl;dr: https://github.com/cruftbox/yolodeck

Last week I saw news of an OpenAI gadget for use while running Codex called Codex Micro.


I love a good gadget, but I don’t use Codex much, nor do I need another device on my cluttered deck. The idea of using a button to grant or block permissions seemed great. Many run Bypass Permissions mode, but you do get asked occasionally.

My desk already has an Elgato Stream Deck on it, so I wondered if it could be pressed into use as a similar device when I’m working with Claude Code.


I found a repo by Paul Tyng that had the basics working. His codebase is for macOS, but I work on Windows. So I forked it and worked with Claude to replace ~45 lines of macOS-specific code with Windows equivalents. Most everything else carried over unchanged.

Once I got the basics working, I tried to improve the button design a bit and then add a few features. First was getting a report of how much usage I had left for the session and when it would reset. Running off the Pro plan means having to pay attention to such things that leet Max users don’t have to worry about. I also switch between models, depending on the complexity of the tasks.


This is where I ran into the first issue with how the Claude desktop app on Windows works differently than when running a CLI in Windows Terminal.

From what I found in my testing, when you are running the nice GUI app, Claude kinda says you are running one session at a time. Even though switching between sessions/projects is simple in the app, the underlying hooks only report the single session that you last did active work in.

The second issue: when running the desktop app, there’s no usage data to gather, even though the GUI displays it.


This is weaksauce, IMHO.

Conversely, when running in a terminal, you can be running multiple sessions and yolodeck can see them all. You also get updated usage and reset data. Ideally, this behaviour would be in the Windows app as well, but it’s not.

The Stream Deck lets you know when Claude wants your attention and allows you to approve/deny permissions.

The Stream Deck plugin allows you to place and use (or not use) any of the buttons as you see fit.

I don’t run an agent harness for my home projects, but bolting one on shouldn’t be too hard as long as it can hold open a permission request and wait for my answer, not just fire off a notification after the fact.

In fact, modifying the code to work with Codex or Gemini CLI should be fairly trivial.

All the code is here: https://github.com/cruftbox/yolodeck

Broadside: Cross-posting app for Bluesky & Mastodon

I enjoy posting images to Bluesky and Mastodon, and I try to include alt text every time.

I got tired of writing a post, dragging the image into Bluesky, then into Mastodon, then into my other Mastodon account, and then having to go back to paste in the alt text for each account. Posts with multiple images were an even bigger headache.

To quote Heinlein, “Progress is made by lazy men looking for easier ways to do things.”

So I built a thing. It’s called Broadside.

A broadside is when a ship fires every cannon on one side at once. That’s the whole idea: I write a post once, attach my images, add alt text, and Broadside fires it at every Bluesky and Mastodon account I’ve got in a single click.

It’s probably overkill for a single account, but if you’re juggling multiple social accounts it’s a huge quality of life improvement.

Broadside is built with Flask, using the AT Protocol and Mastodon APIs, and runs in a Docker container.

It also supports threaded posts, with Broadside handling the whole chain across each account.


A few other niceties I added:

  • Stores app passwords and access tokens through a setup wizard.
  • Matches Bluesky’s character counting (emoji and all).
  • Resizes images in the browser before upload.
  • Generates proper Bluesky link preview cards.
  • Shows success/failure status for every account with direct links to each post.


It runs on my home NAS, keeping my credentials local, and never sending them to a third-party service.

Broadside is not a Twitter or Threads tool, just a Bluesky and Mastodon tool. IYKYK.

I built the thing with Claude Code over an afternoon, which still feels a little like cheating.

The code is on GitHub if you want to run or modify it: github.com/cruftbox/broadside.

Compose once. Fire a broadside. Never forget the alt text again.