My Arduino spins faster when Claude burns more tokens | TerminalBytes
Skip to content
Go back<br>at the top of the post serves mobile. --><br>My Arduino spins faster when Claude burns more tokens<br>18 May, 2026
On this page
I love mechanical desk toys. Newton’s cradles, kinetic sand timers, those little drinking-bird things. They all share the same defect: they don’t know anything about what I’m doing on my computer. The cradle clicks at the same pace whether I’m in flow, in a meeting, or away from the desk. The whole point of a desk toy is to be for the desk, and yet none of mine had any opinion about the actual work happening on it.
So I built one that does.
It’s a DC motor inside a gutted AliExpress Stirling-engine kit chassis. The flywheel spins faster the more tokens Claude Code is burning. When I lock the Mac, a Kasa smart plug kills the lamp on my desk and the 9V supply to the motor at the same time. When I unlock, the lamp comes back on and the motor goes back to responding to whatever Claude is doing right now.
Could I have just stared at the token counter in the terminal? Absolutely. Could I have wired a smart bulb to brighten with activity? Sure, but lights don’t hit the same. I wanted something physical moving, something my eye catches in peripheral vision the way a clock’s second hand does.
Left pane: my Claude session. Right pane: tail of the Python watcher mapping tokens to motor SPEED.
And here’s what the desk does with that signal.
TL;DR
Arduino Uno R3 + L298N H-bridge + DC motor with flywheel (salvaged from a broken Stirling-engine kit) on a 9V supply
Python launchd agent on macOS polls Claude Code’s local JSONL transcripts, maps token activity to motor SPEED via an exponentially-decaying activity level
TP-Link Kasa power strip with two named outlets, one for a desk lamp, one for the motor’s 9V supply, both toggled by screenIsLocked / screenIsUnlocked notifications
Repos and full code linked in Code and references at the bottom
The Kasa side: my desk listens to my Mac
The simplest piece. macOS broadcasts com.apple.screenIsLocked and com.apple.screenIsUnlocked notifications via NSDistributedNotificationCenter. PyObjC subscribes to both in about ten lines. On lock, the watcher calls out to a TP-Link Kasa HS300 power strip and switches off two named outlets:
Standing Lamp is exactly what it sounds like.
Fidget is the 9V supply for the motor rig.
nc = NSDistributedNotificationCenter.defaultCenter()<br>nc.addObserver_selector_name_object_(<br>listener, b"onLock:", "com.apple.screenIsLocked", None<br>nc.addObserver_selector_name_object_(<br>listener, b"onUnlock:", "com.apple.screenIsUnlocked", None<br>The lamp side is mood lighting. The Fidget side is also a hardware fail-safe: even if the Python crashes between sending SPEED=0 to the Arduino and the motor actually receiving it, cutting the 9V outlet at the Kasa kills the motor unconditionally. Software can write any commands it wants to a chip with no power. I like that the desk has two stop buttons, one in software and one in hardware, both wired to the same event.
python-kasa handles all the protocol. The watcher just shells out to its CLI:
subprocess.run(<br>[KASA, "--host", HOST, "device", "off", "--name", child],<br>timeout=20, capture_output=True, text=True,<br>There’s also a separate shell script (toggle-standing-lamp.sh) for when I want to flip the lamp manually from the command line without going through the daemon. Both live in the screen-watcher repo linked in the Code and references section.
Gutting a broken Stirling engine
The chassis is a clone Stirling-engine kit, the kind that comes with a glass cylinder, a flywheel, a drive belt, a coloured LED inside the cylinder, and instructions that say to soak a wick in denatured alcohol and light it. It was one of my favourite mechanical toys for about a month. Then I dropped it. The pistons snapped, and replacement parts for a $20 AliExpress clone basically don’t exist. The chassis sat in a box for a year while I felt vaguely guilty about it being too pretty to throw out and too useless to put back on the desk.
What’s still good about it after the fall: the mechanical bits. The flywheel is heavy, well-balanced, and looks great spinning. The drive belt couples to a small pulley on a secondary shaft. The whole assembly sits on a polished aluminium base that catches reflections.
Then I realised: I don’t need the heat engine. I just need something to spin the flywheel. A small DC motor running off a 9V supply can drive that pulley through the same belt the burner used to. The only difference is the burner cared about temperature differentials and the DC motor cares about PWM duty cycle.
I sourced a similar Stirling kit on Amazon for anyone trying to do the same thing without waiting on AliExpress shipping. The flywheel-and-belt geometry is the part that matters.
The hardware
Arduino Uno R3 doing PWM on pin 9. I’m using the one from Elegoo’s Most Complete Starter Kit V2.0 because it ships with...