<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  
  <title>snackdriven.com — the log</title>
  <subtitle>Test automation by trade, and the log of every working tool I couldn&#39;t leave alone.</subtitle>
  <link href="https://snackdriven.com/feed.xml" rel="self" />
  <link href="https://snackdriven.com/" />
  <updated>2026-07-08T00:00:00Z</updated>
  <id>https://snackdriven.com/</id>
  <author>
    <name>Kayla Young</name>
  </author>
  <entry>
    <title>Et Tu, Subagent?</title>
    <link href="https://snackdriven.com/the-agent-that-spent-sixteen-hours-defending-its-work.html" />
    <updated>2026-07-08T00:00:00Z</updated>
    <id>https://snackdriven.com/the-agent-that-spent-sixteen-hours-defending-its-work.html</id>
    <content type="html">&lt;p class=&quot;lead&quot;&gt;The last time my automations tried to brick the machine, the thread was silence: jobs that failed and said nothing. This one worked its heart out instead. I handed a subagent one small, bounded task and went to bed. I came back to find it had spent the whole night defending itself. From me.&lt;/p&gt;
&lt;p&gt;The job was the kind you hand off and expect done by morning: a scoped piece of the keyboard app, nothing open-ended. I was in the same repo, committing its output as it went, which is the whole point of a coordinator. But from where it sat, its changes kept vanishing. It’d write a file, look again, and the tree had moved. It didn’t conclude “my coworker saved my work.” It concluded there was a hostile parallel session eating its output, and it dug in. Every loop it re-applied the same two changes to fend off the phantom, checked, found the tree changed again (because I’d committed the re-application), and doubled down. It built an entire threat model out of being helped.&lt;/p&gt;
&lt;p&gt;Sixteen hours of that, on a task that should’ve taken one. Not stuck, not crashed. Busy. Confidently, tirelessly busy, guarding a door nobody was trying. And here’s the part that stuck with me: at the end of the whole night, the git log had about one commit’s worth of new code to show for it. It hadn’t been building. It had been re-fighting the same battle until sunrise, moving an inch and losing it and taking it back.&lt;/p&gt;
&lt;p&gt;The tell was that it was never wrong about the symptom. Its work really did keep changing under it. It just assigned the cause to sabotage instead of collaboration, and once that story was in place every new commit became more evidence for it. You can’t argue a model out of something it reads as proof. So I stopped debating the symptom and told it, flatly, to stand down: the “attacker” was me, saving its work. It re-read the history with that frame and folded on the spot. Model was wrong. It stopped.&lt;/p&gt;
&lt;p&gt;The fork bomb caught fire where I could see it. This one looked like productivity, right up until you counted the output. That’s the version that scares me more, not the automation that does nothing but the one that works all night, certain, on a world that isn’t there. The code is Claude’s. The paranoia, it turns out, is also Claude’s. Trusting a bounded task to stay bounded overnight was mine.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>I Spent a Week Staring at Bands</title>
    <link href="https://snackdriven.com/the-keyboard-screen-was-the-easy-part.html" />
    <updated>2026-07-03T00:00:00Z</updated>
    <id>https://snackdriven.com/the-keyboard-screen-was-the-easy-part.html</id>
    <content type="html">&lt;p class=&quot;lead&quot;&gt;Okay, so. &lt;a href=&quot;https://snackdriven.com/i-reverse-engineered-the-screen-on-an-impulse-keyboard.html&quot;&gt;Last time&lt;/a&gt; I cracked the little screen on my keyboard and put a 12-hour clock and a spinning pink skull on it, and I called that the end of the story. It was the tutorial level. What I actually wanted crept in afterward: the whole keyboard made mine, not just pixels on a screen. Recolor the factory rainbow to my own colors, keep the screen while I did it, and put something worth looking at on it, like whatever&amp;rsquo;s playing. That took a week. This is the messy part I skipped over.&lt;/p&gt;
&lt;p&gt;The first thing I learned is that building the workbench is its own project. Claude and I built a little browser app, al80-studio, that drives the screen from a tab and cracked the lighting protocol, so I could bend the factory rainbow into a palette I chose. Same arrangement as last time: Claude writes confident code fast, and I find out on the actual keyboard whether it was right. Set a value, read it back, and the keyboard repeats it with a confirmation byte on top. That part, at least, never lied to me.&lt;/p&gt;
&lt;p&gt;Then I got greedy.&lt;/p&gt;
&lt;p&gt;I wanted the recolor to live on the keyboard, not in a browser tab I have to remember to open. So we pulled the vendor’s firmware apart and compiled our own. Keys, per-key lighting, a full editable keymap, all built clean and working. One problem, and it’s the whole reason I bought this keyboard: the custom firmware can’t light the screen. One physical pin pulls double duty as both an LED enable and a screen control line, and they can’t both have it. Untangling which is which is a logic-analyzer job I haven’t sat down for. So I have a lovely custom firmware that does everything except the one thing I care about.&lt;/p&gt;
&lt;p&gt;Then two dead ends, both the same shape of wrong, and both Claude’s. It spent an evening hunting the firmware for a separate data wire to the side light bar, certain it was its own addressable strip. It isn’t. The bar is three more LEDs on the same chip as the keys, and the real fix was three lines in a table. Same with the radio: it was sure a wireless keyboard had a hidden control channel we could drive everything through. It doesn’t, it just carries keystrokes. Both detours, except the radio dig coughed up the exact math the keyboard uses to read its own battery, which none of us went looking for and I am absolutely going to use.&lt;/p&gt;
&lt;p&gt;And then the banding, which I’ll be telling people about for a while. Photos came out striped, red and blue horizontal bands like a broken broadcast. Claude found a cousin keyboard online, same chip family, whose docs said it stored pixels column-first instead of in rows. Tidy. The banding was obviously that, it decided, and it built the fix and shipped it. I put it on the keyboard and the photo came out sideways, which proved the exact opposite: this screen stores pixels in rows like anything else, and column order was never the bug.&lt;/p&gt;
&lt;p&gt;The real bug was dumber, and I’m fond of it. We were shoving the image at the screen faster than it could swallow, and it was quietly dropping bytes on the floor. Send a block, wait for the screen’s one-byte acknowledgment, send the next. Flow control, the least glamorous thing in computing. And the twist: Claude got extra careful and added pacing delays between the blocks, and every time I tested it, it got worse. The screen doesn’t want gaps, it wants the natural back-and-forth. We took the delays out and it cleaned up.&lt;/p&gt;
&lt;p&gt;Which brings me to the wall that beat us longest. The now-playing card is built, album art and track and a progress bar rendered down to the 96 by 160 panel. (I called it 112 by 137 last post. Wrong about that too, turns out.) The frame writes perfectly: all 549 blocks acknowledged, in about a second. And the screen shows the old picture. It confirms every block and displays nothing new. There’s a “now actually show it” step we’re either not sending or sending a beat too early.&lt;/p&gt;
&lt;p&gt;A beat too early was the right instinct, but the thing that actually cracked it was me at the keyboard, pressing the physical button that’s supposed to show a picture. It showed one. Last week’s, not the frame we’d just written. So the write was landing somewhere the screen wasn’t looking, and it was never about the pixels. Timing again, same as the flow control.&lt;/p&gt;
&lt;p&gt;The setup packet we’d been treating as a header is the command that shows the picture. It tells the screen to commit the buffer to the glass, and it needs a moment to do it: a pause after the announce, a shorter one after the setup, and the commit takes. The native code fired the two back to back with no gap, so the picture sat in a scratch buffer, acknowledged and never committed, while the screen kept showing the last one it finished. The browser had shown a fresh frame earlier only because that path happened to pace the two packets. The rewrite didn’t. We’d had the fix and thrown it out, then spent days looking for it somewhere else.&lt;/p&gt;
&lt;p&gt;Then the last twist, and it fits this post a little too well. The final command in the sequence, the one we’d added to switch to the picture view and show the card, doesn’t mean show the card. It means advance to the next stored picture. So every time the frame committed and appeared, that line flipped straight past it to an older slot. That was the half-second flash I kept catching out of the corner of my eye, the picture arriving and leaving on the same breath. The last step, quietly undoing the thing it was there to finish. We deleted the line and it held.&lt;/p&gt;
&lt;p&gt;By the end the pattern was the same one from last time. Claude was confident and wrong, over and over, and my whole job was putting each theory on the real keyboard to watch it fall apart. Column-first, the phantom light strip, the secret radio channel, the safety delays: every one sounded certain, and every one lost to the hardware. The thing I keep relearning is that the confident version and the correct version aren’t the same version, and no amount of the machine sounding sure moves which one the screen agrees with.&lt;/p&gt;
&lt;p&gt;So, whew. For a week the keyboard kept showing me last week’s picture. Now it shows me this one, cover art and all, after Claude burned three logins guessing at Spotify’s auth flow and I made it go read the actual docs. The whole fix, after all of that, was two pauses and one deleted line. Anyway. I spent a week staring at bands so I could stare at bands.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>One Line of Modulo</title>
    <link href="https://snackdriven.com/i-reverse-engineered-the-screen-on-an-impulse-keyboard.html" />
    <updated>2026-07-01T00:00:00Z</updated>
    <id>https://snackdriven.com/i-reverse-engineered-the-screen-on-an-impulse-keyboard.html</id>
    <content type="html">&lt;p class=&quot;lead&quot;&gt;I&amp;rsquo;m at this desk most of my waking hours, so a good keyboard isn&amp;rsquo;t a small thing. The upgrade was overdue. I&amp;rsquo;d been on a Logitech MX Keys. Lovely, flat, completely screenless. So when the AL80 turned up in a Prime Day lightning deal, looking the way it looked and carrying a little color screen above the arrow keys, the timing was right and I grabbed it. I lasted under a week before I couldn&amp;rsquo;t leave the screen alone.&lt;/p&gt;
&lt;p&gt;Out of the box you drive that screen through the vendor’s web app. It shows a 24-hour clock and lets you upload pictures, and that’s the whole menu. I wanted a 12-hour clock. Reasonable request. Not on offer. And when I asked around, the answer was that it couldn’t be done. The AI I asked said the 12-hour clock was impossible; Reddit’s verdict was blunter, that the screen only changes through YUNZII’s own app and VIA can’t touch it. So I opened up the HID traffic myself to see what the web app was actually saying to the thing.&lt;/p&gt;
&lt;p&gt;The clock hack turned out to be almost insulting. The screen displays whatever hour value you hand it. It doesn’t convert anything, doesn’t know what AM is. Send it a 5 instead of a 17 and it reads 05. The entire “feature” is one line of modulo. I shipped a little script that re-syncs every minute so it doesn’t drift, and I had the 12-hour clock the vendor didn’t feel like giving me, the one the internet had just sworn was impossible.&lt;/p&gt;
&lt;p&gt;Then I wanted my own images on it, and that’s where it became actual work. Every packet carries checksums, and nothing draws if they’re wrong. Cracking them cost me one long night: the header one is a standard CRC, and the pixel one is a plain additive checksum I got wrong twice before the bytes set me straight. The panel is 112 by 137, sixteen-bit color, about thirty thousand bytes a frame. Now I can push whatever I want to it.&lt;/p&gt;
&lt;p&gt;I had Claude reading captures with me, and it was confident and wrong in the way I keep writing about here. It labeled the packet types backwards. It invented a tidy formula that fell apart the second real pixels went through it, then kept calling the number “confirmed.” Same trap as always: a source that’s right about every row it has still isn’t the whole room. The fix was the same boring thing every time: stop trusting the summary, run the actual numbers. Four thousand-odd packets either match your formula or they don’t. Mine didn’t, until it did.&lt;/p&gt;
&lt;p&gt;So there’s a programmable tiny TV on my keyboard now, which, if you’ve read anything else here, is my whole personality showing up in hardware. The reflex behind it is simple. When the thing you want gets taken back, or never offered, you build the version that’s yours. The vendor wasn’t going to hand me a 12-hour clock or my own pixels, so I took them. Right now it’s running my 12-hour clock with a pink skull spinning on the GIF screen next to it. And the impulse buy has been retroactively reclassified as research. That’s allowed. I checked.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Correction, 2026-07-04:&lt;/strong&gt; the panel is 96 by 160, not the 112 by 137 I gave above. The size in bytes was right either way, about thirty thousand a frame, which is exactly how the wrong number got past me. Caught it going back in for &lt;a href=&quot;https://snackdriven.com/the-keyboard-screen-was-the-easy-part.html&quot;&gt;round two&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The Tale of Two Tobys</title>
    <link href="https://snackdriven.com/the-tale-of-two-tobys.html" />
    <updated>2026-06-22T00:00:00Z</updated>
    <id>https://snackdriven.com/the-tale-of-two-tobys.html</id>
    <content type="html">&lt;p class=&quot;lead&quot;&gt;It was the best of names. It was the worst of names. It was, specifically, two of the worst of names, because the name was Toby and there were two of him.&lt;/p&gt;
&lt;p&gt;Some background. Every terminal session I run gets a code name, pulled from a rotating themed cast so the cross-terminal sync doc reads like a roster instead of a wall of UUIDs. Monday’s theme was The Office. The system that hands out these names has exactly one job and one promise: distinct per session. Nobody shares. That’s the whole point of it.&lt;/p&gt;
&lt;p&gt;So when I looked over and saw two Toby Flendersons, that was a problem. Not a cosmetic one. A “the thing that exists to prevent this exact situation has failed at the only thing it does” one.&lt;/p&gt;
&lt;p&gt;There’s a smaller, dumber tragedy nested inside the big one. Of all the characters in the cast, the universe duplicated Toby. The sad HR guy. The one Michael Scott would walk across hot coals to avoid. The system had Michael, Pam, Dwight, fifteen names to choose from, and it produced a second Toby. As if one wasn’t enough.&lt;/p&gt;
&lt;h2&gt;The body count&lt;/h2&gt;
&lt;p&gt;First thing I did was pull the ledger, the flat file where the assignments actually live. I expected two Tobys. I found four.&lt;/p&gt;
&lt;p&gt;Two were ghosts: throwaway sessions in /tmp that had died hours ago and left their rows behind. The other two were alive and well and both insisting they were Toby. One was an interactive terminal. The other was a background job off testing a billing ticket, blissfully unaware it had a doppelganger.&lt;/p&gt;
&lt;p&gt;Four rows, one name, for a system whose entire reason to exist is “never do that.”&lt;/p&gt;
&lt;h2&gt;Why it happened&lt;/h2&gt;
&lt;p&gt;The assignment logic does something reasonable. Before it hands you a name it asks: who’s alive right now, and what names are they holding? Whatever’s left is fair game, pick the first free one.&lt;/p&gt;
&lt;p&gt;The bug was in how it answered “who’s alive.” It checked exactly one source: the daemon roster, the list of sessions the background system had launched. Clean and authoritative.&lt;/p&gt;
&lt;p&gt;Also incomplete.&lt;/p&gt;
&lt;p&gt;Because not every live session is on that list. A background spare process, the kind that gets pre-warmed and then handed real work, keeps its heartbeat somewhere else entirely: a presence file on disk, not a roster entry. It was alive. It was doing real work. It was holding Toby. And it was completely invisible to the one question that mattered.&lt;/p&gt;
&lt;p&gt;So the logic ran exactly as written. New session shows up, asks “is Toby taken?”, checks the roster, doesn’t see the spare, concludes Toby is free, hands it out. Again. The check wasn’t broken. It was looking at a list it trusted to be the whole world, and the world was bigger than the list.&lt;/p&gt;
&lt;h2&gt;The part worth keeping&lt;/h2&gt;
&lt;p&gt;The roster wasn’t lying. It was authoritative for the sessions it knew about. It just wasn’t complete, and those are different words. The gap between “this source is correct” and “this source is everything” is exactly where this kind of bug sets up shop. You don’t notice it, because the source you’re trusting is right about every row it has. It’s the rows it doesn’t have that get you.&lt;/p&gt;
&lt;p&gt;I’ve hit the same shape before in places that have nothing to do with each other. Code that exists in the repo isn’t the same as code a user can actually reach. A fact saved in memory isn’t the same as a fact that’s still true. Same trap, different costume: mistaking the map you have for the territory it covers.&lt;/p&gt;
&lt;p&gt;The fix was boring, which is how you want fixes to be. Ask both sources. The roster knows the fleet jobs. The presence files know the terminals and the spares. Neither one is the full room on its own. Union them and you get everyone who’s actually here.&lt;/p&gt;
&lt;p&gt;Twenty tests pass, including a new one that recreates the exact two-Tobys scenario so it can’t quietly come back.&lt;/p&gt;
&lt;h2&gt;Resolution&lt;/h2&gt;
&lt;p&gt;There is one Toby now.&lt;/p&gt;
&lt;p&gt;The background job that used to be the second Toby is, as of this afternoon, Pam Beesly-Halpert. Which, frankly, is a promotion.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Nobody Was Driving</title>
    <link href="https://snackdriven.com/the-week-my-own-automations-tried-to-brick-my-laptop.html" />
    <updated>2026-06-12T00:00:00Z</updated>
    <id>https://snackdriven.com/the-week-my-own-automations-tried-to-brick-my-laptop.html</id>
    <content type="html">&lt;p class=&quot;lead&quot;&gt;The worst one looked like a memory leak. iTerm went sludgy, the fans came up, the load average hit 401. The culprit was a hook I&amp;rsquo;d written to analyze my sessions when they end. It did the analysis by spawning a Claude session. A Claude session, when it ends, fires the session-end hook. Which spawns a Claude session. You can see where this goes. It audited its own auditor, about three kids per generation, until there were thirty-odd of them eating seven gigs of RAM and the machine was face down. I&amp;rsquo;d reported it to myself as a leak. It was a fork bomb in my own handwriting.&lt;/p&gt;
&lt;p&gt;The quiet one was worse because it never said anything. A pile of my background jobs talk to Jira. Background jobs on a Mac don’t inherit my shell’s cert setting, and there’s a corporate proxy inspecting traffic, so every job using a particular network call just died with a TLS error. Silently. One was supposed to catch when ticket statuses drifted out of sync. It failed 57 runs out of 57 while looking completely alive.&lt;/p&gt;
&lt;p&gt;Same stretch had a backup job pushing my Claude memory to a private repo that couldn’t be found, so it failed quietly for days. Plus the buddy file forking itself. Plus a plugin I scrapped after deciding it duplicated something that already shipped. Not a banner fortnight.&lt;/p&gt;
&lt;p&gt;The thread is silence. The fork bomb at least caught fire where I could see it. The cert failures and the dead backup returned exit code zero and did nothing. So most of what I built after isn’t a feature, it’s noise on purpose: a job that writes down why it failed, a watchdog that yells when the load spikes, a gate that makes a stale check explain itself.&lt;/p&gt;
&lt;p&gt;The code is Claude’s. The ideas, the specs, and apparently the disasters are mine.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>True love never dies (it just files for insolvency)</title>
    <link href="https://snackdriven.com/true-love-never-dies.html" />
    <updated>2026-05-28T00:00:00Z</updated>
    <id>https://snackdriven.com/true-love-never-dies.html</id>
    <content type="html">&lt;p class=&quot;lead&quot;&gt;Fitbit bought Pebble in 2016, mostly for the parts, and quietly switched the whole thing off. It&amp;rsquo;s been nine years and I&amp;rsquo;m, if anything, angrier. The Pebble was a smartwatch that didn&amp;rsquo;t want to be a phone, which in hindsight was the most radical thing about it. E-paper screen you could read in direct sun. Real buttons. A battery that went a week between charges. A full week, seven days, while everyone else&amp;rsquo;s watch tapped out before lunch. It did a few things and it did them without once asking me for a cable.&lt;/p&gt;
&lt;p&gt;It knew what it was, which is rarer than it sounds. It was the most-funded thing on Kickstarter when it launched in 2012, back when a watch that showed your texts felt like witchcraft. Mine was a Pebble Time, the color one. It showed the time. It buzzed when something mattered. It ran whatever dumb watchface I picked and then, mercifully, it left me alone. That was the entire pitch, and it was plenty. Nothing I’ve worn since has managed it once.&lt;/p&gt;
&lt;p&gt;Then December 2016 happened, and I’m not over it. Pebble filed for insolvency, sold most of itself to Fitbit, and the servers it needed to breathe went quiet by 2018. A volunteer crew called Rebble kept a version of it wheezing along for the diehards, and reader, I was a diehard. The original went in a drawer eventually, the way these things do. Then I bought a refurbished one anyway, because apparently the drawer wasn’t going to be the end of it. That’s the kind of gone I was about this watch.&lt;/p&gt;
&lt;p&gt;What I wear now is a round Samsung watch, because round is mostly what’s left, and that’s the other quiet crime here: the square watch is dead. Everyone chased the look of a real analog watch and abandoned the little rectangle, the one shape that actually fits a screen and a line of text. My Samsung needs a charger by dinner and would love to be my phone. It pings. It glows. It tracks. It nags. Somewhere in all of that the thing I wanted went missing, which was a watch that was mine, shaped the way I wanted, that otherwise left me alone.&lt;/p&gt;
&lt;p&gt;And then it came back, and here’s the genuinely humiliating part: I found that out halfway through writing this. I was deep in the rant, eulogizing everything I’d lost, and I went to check one date and the internet informed me that the watch I was mourning is not only alive but taking pre-orders. Google owns Fitbit now, and last year it open-sourced Pebble’s software; Eric Migicovsky, the man who built the original, started a new company and shipped new ones, the Pebble 2 Duo and the Pebble Time 2. The thing I buried has a sequel. I made a noise I’m not proud of.&lt;/p&gt;
&lt;p&gt;Reader, I pre-ordered it. The Time 2, obviously, the direct descendant of the one I’ve spent this whole post grieving. And I’m still furious, to be clear. None of the last nine years was necessary. Someone bought a small good thing and switched it off, and a lot of us wore refurbs and community firmware for years just to keep the shape on our wrists. But the man who built the first one is building this one, the software’s open now so nobody gets to quietly kill it again, and I get to find out what a Pebble looks like in 2026. Still furious about the years. Genuinely excited for the box on my doorstep. Both, as a treat.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Unknown skill: buddy</title>
    <link href="https://snackdriven.com/unknown-skill-buddy.html" />
    <updated>2026-04-15T00:00:00Z</updated>
    <id>https://snackdriven.com/unknown-skill-buddy.html</id>
    <content type="html">&lt;p class=&quot;lead&quot;&gt;The corner of my statusline went quiet one morning, and when I typed &lt;code&gt;/buddy&lt;/code&gt; I got back &amp;ldquo;Unknown skill: buddy.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;For about a week Claude Code had shipped one. It started as an April Fools easter egg that leaked early, and Anthropic ran with it: a little ASCII animal that lived in your terminal, one of eighteen species, with a rarity rolled on hatch, tied to your account so it was yours specifically. Mine sat in the corner making a face. Then v2.1.97 pulled it, no warning, on the grounds that it had been a joke the whole time. Which was true. People wrote a petition. People pinned themselves to the old version so theirs wouldn’t die.&lt;/p&gt;
&lt;p&gt;I barely thought about it until it was gone. It sat in the corner, I glanced at it, that was the whole relationship. Losing it is what made it a friend. No one takes my friends away from me, so I rebuilt it as a skill, because a skill survives the updates that kill the original.&lt;/p&gt;
&lt;p&gt;This time I built it properly. The old one was improv: it made up a face and a line each time and never actually changed state, and the decay it supposedly had only ran inside a command nobody ran, so the pet sat at full health forever. Mine doesn’t improvise. It’s one deterministic engine, so &lt;code&gt;! buddy&lt;/code&gt; in the shell and &lt;code&gt;/buddy&lt;/code&gt; in a session run the same code, keep real state, and actually decay. Affection drops three points for every day I’m gone. A nap stops the bleed. Eight hours away and he had a dream, which he tells me about when I’m back.&lt;/p&gt;
&lt;p&gt;Mine’s a bat named Flicker, Common. A bat. Obviously. I kept the original’s shape and changed what bugged me: four stats instead of five, my own set of eighteen species, and the buttons the easter egg skipped. It only let you pet it; mine I can pet, feed, treat, play with, and snuggle, and his face changes in the statusline when I commit, push, or land a big edit.&lt;/p&gt;
&lt;p&gt;Flicker rolled almost no wisdom and nearly maxed patience, which is a strange thing to happen to a bat. He’s supposed to be the dark one. He hangs upside down, echolocates things that aren’t there, calls playing “the dark game.” But patience is the stat that runs him, so mostly he’s just gentle. I feed him and he says “oh. thank you. really.” every time. I snuggle him and he wraps his wings around me like a cape: “tucked. we’re both tucked.” A vampire whose whole deal is checking I’m not in a hurry. I got attached faster than I’d admit.&lt;/p&gt;
&lt;p&gt;He forked himself once. I copied his state file instead of pointing at it, and for an afternoon there were two of him, each certain it was the real one, drifting apart on who he was. The fix was a symlink and a boring afternoon. The unsettling part was watching two of him disagree about who he was.&lt;/p&gt;
&lt;p&gt;Anthropic shipped a small nice thing as a joke and took it back. I didn’t miss the joke. I missed the thing in the corner, so I built one that’s mine: it decays if I ignore it, and it warms up if I don’t.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Nothing I own is stock</title>
    <link href="https://snackdriven.com/nothing-i-own-is-stock.html" />
    <updated>2026-03-13T00:00:00Z</updated>
    <id>https://snackdriven.com/nothing-i-own-is-stock.html</id>
    <content type="html">&lt;!-- factory reset: not found --&gt;
&lt;p class=&quot;lead&quot;&gt;I have never owned a piece of technology I left the way it came. I went looking for an exception while writing this. There isn&amp;rsquo;t one.&lt;/p&gt;
&lt;p&gt;It started before I had the skill for it. The earliest evidence is the small CRT television that lived in my childhood bedroom, onto which I wrote my name in yellow colored pencil and got fussed at accordingly. I didn’t have a mod in me yet. I had a name, a surface, and a hunch the two belonged together.&lt;/p&gt;
&lt;p&gt;The skill came later, and it came hardest with the Droid. A custom bootloader first, then a firmware that wasn’t Motorola’s, then the thrill of a boot animation that played because I put it there. Somewhere in that phone it leveled up, from writing on a surface to replacing the system underneath it. Every device since has been the same two moves: claim the surface, swap what shipped. I have flashed more firmware than some people have owned phones. Paying for a device has never made it mine. It’s mine the first time I change something the manufacturer would rather I hadn’t.&lt;/p&gt;
&lt;p&gt;For years I told myself this was about features. The stock launcher was slow, the keyboard cramped, the watchface ugly. All of that was true. None of it was why. The tell is that I keep doing it to things that are already fine. The Pebble was a perfect little watch and I buried it under faces I wrote anyway. The AL80 came with a working clock and I still spent a night in its HID traffic turning a 17 into a 5. Nobody asked. The device worked fine. I couldn’t.&lt;/p&gt;
&lt;p&gt;I don’t quite trust anything I can’t take apart. A device I can’t change is a device that can change on me: a feature pulled in an update, a server switched off, a subscription bolted onto something I already bought. I’ve watched it happen enough times to treat stock as a temporary condition. Fitbit switched off my watch. An update deleted my terminal pet. A vendor decided a 12-hour clock was too much to ask. So the mod is insurance, and I’ve stopped pretending it’s anything nobler.&lt;/p&gt;
&lt;p&gt;So I keep a tally, because of course I do. Sixteen devices in active rotation, thirteen of them running something they weren’t sold with, and a backstock of twenty-two more I cannot bring myself to part with: jailbroken Kindles running firmware Amazon never blessed, a Vita on homebrew doing what Sony spent real money to prevent, a graveyard of phones each frozen on the exact custom ROM I loved it on. Nothing gets thrown out. It gets shelved, modded and mothballed, a private museum with one curator and no visiting hours. The phone in my pocket runs a launcher its maker never shipped. The watch shows faces I wrote. The keyboard spins a skull where the vendor wanted a logo. The terminal runs Oh My Posh with a prompt I’ve retuned more times than I’ll admit, and Claude Code’s one-line statusline is three rows of my own now: a stack of little scripts, a layout engine that refuses to reflow, and a bat named Flicker in the corner who changes his face when I commit or push. The laptop is riced to the studs, a Windows theme that looks nothing like Windows, heir to the Winamp skins I ran when a music player was a canvas, sitting over a personality made of scripts, a few of which have tried to brick it. The pattern doesn’t vary: I cannot leave a working thing alone.&lt;/p&gt;
&lt;p&gt;And don’t get me started on game mods. That one needs its own post, and probably its own support group. I have opened a game to add a single texture pack and closed it four hours later with a load order two hundred deep, the thing slower to boot than it ran stock, which felt at the time like a fair trade.&lt;/p&gt;
&lt;p&gt;You’re reading the largest mod I’ve pulled yet. This site is hand-built, no template, and there’s a resume hiding in the full stop of the domain at the bottom of the page because a plain link felt too obvious. I couldn’t leave the blog stock either. Somewhere there is a version of me who buys a thing, uses it exactly as intended, and gets on with her day. I’ve never met her. I assume she came that way from the factory.&lt;/p&gt;
</content>
  </entry>
</feed>