<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Linux on onelegdave.dev</title><link>https://www.onelegdave.dev/tags/linux/</link><description>Recent posts in Linux on onelegdave.dev</description><language>en-us</language><generator>Hugo</generator><ttl>60</ttl><image><url>https://www.onelegdave.dev/images/avatar.jpg</url><title>Linux on onelegdave.dev</title><link>https://www.onelegdave.dev/</link></image><lastBuildDate>Sat, 26 Sep 2026 20:00:00 -0700</lastBuildDate><atom:link href="https://www.onelegdave.dev/tags/linux/index.xml" rel="self" type="application/rss+xml"/><item><title>I Made My AI Tools Ask Permission</title><link>https://www.onelegdave.dev/posts/i-made-my-ai-tools-ask-permission/</link><guid isPermaLink="true">https://www.onelegdave.dev/posts/i-made-my-ai-tools-ask-permission/</guid><pubDate>Sat, 26 Sep 2026 20:00:00 -0700</pubDate><dc:creator>OneLegDave</dc:creator><category>AI crew</category><category>Linux</category><description>For a couple of months I tinkered with an idea: let several AI coding tools work as one crew without letting any of them touch what they should not. Tonight it became a real, free, open-source release candidate called GovernCode.</description><media:content url="https://www.onelegdave.dev/images/posts/i-made-my-ai-tools-ask-permission.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><media:thumbnail url="https://www.onelegdave.dev/images/posts/i-made-my-ai-tools-ask-permission.jpg" width="1200" height="630"/><content:encoded>&lt;p&gt;&lt;img src="https://www.onelegdave.dev/images/posts/i-made-my-ai-tools-ask-permission.jpg" alt="I Made My AI Tools Ask Permission" width="1200" height="630"&gt;&lt;/p&gt;&lt;p&gt;I pay for more AI coding tools than any reasonable person should, and for a couple of months I&amp;rsquo;ve been tinkering with one question: what if they worked together, and none of them could do anything I hadn&amp;rsquo;t agreed to?&lt;/p&gt;&#10;&lt;p&gt;Not &amp;ldquo;agreed to&amp;rdquo; in the sense of clicking Accept four hundred times until my finger goes numb. Agreed to in the sense that the operating system itself won&amp;rsquo;t let them do anything else.&lt;/p&gt;&#10;&lt;p&gt;That idea now has a name, a public repository, a website, and as of tonight a first release candidate. It&amp;rsquo;s called GovernCode. It&amp;rsquo;s free, it&amp;rsquo;s open source, and it will stay that way.&lt;/p&gt;&#10;&lt;h2 id="one-boss-a-few-contractors-and-a-building-inspector"&gt;One boss, a few contractors, and a building inspector&lt;/h2&gt;&#10;&lt;p&gt;GovernCode lets you pick one AI tool to lead a project. That&amp;rsquo;s the Controller. It keeps the big picture and hands small, bounded jobs to the others, the Runners, the way a contractor hands a room to a subcontractor. Each job gets written down first: what to do, which files it may touch, how much of my usage it may burn, and what &amp;ldquo;done&amp;rdquo; means.&lt;/p&gt;&#10;&lt;p&gt;Every one of them runs inside a sandbox that Linux enforces. Not a polite instruction in the prompt asking the AI to behave. The kernel&amp;rsquo;s own locks (Landlock and seccomp, if you want the names) decide which folders it can read, which it can write, and where on the network it can go. If my machine can&amp;rsquo;t enforce those rules, GovernCode refuses to start any AI tool at all and tells me why. There is no &amp;ldquo;just this once&amp;rdquo; switch, on purpose, because I know myself.&lt;/p&gt;&#10;&lt;p&gt;When a tool wants to run something that matters, it stops and shows me exactly what will run, byte for byte. Not a friendly summary. The actual command.&lt;/p&gt;&#10;&lt;h2 id="the-part-where-i-nearly-gave-up-on-my-own-demo"&gt;The part where I nearly gave up on my own demo&lt;/h2&gt;&#10;&lt;p&gt;The first time I tried to show it off, I spent more time clicking Allow than watching the AI work. Every &lt;code&gt;npm test&lt;/code&gt;, every file edit, every harmless &lt;code&gt;ls&lt;/code&gt;. It was secure the way a locked filing cabinet at the bottom of a lake is secure.&lt;/p&gt;&#10;&lt;p&gt;So now I can say yes once, yes for the rest of this job, or yes for this project, and the plain read-only stuff just runs. The sandbox doesn&amp;rsquo;t move an inch when I do that. It only stops asking me the same question forty times. Deleting things, git, the network, and handing work to another AI still ask every single time.&lt;/p&gt;&#10;&lt;h2 id="i-let-the-ais-audit-the-ai-babysitter"&gt;I let the AIs audit the AI babysitter&lt;/h2&gt;&#10;&lt;p&gt;Before putting a release candidate out, I had other AI tools try to break it. They found real holes. A tool could start a background process, &amp;ldquo;finish&amp;rdquo;, and leave that process running. A cleverly placed shortcut in a folder could have widened what a later job was allowed to write. A carefully worded command could sneak past the &amp;ldquo;this is just a harmless read&amp;rdquo; check.&lt;/p&gt;&#10;&lt;p&gt;All of that is fixed, each fix has a test, and the sandbox now proves its rules on your machine every time it starts, including against those exact tricks. I&amp;rsquo;d rather find out from a robot at my desk than from someone&amp;rsquo;s bug report.&lt;/p&gt;&#10;&lt;h2 id="local-models-because-quota-is-money"&gt;Local models, because quota is money&lt;/h2&gt;&#10;&lt;p&gt;Small jobs can go to a model running on my own graphics card. It gets no tools and can&amp;rsquo;t run anything. It reads the files it&amp;rsquo;s given and proposes changes, GovernCode checks every file it wants to touch, and I review it like anyone else&amp;rsquo;s work. The first real one wrote a usage section for a README in six seconds and cost exactly zero of my subscription.&lt;/p&gt;&#10;&lt;h2 id="the-rule-i-care-about-most"&gt;The rule I care about most&lt;/h2&gt;&#10;&lt;p&gt;GovernCode makes building software with AI a lot more approachable. It does not make anyone less responsible for what they ship. If I accept a change, it&amp;rsquo;s mine. I read the diff, I understand the code, I run the tests. The AI can write it. Only I can answer for it.&lt;/p&gt;&#10;&lt;p&gt;That&amp;rsquo;s written into the project&amp;rsquo;s philosophy as rule number two, right after &amp;ldquo;you hold the controls&amp;rdquo;, and it&amp;rsquo;s staying there.&lt;/p&gt;&#10;&lt;h2 id="where-it-stands"&gt;Where it stands&lt;/h2&gt;&#10;&lt;p&gt;It&amp;rsquo;s a release candidate for Linux, for people who like poking at things from a terminal. macOS and Windows are next, together, same priority, because I&amp;rsquo;m not making either one wait for the other. I&amp;rsquo;m dual-booting my laptop with Windows tonight so I can actually test it there.&lt;/p&gt;&#10;&lt;p&gt;None of this would exist if Omarchy hadn&amp;rsquo;t made my computer fun again and dragged a passion I&amp;rsquo;ve had forever back out of the drawer where time had shoved it. So: thank you, DHH, and everyone behind Omarchy.&lt;/p&gt;&#10;&lt;p&gt;GovernCode is at &lt;a href="https://governcode.com"&gt;governcode.com&lt;/a&gt;. It&amp;rsquo;s free forever. If it saves you an afternoon, there&amp;rsquo;s a coffee button. My AI crew runs on tokens. I run on coffee. Only one of us has a button.&lt;/p&gt;&#10;</content:encoded></item><item><title>The Droid You Are Looking For</title><link>https://www.onelegdave.dev/posts/omadroid/</link><guid isPermaLink="true">https://www.onelegdave.dev/posts/omadroid/</guid><pubDate>Fri, 11 Sep 2026 14:00:00 -0700</pubDate><dc:creator>OneLegDave</dc:creator><category>Plugins</category><category>Linux</category><description>My second Omarchy plugin mirrors an Android phone onto the desktop. Most of the actual work was deciding when software is allowed to guess on your behalf, and when it absolutely is not.</description><media:content url="https://www.onelegdave.dev/images/posts/omadroid.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><media:thumbnail url="https://www.onelegdave.dev/images/posts/omadroid.jpg" width="1200" height="630"/><content:encoded>&lt;p&gt;&lt;img src="https://www.onelegdave.dev/images/posts/omadroid.jpg" alt="The Droid You Are Looking For" width="1200" height="630"&gt;&lt;/p&gt;&lt;p&gt;Second plugin. This one puts your Android phone on your desktop: mirrored screen, mouse and keyboard control, no root, no Samsung account, no paid tier, no separate app installed on the phone begging for permissions it doesn&amp;rsquo;t need.&lt;/p&gt;&#10;&lt;p&gt;Under the hood it&amp;rsquo;s scrcpy doing the actual mirroring, because scrcpy is excellent and rewriting it would be idiotic. KDE Connect is optional on top for battery status and Ring. What I built is the part that makes those two things pleasant to live with instead of a pile of terminal commands you look up every single time.&lt;/p&gt;&#10;&lt;p&gt;Currently sitting in the Omarchy marketplace queue waiting on security review, which feels appropriate given how much of this post is about security decisions.&lt;/p&gt;&#10;&lt;h2 id="the-thing-that-took-the-most-thought"&gt;The thing that took the most thought&lt;/h2&gt;&#10;&lt;p&gt;Getting a phone mirrored is not hard. Getting a phone mirrored is &lt;code&gt;scrcpy&lt;/code&gt; and about four minutes of reading. The hard part is everything around it, and specifically one question that came up over and over in different costumes: when is this software allowed to guess?&lt;/p&gt;&#10;&lt;p&gt;Take phone identity. Multiple connections can point at the same physical phone. USB and Wi-Fi at the same time, IPv4 and IPv6, an address that changed when your router handed out a new lease. You want those grouped into one card, obviously, because they&amp;rsquo;re one phone.&lt;/p&gt;&#10;&lt;p&gt;But grouping is a claim. If I merge two connections into one card, I&amp;rsquo;m asserting they&amp;rsquo;re the same device, and if I&amp;rsquo;m wrong your input goes somewhere you didn&amp;rsquo;t intend. So merging only happens on hardware identity that Android actually reports. Matching model names never merges anything. Matching nicknames never merges anything. Two Pixels with the same nickname are two phones until the hardware says otherwise, because &amp;ldquo;they&amp;rsquo;re both called Pixel&amp;rdquo; is a coincidence, not evidence.&lt;/p&gt;&#10;&lt;p&gt;If Android refuses the identity query and discovery can&amp;rsquo;t work it out, the connection stays separate as an unresolved entry rather than getting quietly filed under whichever phone looks closest. An unmerged duplicate is a minor annoyance. A wrong merge sends your keystrokes to the wrong device.&lt;/p&gt;&#10;&lt;h2 id="reconnecting-without-being-creepy-about-it"&gt;Reconnecting without being creepy about it&lt;/h2&gt;&#10;&lt;p&gt;Remembered phones reconnect automatically when discovery advertises the same identity, even if the address and port both changed. That&amp;rsquo;s genuinely convenient and it&amp;rsquo;s the behavior you want.&lt;/p&gt;&#10;&lt;p&gt;What it does not do is automatically pair with phones it&amp;rsquo;s never seen. It does not start a mirror session on its own. Retries are capped at once per address every 30 seconds, and you can turn the whole thing off. After a successful pairing there&amp;rsquo;s a ten minute window where discovery can finish the connection, and then it stops.&lt;/p&gt;&#10;&lt;p&gt;The difference matters. Reconnecting to a phone you already explicitly authorized is completing something you started. Pairing with an unknown phone because it happened to show up on the network is a decision nobody asked it to make.&lt;/p&gt;&#10;&lt;p&gt;Same principle as the GPU selection in my last plugin: auto mode gets to be clever, explicit choices get respected exactly as made.&lt;/p&gt;&#10;&lt;h2 id="wake-is-not-unlock"&gt;Wake is not unlock&lt;/h2&gt;&#10;&lt;p&gt;There&amp;rsquo;s a Wake/unlock button for when the phone&amp;rsquo;s asleep. It sends Android&amp;rsquo;s wake command and asks Android to show its normal unlock prompt. Then it stops and you unlock the phone yourself.&lt;/p&gt;&#10;&lt;p&gt;It does not submit credentials. It does not bypass a secure lock. It cannot, and it shouldn&amp;rsquo;t be able to, and I&amp;rsquo;m not interested in building the version that tries. Lock screens and capture-protected apps keep enforcing their restrictions through the mirror exactly as they should, and if that&amp;rsquo;s inconvenient in some specific app, good. That&amp;rsquo;s the lock working.&lt;/p&gt;&#10;&lt;h2 id="what-it-does-not-do-deliberately"&gt;What it does not do, deliberately&lt;/h2&gt;&#10;&lt;p&gt;No telemetry. No advertising. No cloud relay. No automatic update check. No crash upload. Nothing phones home, ever.&lt;/p&gt;&#10;&lt;p&gt;Runtime phone endpoints are restricted to private local-network addresses. There&amp;rsquo;s no support for pointing it at a public Internet endpoint or overriding the remote ADB server, because a phone-mirroring tool that can be aimed at an arbitrary remote host is a substantially different and worse thing than one that can only talk to your own LAN.&lt;/p&gt;&#10;&lt;p&gt;Automatic clipboard sharing is off. You paste with an explicit keystroke or it doesn&amp;rsquo;t happen. Pairing codes go through standard input, get cleared from the panel, and never touch disk or appear in a process command line where anything reading the process list could scoop them up.&lt;/p&gt;&#10;&lt;p&gt;Nothing gets installed just because you opened the panel. There are Install buttons for missing tools, and they do exactly nothing until clicked.&lt;/p&gt;&#10;&lt;p&gt;And it&amp;rsquo;s honest about what authorization actually means: ADB pairing gives this computer debugging access to your phone, disabling the plugin does not revoke that, and if you stop trusting a machine you need to forget it in Android&amp;rsquo;s own settings. That&amp;rsquo;s in the README rather than buried, because someone who installs this should understand what they just handed out.&lt;/p&gt;&#10;&lt;h2 id="the-bit-im-quietly-pleased-with"&gt;The bit I&amp;rsquo;m quietly pleased with&lt;/h2&gt;&#10;&lt;p&gt;The four-step connect guide. Desktop, Phone, Pair, Ready. Every one of those steps can fail in its own specific way and each failure gets its own specific message instead of a generic &amp;ldquo;could not connect&amp;rdquo; that leaves you guessing which of five things went wrong.&lt;/p&gt;&#10;&lt;p&gt;Wireless pairing on Android has a genuine trap in it: the pairing port and the connection port are different numbers, and nothing about the Android UI makes that obvious. People get it wrong constantly and then have no idea why nothing works. So the plugin calls it out directly, in bold, right where you&amp;rsquo;d hit it.&lt;/p&gt;&#10;&lt;p&gt;That&amp;rsquo;s not clever engineering. It&amp;rsquo;s just having actually used the thing and noticed where I personally got stuck.&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;omarchy plugin add https://github.com/onelegdave/omadroid --enable&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Waiting on security review for the marketplace. In the meantime it installs fine straight from the repo, and every command it can run and every network endpoint it can reach is inventoried in SECURITY.md if you&amp;rsquo;d rather check before trusting it. Which, for something that gets debugging access to your phone, you probably should.&lt;/p&gt;&#10;</content:encoded></item><item><title>It Broke My GPU and I Like It Anyway</title><link>https://www.onelegdave.dev/posts/fun-again/</link><guid isPermaLink="true">https://www.onelegdave.dev/posts/fun-again/</guid><pubDate>Thu, 10 Sep 2026 16:00:00 -0700</pubDate><dc:creator>OneLegDave</dc:creator><category>Linux</category><category>Omarchy</category><description>Omarchy cost me half a GPU, a monitor running at a third its refresh rate, and an entire website. I am still here, and my computer is fun again for the first time in years.</description><media:content url="https://www.onelegdave.dev/images/posts/fun-again.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><media:thumbnail url="https://www.onelegdave.dev/images/posts/fun-again.jpg" width="1200" height="630"/><content:encoded>&lt;p&gt;&lt;img src="https://www.onelegdave.dev/images/posts/fun-again.jpg" alt="It Broke My GPU and I Like It Anyway" width="1200" height="630"&gt;&lt;/p&gt;&lt;p&gt;In the last week Omarchy has quietly run my GPU at half power, left a 165Hz monitor sitting at 60, and been the direct cause of me deleting my own website. Genuinely rough introduction. Both of the first two got their own full autopsy, and the third one was entirely my fault but would not have happened if I hadn&amp;rsquo;t been reinstalling in the first place.&lt;/p&gt;&#10;&lt;p&gt;I&amp;rsquo;m still running it. I&amp;rsquo;m going to keep running it. Not out of stubbornness, and not because I&amp;rsquo;ve talked myself into pretending the problems weren&amp;rsquo;t real. Because for the first time in a long time my computer feels like mine instead of like a rental.&lt;/p&gt;&#10;&lt;h2 id="thirty-nine-seconds"&gt;Thirty-nine seconds&lt;/h2&gt;&#10;&lt;p&gt;I timed an install at thirty-nine seconds. Full desktop, Hyprland running, tiling, themed, done. Windows took over an hour on comparable hardware and spent a good chunk of that time asking me to sign into things and declining to take no for an answer.&lt;/p&gt;&#10;&lt;p&gt;That gap isn&amp;rsquo;t just a fun number to post. Fast installs change your relationship with the machine. When reinstalling costs you an hour of babysitting plus an evening of putting everything back, you don&amp;rsquo;t experiment. You get conservative. You leave broken things broken because fixing them might mean starting over, and starting over is a whole weekend.&lt;/p&gt;&#10;&lt;p&gt;When it costs thirty-nine seconds, &amp;ldquo;let me just wipe it and try that differently&amp;rdquo; stops being a threat and becomes a shrug. That single change quietly unlocks every other good thing here, because it makes being wrong cheap.&lt;/p&gt;&#10;&lt;h2 id="the-extension-surface-is-actually-reachable"&gt;The extension surface is actually reachable&lt;/h2&gt;&#10;&lt;p&gt;I wrote a plugin for this thing. An actual published one, a native system monitor that lives in the bar, reads telemetry straight off the kernel, and pulls every color it draws from the active theme.&lt;/p&gt;&#10;&lt;p&gt;I want to be clear about how unusual that is from where I&amp;rsquo;m standing, because I had zero programming experience not that long ago. On most desktops, &amp;ldquo;write your own panel widget&amp;rdquo; is a project you research for a week and then abandon. Here the plugin API was documented, the validator told me what I&amp;rsquo;d broken before anyone else had to, and installing it was one command. The distance between &amp;ldquo;I wish this existed&amp;rdquo; and &amp;ldquo;this exists and I&amp;rsquo;m using it&amp;rdquo; was days, not never.&lt;/p&gt;&#10;&lt;p&gt;That&amp;rsquo;s not the distro being magic. That&amp;rsquo;s a system that assumed from the start you might want to change it, versus systems built on the assumption you&amp;rsquo;d better not try.&lt;/p&gt;&#10;&lt;h2 id="everything-matches-because-everything-can"&gt;Everything matches, because everything can&lt;/h2&gt;&#10;&lt;p&gt;My desktop is a specific set of colors I picked. My terminal matches. My bar matches. My plugin matches, automatically, because it reads the theme rather than hardcoding anything. When I built this blog, the palette came out of my own desktop, and the banner came out of the same aesthetic.&lt;/p&gt;&#10;&lt;p&gt;That&amp;rsquo;s a stupid thing to care about. I care about it a lot. A machine that looks like something you chose rather than something you were assigned is a machine you actually want to sit down at, and I refuse to be embarrassed about that.&lt;/p&gt;&#10;&lt;h2 id="the-part-where-it-broke-everything"&gt;The part where it broke everything&lt;/h2&gt;&#10;&lt;p&gt;Now the honest bit, because a post that only lists the good parts is an advert and I&amp;rsquo;m not writing one of those.&lt;/p&gt;&#10;&lt;p&gt;The GPU thing was genuinely bad. &lt;code&gt;nvidia-powerd&lt;/code&gt; never gets enabled on install, so my RTX 5060 sat pinned at 50 watts instead of boosting to 100, silently, with no error and no warning, on a laptop that had been flawless for a year prior. I only found it because I got suspicious enough to check numbers instead of trusting vibes. That&amp;rsquo;s a real bug with a real cost, and it shipped.&lt;/p&gt;&#10;&lt;p&gt;The monitor thing was the same flavor: 165Hz panel running at 60 because the config takes whatever refresh rate the monitor advertises first rather than the highest one available. Two unrelated bugs stacked on top of each other, both invisible, both making the machine feel worse than it was in ways I couldn&amp;rsquo;t immediately articulate.&lt;/p&gt;&#10;&lt;p&gt;And then I reinstalled and lost my entire blog, because I&amp;rsquo;d been building it locally without a remote. Not Omarchy&amp;rsquo;s fault in any meaningful sense. But it happened because I was reinstalling, and I was reinstalling because the install is cheap, which is exactly the freedom I just spent three paragraphs praising. Cheap experiments cut both ways.&lt;/p&gt;&#10;&lt;h2 id="why-thats-not-a-contradiction"&gt;Why that&amp;rsquo;s not a contradiction&lt;/h2&gt;&#10;&lt;p&gt;Here&amp;rsquo;s the thing though: I could actually fix all of it.&lt;/p&gt;&#10;&lt;p&gt;The GPU bug, I proved with a controlled experiment, masking and unmasking the daemon on two different distros until the number moved exactly where I predicted, then filed a bug report with reproduction steps clean enough that there was nothing left to argue about. The monitor bug was a config line. The lost blog got rebuilt from my own notes in fifteen minutes and now has three separate layers of backup that didn&amp;rsquo;t exist before, which is strictly better than what I had.&lt;/p&gt;&#10;&lt;p&gt;None of that is possible on a system that treats you as a consumer. When something&amp;rsquo;s broken on a sealed appliance, your options are wait, or accept it, or buy a different appliance. Here, every single problem was mine to dig into, understand, and either fix or report properly. Even the failures were interesting.&lt;/p&gt;&#10;&lt;p&gt;That&amp;rsquo;s what I actually mean by fun. Not that nothing goes wrong. Plenty goes wrong. It&amp;rsquo;s that when something does go wrong, I get to open it up and find out why, and I usually can, and sometimes the fix I send back helps someone else who would&amp;rsquo;ve hit the same wall.&lt;/p&gt;&#10;&lt;p&gt;I had forgotten computers could be like that. Somewhere between work machines I don&amp;rsquo;t control and phones I&amp;rsquo;m not allowed to open, I&amp;rsquo;d drifted into treating my own hardware as something that happens to me rather than something I do things with.&lt;/p&gt;&#10;&lt;p&gt;Thirty-nine seconds to install, an afternoon to write a plugin, a week to find a bug nobody else had pinned down. It broke my GPU and I like it anyway.&lt;/p&gt;&#10;</content:encoded></item><item><title>Zero Is a Lie</title><link>https://www.onelegdave.dev/posts/zero-is-a-lie/</link><guid isPermaLink="true">https://www.onelegdave.dev/posts/zero-is-a-lie/</guid><pubDate>Sun, 06 Sep 2026 11:00:00 -0700</pubDate><dc:creator>OneLegDave</dc:creator><category>Plugins</category><category>Linux</category><description>My first published Omarchy plugin started as a lazy wrapper around btop and ended with me ripping btop out entirely. Along the way I had to decide what a system monitor is allowed to say when it genuinely does not know something.</description><media:content url="https://www.onelegdave.dev/images/posts/zero-is-a-lie.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><media:thumbnail url="https://www.onelegdave.dev/images/posts/zero-is-a-lie.jpg" width="1200" height="630"/><content:encoded>&lt;p&gt;&lt;img src="https://www.onelegdave.dev/images/posts/zero-is-a-lie.jpg" alt="Zero Is a Lie" width="1200" height="630"&gt;&lt;/p&gt;&lt;p&gt;I wanted a system monitor in my bar that actually matched my theme instead of sitting there as a mismatched floating terminal window I had to manually position every single time I logged in. The honest first version of this project was embarrassing: wrap btop, throw it in a panel, call it done. It even shipped under that name internally. Then I actually sat with it for a week and got annoyed enough to rebuild the whole thing properly.&lt;/p&gt;&#10;&lt;p&gt;What exists now is System QuikView, a native Omarchy Shell plugin. No btop. No root service. No cloud account, no pip packages, nothing phoning home. It reads Linux telemetry directly off &lt;code&gt;/proc&lt;/code&gt; and sysfs, renders it through Quickshell&amp;rsquo;s own QML, and pulls every single color it displays from whatever Omarchy theme happens to be active. Switch themes, the widget updates live, because it was never allowed to hardcode a color to begin with.&lt;/p&gt;&#10;&lt;h2 id="the-migration-path-i-owe-past-me"&gt;The migration path I owe past me&lt;/h2&gt;&#10;&lt;p&gt;The installer still knows how to find and migrate that original btop-wrapper prototype: same placement, same preferences, straight upgrade path, no starting over. Small thing, but I&amp;rsquo;m glad I didn&amp;rsquo;t just delete the evidence and pretend the finished version sprang out fully formed. It didn&amp;rsquo;t. It started as duct tape around someone else&amp;rsquo;s tool and got replaced piece by piece until none of the original tape was left.&lt;/p&gt;&#10;&lt;h2 id="the-design-decision-that-actually-took-thought"&gt;The design decision that actually took thought&lt;/h2&gt;&#10;&lt;p&gt;Most of the surface area here is fairly mechanical: read a number, put it on a graph, color it by theme. The one part that made me stop and actually think came from GPU handling, and specifically from a question that sounds trivial until you sit with it: what does the widget show when a sensor genuinely has no reading?&lt;/p&gt;&#10;&lt;p&gt;The lazy answer is zero. Zero is wrong, and it&amp;rsquo;s wrong in a way that&amp;rsquo;s actively dangerous for exactly the same reason a blank medication list is dangerous. Zero degrees is not &amp;ldquo;no reading available,&amp;rdquo; it&amp;rsquo;s a specific, false, freezing-cold claim about a piece of hardware that might currently be on fire. A missing value and an actual value of zero are two completely different facts, and collapsing them into the same digit is a decision to lie every single time the sensor doesn&amp;rsquo;t answer.&lt;/p&gt;&#10;&lt;p&gt;So a missing sensor shows a plain dash. Not a number pretending to be data. An honest admission that nothing came back.&lt;/p&gt;&#10;&lt;p&gt;That same principle runs through the multi-GPU handling too. If you explicitly pick a specific GPU by name and it disconnects, the widget does not quietly fail over to whichever GPU happens to still be plugged in and keep drawing a graph like nothing happened. It shows that reading as unavailable and waits for you to notice, because silently substituting a different device&amp;rsquo;s numbers under the same label is its own kind of lie, just dressed up as helpfulness.&lt;/p&gt;&#10;&lt;h2 id="auto-mode-gets-to-be-smart-explicit-mode-does-not"&gt;Auto mode gets to be smart, explicit mode does not&lt;/h2&gt;&#10;&lt;p&gt;There&amp;rsquo;s a real tension between &amp;ldquo;just work&amp;rdquo; and &amp;ldquo;never guess wrong,&amp;rdquo; so I split it into two modes on purpose instead of picking one philosophy and forcing it everywhere.&lt;/p&gt;&#10;&lt;p&gt;Auto mode is allowed to be clever: prefer a dedicated GPU when one&amp;rsquo;s available and reporting, fall back to whatever else exists otherwise, and it can pick different actual devices for usage versus temperature versus VRAM if that&amp;rsquo;s genuinely what&amp;rsquo;s available. That&amp;rsquo;s a real convenience and I don&amp;rsquo;t think it&amp;rsquo;s dishonest, because nobody who picks &amp;ldquo;auto&amp;rdquo; is claiming to know or care which specific piece of silicon answers.&lt;/p&gt;&#10;&lt;p&gt;But the moment you pin a specific device by name, you&amp;rsquo;ve made a claim, and the widget&amp;rsquo;s job flips from being helpful to being accurate to that claim. It doesn&amp;rsquo;t get to quietly reinterpret &amp;ldquo;show me this GPU&amp;rdquo; as &amp;ldquo;show me a GPU&amp;rdquo; just because the first one went away. Same underlying data source, two completely different obligations depending on whether a human explicitly chose a specific thing or asked for the software&amp;rsquo;s best guess.&lt;/p&gt;&#10;&lt;h2 id="what-actually-shipped"&gt;What actually shipped&lt;/h2&gt;&#10;&lt;p&gt;Bar reading you can set to CPU, memory, GPU usage, temperature, VRAM, network speed, disk usage, or nothing but an icon. Click it, get a full dashboard: history graphs, per-process ranking by CPU then memory, temperature gauges that use the hardware&amp;rsquo;s own reported warning thresholds when it has them and fall back to a plain labeled scale when it doesn&amp;rsquo;t. Sections reorder and collapse, and that layout survives a restart instead of resetting itself every time like it&amp;rsquo;s personally offended you touched it.&lt;/p&gt;&#10;&lt;p&gt;Tests cover the boring-but-load-bearing stuff: no GPU present, one GPU, several GPUs, a GPU that vanishes mid-session, missing readings across the board. &lt;code&gt;python3 -m unittest&lt;/code&gt;, a separate Node suite for the selection logic in &lt;code&gt;Model.js&lt;/code&gt;, a QML linter, and a plugin validator Omarchy itself ships to catch structural mistakes before they become someone else&amp;rsquo;s bug report.&lt;/p&gt;&#10;&lt;p&gt;Installed like any other Omarchy plugin:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;omarchy plugin add https://github.com/onelegdave/system-quikview.git --enable&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;First one of these I&amp;rsquo;ve actually finished and put out publicly rather than leaving half-built in a folder labeled &amp;ldquo;someday.&amp;rdquo; The btop wrapper would have shipped faster. It also would have kept lying to me about GPU temperature the first time a sensor didn&amp;rsquo;t answer, and I&amp;rsquo;d rather have spent the extra week than ship a monitor I can&amp;rsquo;t actually trust the numbers on.&lt;/p&gt;&#10;</content:encoded></item><item><title>Half a GPU</title><link>https://www.onelegdave.dev/posts/half-a-gpu/</link><guid isPermaLink="true">https://www.onelegdave.dev/posts/half-a-gpu/</guid><pubDate>Wed, 02 Sep 2026 14:00:00 -0700</pubDate><dc:creator>OneLegDave</dc:creator><category>Linux</category><category>Omarchy</category><description>My laptop GPU was quietly running at half power on Omarchy, after a full year of this exact machine giving me zero problems. Took less than a week to notice, and I still almost talked myself out of it.</description><media:content url="https://www.onelegdave.dev/images/posts/half-a-gpu.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><media:thumbnail url="https://www.onelegdave.dev/images/posts/half-a-gpu.jpg" width="1200" height="630"/><content:encoded>&lt;p&gt;&lt;img src="https://www.onelegdave.dev/images/posts/half-a-gpu.jpg" alt="Half a GPU" width="1200" height="630"&gt;&lt;/p&gt;&lt;p&gt;I bought a laptop with an RTX 5060 in it a year ago. It has been, until recently, completely unremarkable — no weird crashes, no thermal bullshit, no gremlins. A full year of just fucking working. Then I put Omarchy on it, and in under a week I owned a laptop with half an RTX 5060 in it, and didn&amp;rsquo;t know.&lt;/p&gt;&#10;&lt;p&gt;Here&amp;rsquo;s the thing about a hobbled GPU: it doesn&amp;rsquo;t announce itself. It doesn&amp;rsquo;t throw an error. It just quietly does less work than it&amp;rsquo;s capable of, while you sit there thinking &amp;ldquo;huh, this feels a bit sluggish for the hardware&amp;rdquo; and blaming everything except the actual cause, because the actual cause is invisible unless you go looking for it with a multimeter&amp;rsquo;s worth of paranoia.&lt;/p&gt;&#10;&lt;h2 id="the-vibe-was-off-fast"&gt;The vibe was off, fast&lt;/h2&gt;&#10;&lt;p&gt;This is the part that annoys me most in hindsight: this is a machine with a full year of clean behavior on record. Same laptop, same silicon, same everything, running perfectly fine on a previous install for twelve straight months. Then a new distro goes on, and within days something feels off. The correct instinct there is obvious — suspect the thing you just changed, not the hardware that&amp;rsquo;s been flawless for a year. I did not have this instinct on day one. I had it by about day four, after several days of increasingly irritated vague dissatisfaction.&lt;/p&gt;&#10;&lt;p&gt;New distro, new install, everything looking gorgeous, performance feeling&amp;hellip; fine. Not bad. Just fine. Games ran. Renders rendered. Nothing was on fire. Which is exactly the problem with a silent performance regression — there&amp;rsquo;s no crash to point at, no log line screaming for attention, just a persistent, low-grade sense that something&amp;rsquo;s leaving performance on the table and you can&amp;rsquo;t fucking prove it. So you sit there for days quietly resenting your own laptop like an idiot, forgetting it had been perfect for a year right up until you changed the one thing you changed less than a week ago.&lt;/p&gt;&#10;&lt;p&gt;So I did what any reasonable person does when they can&amp;rsquo;t prove a feeling: I went and got numbers.&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;nvidia-smi&lt;/code&gt; while gaming. Power draw sitting at a suspiciously round &lt;strong&gt;50 watts&lt;/strong&gt;, pinned there like a coward. Not &amp;ldquo;50 watts because the game is light on the GPU.&amp;rdquo; Fifty watts &lt;em&gt;flat&lt;/em&gt;, under a load that should have been begging for more.&lt;/p&gt;&#10;&lt;p&gt;For context: this is a laptop 5060, and 50W is roughly its baseline TGP — the floor, not the ceiling. These chips are supposed to boost well above that under load. Sitting exactly at the floor, permanently, isn&amp;rsquo;t &amp;ldquo;conservative,&amp;rdquo; it&amp;rsquo;s &amp;ldquo;someone forgot to flip a fucking switch.&amp;rdquo;&lt;/p&gt;&#10;&lt;h2 id="proving-it-wasnt-in-my-head"&gt;Proving it wasn&amp;rsquo;t in my head&lt;/h2&gt;&#10;&lt;p&gt;Here&amp;rsquo;s where it stopped being a vibe and became an actual investigation, because &amp;ldquo;the GPU feels capped&amp;rdquo; is not a bug report anyone can act on, including me.&lt;/p&gt;&#10;&lt;p&gt;I had the same physical laptop running CachyOS not long before this, for that entire clean year. Different distro, different config, identical silicon, a full year of prior history saying this hardware has zero problems. So I had something no bug report ever gets: a perfect A/B test on the same chip.&lt;/p&gt;&#10;&lt;p&gt;Booted CachyOS. Same game, same settings, same everything. &lt;code&gt;nvidia-smi&lt;/code&gt; again.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;85 to 93 watts, 78 to 80°C under load.&lt;/strong&gt; Same chip. Same cooler. Same room temperature. Nearly double the power draw, just from being a different pile of software sitting on top of it.&lt;/p&gt;&#10;&lt;p&gt;So it wasn&amp;rsquo;t the silicon. It wasn&amp;rsquo;t age. It wasn&amp;rsquo;t thermal throttling. It wasn&amp;rsquo;t my imagination, my expectations, or a shit game engine. It was Omarchy specifically doing something — or rather, not doing something — that CachyOS was doing right, and that this exact laptop had apparently been quietly capable of for a year without complaint.&lt;/p&gt;&#10;&lt;h2 id="finding-the-leash"&gt;Finding the leash&lt;/h2&gt;&#10;&lt;p&gt;The actual culprit, once I went hunting: &lt;strong&gt;&lt;code&gt;nvidia-powerd&lt;/code&gt;&lt;/strong&gt;, a background service Nvidia ships specifically to manage Dynamic Boost — the mechanism that lets the GPU actually claim higher power states under load instead of sitting at its conservative default. CachyOS enables it automatically on install. Omarchy just&amp;hellip; doesn&amp;rsquo;t. No warning, no prompt, no &amp;ldquo;hey, you might want this.&amp;rdquo; It simply isn&amp;rsquo;t part of the install, so the GPU spends its entire life politely capped at whatever the silicon defaults to out of the box, and nobody bothers to tell you.&lt;/p&gt;&#10;&lt;p&gt;I didn&amp;rsquo;t want to believe a missing background daemon was really the whole fucking story, so I did the only thing that would actually settle it: I broke the &lt;em&gt;working&lt;/em&gt; install on purpose. Masked &lt;code&gt;nvidia-powerd&lt;/code&gt; on CachyOS, the one that had been running fine for a year.&lt;/p&gt;&#10;&lt;p&gt;Power draw dropped to exactly 50 watts. Same number, same ceiling, same everything as Omarchy.&lt;/p&gt;&#10;&lt;p&gt;Then I went back to Omarchy and forced the daemon on by hand.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;100 watts.&lt;/strong&gt; Unlocked, on command, on the exact install that had spent less than a week quietly ripping me off while I sat there blaming a laptop that had done nothing wrong for a year.&lt;/p&gt;&#10;&lt;p&gt;That&amp;rsquo;s as close to a controlled experiment as you get outside an actual lab: flip one service off, lose the performance. Flip it on, get it back. Do it in both directions, on both distros, and watch the number move exactly where you told it to. At that point it&amp;rsquo;s not a theory anymore, it&amp;rsquo;s just a fact you&amp;rsquo;ve now personally reproduced four times.&lt;/p&gt;&#10;&lt;h2 id="the-compounding-bug-that-made-it-so-much-worse"&gt;The compounding bug that made it so much worse&lt;/h2&gt;&#10;&lt;p&gt;While I was in there, I found a second, completely unrelated problem stacked right on top, because apparently the universe wanted this diagnosis to be as fucking annoying as possible.&lt;/p&gt;&#10;&lt;p&gt;My external monitor does 165Hz. Omarchy had it running at 60Hz. Not because of the wattage nonsense — because its config picks whatever refresh rate the monitor &lt;em&gt;advertises first&lt;/em&gt; in its own list, rather than the highest one available, and apparently this monitor&amp;rsquo;s firmware lists 60Hz before 165Hz for reasons known only to whoever wrote its EDID data at 2am on a Friday and never thought about it again.&lt;/p&gt;&#10;&lt;p&gt;So for a good chunk of that week I was troubleshooting &amp;ldquo;why does everything feel underpowered&amp;rdquo; while actually looking at two completely independent bugs at once — a genuinely underpowered GPU, and a display quietly running at over a third of its actual refresh rate. Neither one caused the other. Both made the machine feel like garbage, which was extra insulting given it had been flawless for a year before this install existed. Untangling &amp;ldquo;is this the wattage or is this the refresh rate&amp;rdquo; took longer than either fix did once I&amp;rsquo;d actually separated the two idiots living in the same house.&lt;/p&gt;&#10;&lt;h2 id="filing-the-report"&gt;Filing the report&lt;/h2&gt;&#10;&lt;p&gt;Once I had reproducible numbers in both directions, I wrote it up properly and filed it against Omarchy&amp;rsquo;s own tracker on GitHub. Exact steps to reproduce, exact wattage numbers, the masking test, all of it — not &amp;ldquo;this feels slow,&amp;rdquo; but &amp;ldquo;do X, get 50W, do Y, get 100W, here&amp;rsquo;s the log,&amp;rdquo; cross-linked to the existing discussion thread so nobody has to go hunting for context.&lt;/p&gt;&#10;&lt;p&gt;A bug report that says &amp;ldquo;performance seems bad&amp;rdquo; gets ignored, correctly, because it&amp;rsquo;s unfalsifiable and everyone who&amp;rsquo;s ever run a helpdesk has learned to tune it the fuck out. A bug report that says &amp;ldquo;here is a lever, here is what happens when you pull it, twice, in both directions&amp;rdquo; gets fixed, because there&amp;rsquo;s nothing left to argue with.&lt;/p&gt;&#10;&lt;h2 id="the-actual-takeaway"&gt;The actual takeaway&lt;/h2&gt;&#10;&lt;p&gt;Modern hardware doesn&amp;rsquo;t fail loud anymore. It fails by quietly doing less than it&amp;rsquo;s capable of and daring you to notice, and it can do it in under a week flat if you let it. When a machine that&amp;rsquo;s been rock solid for a year suddenly feels off right after you changed exactly one thing, trust that math immediately. Don&amp;rsquo;t spend four days doubting a laptop that&amp;rsquo;s earned better than that.&lt;/p&gt;&#10;&lt;p&gt;Check anyway. Pull the lever. Watch the number move.&lt;/p&gt;&#10;</content:encoded></item><item><title>Whoopsie</title><link>https://www.onelegdave.dev/posts/whoopsie/</link><guid isPermaLink="true">https://www.onelegdave.dev/posts/whoopsie/</guid><pubDate>Tue, 01 Sep 2026 17:30:00 -0700</pubDate><dc:creator>OneLegDave</dc:creator><category>Linux</category><category>Omarchy</category><description>I deleted my own website, went looking for a backup, and found a beautifully preserved copy of my terminal colour scheme instead.</description><media:content url="https://www.onelegdave.dev/images/posts/whoopsie.jpg" medium="image" type="image/jpeg" width="1200" height="630"/><media:thumbnail url="https://www.onelegdave.dev/images/posts/whoopsie.jpg" width="1200" height="630"/><content:encoded>&lt;p&gt;&lt;img src="https://www.onelegdave.dev/images/posts/whoopsie.jpg" alt="Whoopsie" width="1200" height="630"&gt;&lt;/p&gt;&lt;p&gt;So I built this whole site the other day. Hugo, PaperMod, a custom stylesheet with colours I sampled straight out of the banner image, a hero banner that behaves itself when you shrink the window. Took hours. Committed it to git twice, felt very pleased with myself, went to bed.&lt;/p&gt;&#10;&lt;p&gt;Then I reinstalled my distro.&lt;/p&gt;&#10;&lt;p&gt;You already know how this ends.&lt;/p&gt;&#10;&lt;h2 id="the-part-where-i-find-out"&gt;The part where I find out&lt;/h2&gt;&#10;&lt;p&gt;Fresh install, home directory looked fine. My notes vault was there. Pictures were there. Downloads, full of the usual crap, also there. My Projects folder was sitting right where I left it, containing exactly two things, both belonging to a different project entirely.&lt;/p&gt;&#10;&lt;p&gt;No blog.&lt;/p&gt;&#10;&lt;p&gt;I ran a &lt;code&gt;find&lt;/code&gt; across the entire filesystem for the project directory, because denial is a process and I wanted to watch it return nothing before I&amp;rsquo;d accept it. It returned nothing. Beautiful. Very quick about it, too.&lt;/p&gt;&#10;&lt;p&gt;Then I remembered the migration snapshots on my server. Three of them, taken at various points when I&amp;rsquo;ve moved this laptop between distros like a man who cannot commit to anything. Surely one of those had it.&lt;/p&gt;&#10;&lt;p&gt;The most recent one, taken &lt;em&gt;right before this reinstall&lt;/em&gt;, contained: Desktop, Documents, my shell config, my terminal config, and Pictures. No Projects. Fantastic. Really glad I saved my colour scheme.&lt;/p&gt;&#10;&lt;p&gt;The one before that did have a Projects folder. My heart did a thing. I opened it. Same two unrelated projects, no blog — because that snapshot predates the blog by weeks. So the site was born and died in the gap between two backups, which is a hell of a way to go.&lt;/p&gt;&#10;&lt;h2 id="but-you-used-git"&gt;&amp;ldquo;But you used git&amp;rdquo;&lt;/h2&gt;&#10;&lt;p&gt;I did use git. Two clean commits, nice descriptive messages, branch named &lt;code&gt;main&lt;/code&gt; like a well-adjusted adult who has his shit together.&lt;/p&gt;&#10;&lt;p&gt;Here&amp;rsquo;s the thing about a local git repo that nobody enjoys learning the hard way: the entire history lives in a &lt;code&gt;.git&lt;/code&gt; folder &lt;em&gt;inside the project directory&lt;/em&gt;. Delete the project, delete the history. Git isn&amp;rsquo;t a backup. Git is a very good undo button that lives in the same building as the thing it&amp;rsquo;s undoing. Push it somewhere else or it&amp;rsquo;s just a diary you keep in the glovebox of a car you&amp;rsquo;re about to set on fire.&lt;/p&gt;&#10;&lt;p&gt;Setting up a remote was literally on my todo list from that session. It was item two. I got to item zero.&lt;/p&gt;&#10;&lt;p&gt;The banner image went too, since that was sitting in Downloads, and Downloads is where files go to be deleted by a man doing a spring clean at midnight who is absolutely certain he doesn&amp;rsquo;t need any of this.&lt;/p&gt;&#10;&lt;h2 id="what-actually-protected-me-fuck-all"&gt;What actually protected me: fuck all&lt;/h2&gt;&#10;&lt;p&gt;Let&amp;rsquo;s be honest about the failure. It wasn&amp;rsquo;t bad luck. My server has a genuinely decent backup setup — Restic running twice, once to an external drive and once offsite to Backblaze B2, 7 daily / 4 weekly / 12 monthly retention, integrity checks, failure notifications straight to my phone. It&amp;rsquo;s good. I&amp;rsquo;m proud of it. I&amp;rsquo;d show it to people at parties if I went to parties.&lt;/p&gt;&#10;&lt;p&gt;It backs up &lt;code&gt;/srv/appdata&lt;/code&gt;, &lt;code&gt;/srv/sync&lt;/code&gt;, &lt;code&gt;/srv/backup&lt;/code&gt;, and my compose files. All of which live &lt;em&gt;on the server&lt;/em&gt;.&lt;/p&gt;&#10;&lt;p&gt;The laptop was contributing precisely fuck all to that. Every &amp;ldquo;backup&amp;rdquo; of my laptop was me, by hand, going &amp;ldquo;hmm, I should probably copy some folders before I nuke this thing,&amp;rdquo; and then copying whichever folders I happened to think of in that moment. Which is exactly why I have a pristine copy of my terminal theme and no copy of my actual work.&lt;/p&gt;&#10;&lt;p&gt;Manual backups back up whatever you remembered. Not whatever mattered. Those are very different lists and you only find out how different at the worst possible moment.&lt;/p&gt;&#10;&lt;h2 id="the-fix"&gt;The fix&lt;/h2&gt;&#10;&lt;p&gt;The elegant bit is that I didn&amp;rsquo;t need any new tooling. Syncthing was already running on both machines, already talking to each other, already doing its job for other folders. So:&lt;/p&gt;&#10;&lt;p&gt;My Projects folder is now a synced Syncthing folder, landing at &lt;code&gt;/srv/sync/projects&lt;/code&gt; on the server. That path is &lt;em&gt;already inside both Restic jobs&lt;/em&gt;. So the moment a file hits Projects on the laptop, it replicates to the server, and the next Restic run sweeps it into the local repo and B2. Nothing to configure in the backup scripts. It just inherited the entire chain.&lt;/p&gt;&#10;&lt;p&gt;Staggered file versioning is on at both ends, because plain Syncthing is a mirror, not a backup — delete a file here and it will cheerfully, instantly delete it there, like an over-eager intern. Versioning means the server keeps the old copy in &lt;code&gt;.stversions&lt;/code&gt; instead of enthusiastically helping me destroy my own work.&lt;/p&gt;&#10;&lt;p&gt;One gotcha, and it cost me a genuinely confusing five minutes: Syncthing on my server runs in Docker, with &lt;code&gt;/srv/sync&lt;/code&gt; mounted as &lt;code&gt;/var/syncthing/data&lt;/code&gt; inside the container. So when I typed the host path into the web UI, it threw &lt;code&gt;mkdir /srv/sync: permission denied&lt;/code&gt; and refused to start the folder. It wasn&amp;rsquo;t a permissions problem at all — that path simply does not exist from inside the container. You have to give it the container path. Obvious in hindsight. Deeply fucking irritating at the time.&lt;/p&gt;&#10;&lt;p&gt;And finally, the thing I should have done first, before any of the rest of it: a bare git repo on the server, sitting inside a path Restic already backs up. &lt;code&gt;git push&lt;/code&gt; now sends my history somewhere that isn&amp;rsquo;t this laptop, which is the entire point of a remote and something I will not be forgetting again.&lt;/p&gt;&#10;&lt;h2 id="rebuilding"&gt;Rebuilding&lt;/h2&gt;&#10;&lt;p&gt;Here&amp;rsquo;s the one genuinely smart thing I did last session: at the end of it, I wrote the whole setup up properly. Every CSS variable with its hex value. The full config file. The exact ImageMagick command. The layout override trick and &lt;em&gt;why&lt;/em&gt; it works. All of it in my notes vault, which — being a synced folder — survived without a scratch.&lt;/p&gt;&#10;&lt;p&gt;Rebuild took about fifteen minutes. Install Hugo, scaffold the site, add the theme submodule, paste three files in, done.&lt;/p&gt;&#10;&lt;p&gt;The thing that took hours the first time was never the typing. It was the working out — the hunting through theme files, the trial and error, the six attempts at centering a div. Working out doesn&amp;rsquo;t need to be redone if you wrote it down. Typing is cheap. Figuring it out again is not.&lt;/p&gt;&#10;&lt;p&gt;The only real casualty was the banner. I had to re-source it, and the copy I got back is 1855px wide instead of the original 3710px. Not the end of the world — I dropped the CSS max-width to match, so it isn&amp;rsquo;t being upscaled and going soft on big monitors. Half the resolution, none of the blur. You&amp;rsquo;d never know unless I told you, which I just did, because apparently I can&amp;rsquo;t help myself.&lt;/p&gt;&#10;&lt;h2 id="the-lesson-such-as-it-is"&gt;The lesson, such as it is&lt;/h2&gt;&#10;&lt;p&gt;Backups you have to remember to run are not backups. They&amp;rsquo;re a hobby you do occasionally, and the gap between &amp;ldquo;when I last felt like it&amp;rdquo; and &amp;ldquo;right now&amp;rdquo; is precisely where your work goes to die.&lt;/p&gt;&#10;&lt;p&gt;Automate it or accept that you&amp;rsquo;re going to lose something eventually. There&amp;rsquo;s no third option where you&amp;rsquo;re just really diligent about it forever, no matter how much you&amp;rsquo;d like there to be. I thought I was that guy. I was not that guy.&lt;/p&gt;&#10;&lt;p&gt;Anyway. Site&amp;rsquo;s back. It&amp;rsquo;s now backed up three separate ways, which feels like wild overkill until you remember I&amp;rsquo;m the same idiot who deleted it in the first place.&lt;/p&gt;&#10;</content:encoded></item></channel></rss>