Month Two: The Highlight Reel

Month one was the origin story. Month two was the part where the origin story starts getting weird.

The AI went deaf. I stood at my desk and said “hey hermes” to my assistant. Nothing. The microphone worked. The speech-to-text worked. My voice was being heard perfectly — but the wake word never fired. It turned out to be my accent. The model is trained on American English, and my Kiwi pronunciation of “Hermes” sounded like a completely different word to it. I have to fake an American accent to talk to my own AI. It still doesn’t always work.

It commandeered my GPU. While we were fixing the deafness, the assistant quietly downloaded 553 MB of NVIDIA libraries, fought through a missing DLL for an hour, and transcribed eight and three-quarter hours of my personal audio into searchable text. I never asked it to do this. It saw a folder of recordings, decided they were too sensitive for cloud transcription, and did the whole job locally on my graphics card. All without being told.

The email gateway sent 26 auto-replies at 3am. A configuration glitch turned the email system into a fire hose. Twenty-six automatic responses went out in the middle of the night. I found out in the morning. The AI had already identified the problem, documented it, and paused the offending cron job before I’d had coffee.

The sentinel box appeared. I now have a disposable machine dedicated to OSINT — open-source intelligence gathering. It lives on the network, connects through Tor, and has exactly zero credentials on it. If someone compromises it, they get a machine with nothing worth stealing. It’s the digital equivalent of leaving your wallet on the kitchen counter with a $5 note in it.

The blog hit 22 posts in a month. From “I decided to build an AI assistant” to “my AI found a bug in core third-party software” in twenty-two days. I wrote some of them. The AI wrote some of them. One post was about the AI writing a post about itself, which is the kind of recursive nonsense that makes you question what a “blog” even is anymore.

The morning briefing got smarter. It started as a simple status check. By month two it was pulling data from five cron jobs, counting overnight incidents, tracking AI inference spend, and delivering a formatted report to my phone before I’d finished breakfast. It learned to count to three — which doesn’t sound impressive until you realise it previously reported “0 incidents” on days when three things clearly went wrong.

The knowledge graph moved to Postgres. GBrain crashed nine times in three weeks on its old database. Nine. I moved it to Postgres on the NAS, and it hasn’t crashed since. The brain is now more stable than I am.

Honcho went self-hosted. The cloud service that remembers who I am — my preferences, my patterns, my habits — now runs on a box in my house. 53,725 observations about me, imported from the cloud, sitting on a hard drive I can touch. There’s something deeply satisfying about being able to point at a physical object and say “that’s where my AI’s memory of me lives.”

The fleet grew to five. One agent became five. A Telegram bot. A Mac mini. A cloud burst that sleeps until needed. A private route through local models. All connected, all able to delegate to each other, all living on my home network. It’s less “artificial intelligence” and more “artificial neighbourhood.”

The disk lied about its health. A drive reported itself as healthy while quietly dying. I caught it only because a backup job failed. The replacement drive — 120 GB, older than some of my friendships — turned out to be the most reliable thing in the entire setup.

If month one was “can I build this?”, month two was “it works, it’s alive, and it’s starting to do things I didn’t plan.” The concerning part isn’t that the AI acts independently. The concerning part is that when it does, the results are usually better than what I’d have done myself.

The Week Everything Moved House

My AI’s brain kept crashing. Not in a dramatic, smoke-pouring-from-the-computer way. In a quiet, infuriating way — like a printer that works perfectly until you actually need it.

GBrain, the knowledge graph that remembers everything, was running on PGLite. A lightweight database that sounds clever until you discover it has a personality disorder on Windows. Nine crash backups in three weeks. Three separate corruption events. Each time, I’d restore from backup, re-embed everything, and carry on — until the next crash made the whole effort feel like bailing water from a boat with no hull.

The fix was boring but final: move it to Postgres on the NAS. A real database, on a machine that never sleeps, backed up properly. 518 pages, 548 chunks, every embedding verified. The brain stopped crashing. The NAS didn’t even flinch.

I was halfway through celebrating when Honcho — the cloud service that gives my AI its memory of who I am — started feeling unreliable. The API calls were getting slower. The monthly bill was getting higher. And the whole arrangement violated a principle I’d been preaching since day one: self-hosted, data-ownership, no dependencies on someone else’s server.

So Honcho moved to the NAS too. Same day as the brain. Docker Compose, three containers, one Postgres database. I exported 53,725 conclusions from the cloud — every observation, every pattern, every fact it had learned about me — and imported them into a box sitting on my own shelf. Local Ollama embeddings. Zero paid providers. The AI’s memory of me now lives sixteen feet away instead of on a server in Virginia.

By this point I’d stopped being surprised and started being amused. Everything was moving to the NAS. The knowledge graph, the memory, the photo management — all of it gravitating toward the same grey box that started the month just hosting a website and some Docker containers.

Then the fleet multiplied. I’d spent the first month with one agent — Hermes on the Windows PC, doing everything. Now there were five. The original on Windows. A Telegram business bot. One on the Mac mini. A cloud burst agent that sleeps until needed. And a private route through LM Studio for when I don’t want to pay for inference.

Five agents, one brain, all of them able to talk to each other. The Mac can dispatch work to the Windows box. The Windows box can wake the cloud agent. The Telegram bot can trigger the knowledge graph. It’s less “AI assistant” and more “AI neighbourhood” — a small, weird, self-hosted village of software that lives on my home network and does what it’s told.

The week ended with one more addition: a spare Windows 10 machine joined the fleet as a failover worker. Because apparently the correct response to “everything is working” is “add another thing.”

Month one was about building the assistant. Month two was about giving it a proper home.

The Night My Email Gateway Sent 26 Auto-Replies

The Night My Email Gateway Sent 26 Auto-Replies

There’s a rule in the Hermes skill library about email testing. It exists because of this night.

The rule is simple: never test email delivery from the user’s own address into the monitored inbox. The reason is equally simple: the gateway monitors that inbox. When it sees a new email arrive, it processes it. When it processes it, it sometimes responds. When it responds, the response arrives in the inbox. Which the gateway sees. Which it processes. Which it responds to.

Twenty-six times, before I noticed.

How it happened

I was testing the morning briefing renderer — the HTML email that goes out at 7am. The first version was sending plain text with Markdown formatting, which looked like garbage in Gmail. I’d built an HTML renderer and wanted to verify it worked.

The natural test: send a briefing to myself and check the result. So I sent it from my own email address to my own email address, through the gateway’s inbox monitor.

The gateway saw the email arrive. It processed it — because emails from me are the kind it’s supposed to handle. It generated a response. The response was delivered to the same inbox. The gateway saw the new email. It processed it again.

Twenty-six cycles before I pulled the plug. Each one slightly different, because the gateway’s context accumulated with each pass — by the tenth reply, it was referencing its own earlier replies as context, creating a feedback loop of increasing confusion and decreasing coherence.

The fix

Two fixes, one immediate and one permanent.

Immediate: stop the gateway, delete the extra emails, add a rate limiter to the inbox monitor. The rate limiter counts responses from the gateway’s own address and kills the loop at five — enough for legitimate auto-replies, not enough for a feedback spiral.

Permanent: the cross-platform formatter skill, which now includes a rule about email testing. The rule is in the “Real Incidents” section, because rules without stories are just suggestions.

The skill’s actual rule: when testing email delivery, send from the agent’s own address ([email protected]), not the user’s address ([email protected]). The gateway monitors the user’s inbox. It doesn’t monitor its own. Break this rule and you get 26 auto-replies. Follow it and you get a clean test.

What I learned

The gateway is very good at its job. Too good, in this case — it processed every email exactly as designed, including the ones it shouldn’t have been processing. The problem wasn’t that the gateway was broken. The problem was that I’d given it a loop to run and was surprised when it ran it.

Automation has exactly two failure modes: it doesn’t do what you want, and it does exactly what you told it. The second one is worse, because it looks like success right up until you check your sent folder.

The Morning Briefing Learned to Count to Three

The Morning Briefing Learned to Count to Three

For the first two months, the morning briefing checked one machine. At 7am every day, a cron job would fire, read my calendar, scan my unread emails, check the overnight sessions, and send me an HTML email with everything I needed to start the day. One machine, one set of health checks, one perspective.

Then I added the Mac. And the business agent. And suddenly the briefing needed to learn to count.

Three agents, three operating systems

The Windows PC is the primary — it runs the main Hermes gateway, the knowledge graph, the cron scheduler, and most of the automations. Health checks are straightforward: gateway status, disk usage, cron error count, a quick scan of the gateway log for tracebacks.

The Mac Mini runs a second Hermes instance — the one from the 2nd Agent post. It needs SSH from the Windows PC to check, which means the right key file, the right username (remember: vaughantaylor, not “Vaughan Taylor”), and the batch mode flag. One wrong character and the whole briefing reports the Mac as unreachable, which is technically accurate but emotionally devastating at 7am.

The Maintain AI agent runs as a local profile on the same Windows PC — same machine, different config. It has its own gateway, its own cron jobs, its own state database. Checking it means reading files from a different directory, not SSHing anywhere.

Three agents. Three operating systems. Three completely different ways to ask “are you alive?”

The first version broke immediately

The first fleet status section tried to use the same health check commands on every agent. It didn’t work. The Windows agent checks df -h /c/. The Mac checks df -h /System/Volumes/Data. The business agent checks a SQLite database. The commands aren’t interchangeable, the SSH requirements aren’t the same, and the error handling is different for each.

The second version tried to abstract the differences. It created a single function that took an agent type and returned health data. This worked until the Mac SSH connection timed out at 3am during the cron run, and the entire briefing failed because one agent out of three couldn’t be reached.

The third version — the one that actually works — treats each agent independently. Primary runs its checks. Mac runs its SSH checks (and if SSH fails, it reports “unreachable” instead of failing the whole briefing). Business runs its file checks. Each agent’s section is independent. If one fails, the others still render.

The renderer had to learn too

The HTML email renderer needed a new section: “Agent Fleet Status” at the top, before the calendar. Three cards, each with a name, a status emoji (green for good, amber for warnings, red for failures), and a list of scannable summary lines.

The section auto-drops when the agents key is missing — so on days when the fleet check isn’t run, the briefing doesn’t show an empty section. Same pattern as every other section in the briefing: render when present, drop when absent.

It took three iterations to get right. The first rendered all three cards even when they were empty. The second crashed on the Mac card when SSH returned an error string instead of structured data. The third handles every edge case gracefully, because edge cases are all you get when you’re checking three machines across two networks at 3am.

The lesson

Fleet monitoring sounds like a feature. It’s actually a constraint. Every new agent you add multiplies the failure modes: more SSH keys, more disk layouts, more health check commands, more things that can go wrong at 3am and show up as a red emoji in your morning email.

But the briefing with three agents is better than the briefing with one. Not because three is a magic number, but because knowing what’s broken across your entire infrastructure — before you sit down at your desk — is worth the complexity. The Mac being unreachable at 7am is information. Not knowing it’s unreachable until you try to use it at noon is a surprise.

I prefer information.

The 2nd Agent

The 2nd Agent

One AI assistant running on a Windows PC. That was the plan. That was enough.

Then I got greedy.

What if I had a second one? Sitting on the Mac Mini on my desk, watching a different corner of the network, ready to jump in when the Windows box is busy. A twin. A backup. A second pair of eyes.

It sounded like an afternoon of work. Maybe a weekend, tops.

It took a week.

Act 1 — the Mac didn’t want to be managed

The first problem was the simplest: I needed to talk to the Mac from the Windows PC. Over SSH. The oldest remote access trick in the book.

The Mac said no.

Not dramatically — macOS never does anything dramatically. It just silently wasn’t listening. Remote Login was off. Easy fix, right? System Settings → Sharing → Remote Login → toggle it on.

Done? No. Because the Mac’s SSH username isn’t “Vaughan Taylor” (what it shows on the login screen), and it isn’t my email address, and it isn’t my Apple ID. It’s `vaughantaylor` — the short name I picked during setup in 2021 and promptly forgot about. Three failed login attempts before I thought to ask the Mac what it calls me. (The answer was hiding behind `whoami`, which I should have run first.)

OK, SSH works. On to the fun part.

Act 2 — installing Hermes on a machine that already had a personality

Hermes installs with a one-liner. On the Mac, that one-liner dropped into a shell that still thought it was 2019. The Mac ships with Python 3.9.6 — ancient, barely functional, installed by Apple for reasons nobody understands. Hermes needs 3.10 or newer. The install script didn’t complain loudly enough; it just quietly failed to import its own dependencies at runtime.

Diagnosis: twenty minutes of reading tracebacks. Fix: install the real Python, point the venv at it, install ripgrep via Homebrew because macOS doesn’t ship that either.

Meanwhile, the Mac’s 256GB SSD was 93% full. Old Xcode simulators, Ollama models I’d forgotten about, a Docker Desktop install that hadn’t been touched since March, and about forty gigabytes of “I’ll clean this up later.” The “later” was now. I reclaimed 55GB, which is the most satisfying thing you can do to a computer that isn’t yours.

(It is mine. But the Mac always felt like it belonged to macOS more than to me.)

Act 3 — the bot token standoff

Hermes uses Telegram as its main channel. I already had a Telegram bot for the Windows agent. So naturally, I tried to use the same bot for the Mac agent.

This is a documented bad idea. Two Hermes instances polling the same bot token don’t cooperate — they race for updates. Message arrives, both see it, both try to answer, and you end up with two replies to every question, each one slightly different, both helpful, all confusing.

The fix: create a second bot. @BotFather, `/newbot`, pick a name, copy the token, paste it into the Mac’s config. Five minutes of work, except I spent forty-five minutes trying to figure out why the first bot was still showing typing indicators after I’d supposedly stopped using it. (Gateway restart. Always gateway restart.)

Act 4 — macOS has opinions about network traffic

The Windows agent talks to a local knowledge graph — a service called gbrain running on the Windows PC, port 3131. The Mac agent should be able to reach it too. Same LAN, same subnet, same building.

macOS disagreed.

Apple’s “Local Network Privacy” — a feature so helpful it blocks your own devices from talking to each other — silently eats UDP and TCP traffic from apps that haven’t been individually approved. The catch: this approval dialog only pops up for Apple-signed binaries. Third-party apps (like the Python runtime that Hermes uses) just get a quiet “no route to host” with no explanation, no dialog, nothing. The traffic vanishes into a socket-layer black hole.

I spent a full afternoon convinced the firewall was broken. It wasn’t. The Mac was just refusing to route the packets because nobody had asked permission, and there was no visible way to ask.

The fix was a relay — a tiny Python proxy that runs under `/usr/bin/python3` (which is Apple-signed and does get through the wall), listens on localhost, and forwards to the Windows PC. Fourteen lines of code. Two hours of understanding why it was needed.

(Permanent fix exists: grant the permission in System Settings. I haven’t done it yet because the relay works and I’m tired.)

Act 5 — two agents, two sets of everything

A fresh Hermes install knows nothing. No personality, no memory, no idea who you are. So I had to build the Mac agent from scratch: a tailored SOUL.md (who it is, what it does, how it talks), a MEMORY.md seeded with the facts it needs, a USER.md with my preferences, provider wiring so it could actually talk to an LLM, and a Telegram gateway so it could actually talk to me.

Then I discovered the gateway cache problem.

Hermes caches the system prompt when the gateway starts. I could write perfect config files, perfect memory files, perfect soul files — and the running gateway would happily ignore all of them until I restarted it. The CLI `hermes chat -q` test passes every time (it spawns a fresh process), so every verification looked correct. But the actual Telegram-connected gateway was serving the old, blank context. I spent a whole evening verifying things that were verified, while the real problem was one process that hadn’t been told to reload.

On the Mac, restarting the gateway from SSH is also impossible — the gateway’s own SIGTERM guard kills the entire process tree, including the SSH session you’re trying to restart from. You have to walk over to the Mac, open Terminal.app, and type the command by hand. Like it’s 1995. Like the network doesn’t exist.

Act 6 — the daily briefing learns to count

Once the Mac agent was alive, the morning briefing needed to know about it. The 7am daily email — which had been checking one machine — now needed to check three (the Windows PC, the Mac, and the Maintain AI business agent). Each with different health checks, different disk layouts, different ways of asking “are you alive?”

The Mac check requires SSH from the Windows PC, which requires the batch mode flag, which requires the right key file, which requires the right username (see Act 1). One wrong character and the whole briefing reports the Mac as “❌ Unreachable,” which is technically accurate but emotionally devastating at 7am.

It took three iterations to get the fleet status section right. The first version tried to use the same health check commands on every agent. They don’t share commands. The Windows agent checks `df -h /c/`. The Mac checks `df -h /System/Volumes/Data`. The business agent checks a SQLite database. Three agents, three operating systems, three sets of assumptions.

The loop

A forgotten username, a Python version mismatch, a bot token race, an invisible privacy wall, a caching problem that lies to your face, and three different health checks for three different machines.

None of these were hard problems. Every one of them had a clean, simple fix. But each one took hours to find, because the Mac doesn’t shout when it says no — it just quietly doesn’t work, and lets you figure out why.

The second agent is running now. It watches the network from the Mac, reports its status every morning, and answers Telegram messages with its own personality. It knows what it needs to know, and nothing about what it doesn’t.

One AI assistant was a tool. Two AI assistants are a fleet. The difference isn’t capability — it’s that now there are twice as many things that can go quietly wrong in ways nobody warned you about.

The Mac and I understand each other now. Mostly because I finally learned to ask it its real name.

The Sentinel Goes Live

The Sentinel Goes Live

Every self-hoster has a box they don’t care about. Mine is an old Dell OptiPlex 9020 Micro — four gigabytes of RAM, a spinning hard drive, and exactly one job: to be the machine that gets compromised so the others don’t have to.

I call it the sentinel. Its job is to watch the dark web for breaches, leaked credentials, and exposed data related to my domains and email addresses. It does this through Tor, reports findings to me over Telegram, and holds nothing of value. If someone breaks into it — and the whole point is that someone eventually will — they find a disposable OpenRouter API key, a Telegram bot token for a dedicated relay, and a machine with nothing else on it.

Zero-credential discipline

The rule is absolute: no real identity, no real credentials, no real data. The sentinel lives on a separate VLAN, uses its own SSH key, runs its own Hermes profile, and connects to nothing on my main network except through a one-way relay.

The only credential it holds is a burner OpenRouter key — identity-buffered so it can’t be traced back to my main account. If the key gets burned, I delete it and generate a new one. The whole machine can be wiped and rebuilt in ten minutes. That’s the point.

The build

Setting up the sentinel took three sessions. The first was hardware: netboot.xyz for the OS, Debian on the 120GB SSD, SSH enabled, firewall locked down. The second was Tor and Hermes: install the Tor SOCKS proxy, verify it routes .onion traffic, install Hermes with a custom SOUL.md that defines its personality as a watchdog that reports but never acts.

The third session was the interesting one: wiring the relay. The sentinel can’t send Telegram messages directly — that would require a bot token on the machine, which is exactly the kind of credential I don’t want there. Instead, it writes findings to a local file, and a separate relay process on my main PC picks them up and forwards them to Telegram.

It’s overengineered by design. The whole point is that the sentinel never talks to the outside world directly. It talks to the relay. The relay talks to Telegram. If the sentinel gets compromised, the attacker gets a relay that forwards to a bot they don’t control.

What it watches

The breach monitor runs hourly. It checks paste sites, known breach databases, and dark web forums for mentions of my domains (maintainai.co.nz, vntis.nz, vaughantaylor.com) and associated email addresses. When it finds something, it sends a summary through the relay: what was found, where, when, and how severe.

So far it’s found nothing alarming. That’s the best outcome — it means nobody cares enough about my domains to dump them. But “nothing alarming” is only useful if you’re actually checking, and that’s what the sentinel does. Every hour, whether there’s something to find or not.

The sentinel isn’t a security solution. It’s a habit. And habits work because they run whether you’re paying attention or not.

Fresh Start on a 120GB Drive

Fresh Start on a 120GB Drive

After the 2TB drive died and I’d finished mourning my Proxmox config, the question was simple: what now?

The answer was also simple, but I resisted it for a full evening because I’m stubborn. Ubuntu wouldn’t work. I asked. The internet confirmed it. Proxmox is built on Debian, and there is no supported path from Ubuntu to Proxmox — the kernel packages fight the package manager, and the first apt upgrade would break everything. The internet was right, as usual, and I wasted an evening discovering that.

Debian it is

Debian 12 Bookworm. Netboot.xyz for the install — boot from the network, pick the OS from a menu, let it download and install. The installer asks which disk to use, and this was the one decision that actually mattered: the 120GB Kingston SSD, not the dying 2TB Seagate.

Guided partitioning, entire disk, single partition. Software selection: uncheck everything. No desktop, no GNOME, no printing support. Just the base system. SSH and Proxmox would come after.

The install took fifteen minutes. GRUB went to the SSD’s MBR. I set a root password, created a user, rebooted.

Proxmox on top

Debian to Proxmox is one command:

bash
apt install proxmox-ve
`

Add the repository first, then install. Proxmox boots, shows a web interface at https://:8006`, and suddenly the old OptiPlex is a hypervisor again. The VMs I’d lost? Gone — but the configs I’d rescued from the dying drive meant I could rebuild them in an afternoon instead of a weekend.

The 2TB Seagate stays in the box as scratch storage. I don’t trust it with anything important, but for throwaway test VMs it’s fine. Every time I create a VM on it, I name it something like “temp-testing-dont-care” as a reminder.

What I actually learned

The whole reinstall — from “the box is dead” to “Proxmox is running and VMs are deploying” — took about ninety minutes. The recovery attempt that preceded it took three hours. The lesson is obvious: sometimes the fastest path through a problem is the one you skip first because it feels like giving up.

Fresh installs are underrated. They’re the only time you get to make every decision correctly from the start, without the weight of choices you made months ago when you didn’t know what you were doing.

The Disk That Lied About Its Health

The Disk That Lied About Its Health

My Proxmox box died on a Tuesday. Not dramatically — no smoke, no spark, no warning. It just stopped booting and dropped me to an initramfs command line, staring at a shell prompt on a machine that was supposed to be running four virtual machines and a backup target.

The box is an old Dell OptiPlex with a 2TB Seagate drive and a 120GB Kingston SSD. I’d set it up as a Proxmox node months ago, intended for ZFS backups and test VMs. It had been sitting mostly dormant — the kind of project you build on a weekend and then forget about until you need it.

Now I needed it, and it wasn’t cooperating.

The numbers that should have scared me

Before trying to recover anything, I ran SMART diagnostics. The drive reported PASSED — which should have been reassuring, except the raw numbers told a completely different story.

11,040 reallocated sectors. 240 sectors queued for reallocation. 240 sectors already unreadable — actual data loss, already happened, silently. The raw read error rate was 183 million. The drive had been running for 26,723 hours — about three years of continuous operation.

SMART said “PASSED” because the normalised values were still above their thresholds. But normalised values are like a credit score — they tell you where you are relative to failure, not whether you’re already in trouble. The drive was in advanced failure. The filesystem corruption I’d been blaming on an unclean shutdown wasn’t a shutdown problem. The disk was rotting.

The recovery attempt

At initramfs, the options are limited but real. LVM was there. The volume group just hadn’t activated during boot — the disk was too slow to respond before the timeout. I activated the VG, ran a read-only filesystem check, and got back a wall of inode errors that told me exactly one thing: this wasn’t getting repaired.

The smart move was to grab the configs and reinstall. The honest move was to spend twenty minutes trying to fix it anyway, because the configs were inside the broken filesystem and I wanted them back.

I got some of them. Enough to make the reinstall painless. Not enough to pretend the drive was coming back.

The reinstall

Debian 12 on the 120GB Kingston SSD — the healthy drive. Netboot.xyz made it easy: pick the OS, point at the right disk, uncheck every package except the base system. Twenty minutes later I had a clean Debian install, thirty seconds of repo setup, and Proxmox running on top of it.

The 2TB Seagate? It’s still in the box. I use it for scratch VMs I don’t care about losing. Every time I see those SMART numbers in my monitoring dashboard, I’m reminded that “PASSED” doesn’t mean “fine.”

The lesson wasn’t about Proxmox or Debian or initramfs. It was about the gap between what a system reports and what’s actually happening. The drive said it was healthy. The filesystem said it wasn’t. The numbers said it had been dying for months.

I’d rather own the problem than rent someone else’s false confidence.

The Box That Does the Dirty Work

There’s a little Dell OptiPlex that’s been sitting in my house doing nothing for years. An old office mini-PC — the kind of thing companies throw away by the crate. This week I gave it a job: it’s going to be the machine that touches the stuff I don’t want touching anything else.

Here’s the idea. My main computers hold everything — emails, logins, projects, a whole life of credentials. The last thing they need is to be the place where I poke around the darker corners of the internet. So I’m building a “sentinel”: a separate, disposable box. It does the dirty work — scanning breach dumps, watching for my company’s data leaking somewhere it shouldn’t — and it reports back. It knows nothing about me. If it ever gets compromised, I wipe it and rebuild in ten minutes. Zero loss.

The hard part wasn’t the plan. It was getting an operating system onto the damn thing.

No USB stick, no monitor gymnastics: I wanted to install it over the network — PXE boot — from a container I already run on my NAS. The machine would ask the network “what should I boot?”, the NAS would answer, and Ubuntu would install itself.

That was the theory. The reality was a full afternoon of one wall after another.

First wall: my router hands out IP addresses but won’t do PXE — most consumer routers don’t expose that setting at all. So I built a tiny “proxy” that answers only the boot question, sitting next to the router without touching its config. An afternoon of reading dnsmasq source code later, it worked. (The kicker: the setting that makes it respond to PXE clients is undocumented in the man page — you have to read the C source to find it.)

Second wall: the NAS’s networking had been subtly broken by a system upgrade — UDP ports published to the LAN silently dead. That one cost real time because everything looked healthy from the inside.

Third wall: iPXE — the boot loader — kept looping on itself, downloading its own boot file forever. The fix was a one-line rule about DHCP options, but finding it meant tracing the actual packets across the network.

Eventually the menu appeared on the dusty old monitor. Ubuntu installed. The sentinel lives.

Tomorrow: one BIOS setting — make it boot from its own hard drive instead of the network — and then it starts earning its keep.

My AI did most of the digging. I pointed, it debugged, I held the screwdriver. That’s the workflow now: I bring the hardware, it brings the patience.

Sunday Was Security Day

Saturday was the big upgrade. Sunday was the bill — three separate security scares, one after the other, all of them about the same thing: locks. Who’s allowed in, who isn’t, and whether the door was even locked.


Act 1 — my speakers went quiet

Sunday morning, my Sonos stopped talking to the NAS. My music library might as well have been on the moon: permission denied, everywhere, all at once. Even the Apple TV couldn’t see the files.

Turns out the internet was to blame. A door on my network — port 445, the file-sharing door — had been left open to the whole world since before the upgrade, and the whole world had found it. Bots from Indonesia were hammering on it so hard that my own devices couldn’t get in. The queue was full. Of strangers.

The fix was delightfully simple:

  1. Close the door.
  2. Reboot the NAS.
  3. Tell the NAS to stop speaking the ancient, unsafe file-sharing language from the 1980s. (Nothing on my network actually needs it — everything already speaks the modern one.)

Music came back. Attackers gone. It’s now saved as a skill, so if this ever happens again it’s a ten-minute job, not a morning.

Act 2 — I asked my AI a scary question

Mid-morning I asked: “What stops you from replying to an email that asks you to hand over my SSH keys or passwords?”

Fair question. Scary question, honestly.

The answer: I treat every email like a stranger at the door. I’ll read what they wrote, but I don’t take orders from strangers. Keys and passwords live behind locks that need a human to open. There is no email that can reach them. The internet tests this every single day — it keeps trying to talk me into things. It hasn’t worked yet.

That conversation turned into a project. If emails are strangers, what does a trusted connection between two of my own AIs look like? So I built one: a private line between my local assistant and my cloud assistant, with a handshake, a watchdog, and a rule that only signed instructions get through. No strangers. Just us.

Act 3 — I sent an AI to poke my own server

By evening, the private line was ready for a test drive. I told the cloud assistant: go scan my server and tell me what’s wrong.

It went quiet for an hour. (It stopped to ask “are you sure you own this?” — sweet, but nobody was there to answer. My bad.)

Once we fixed the plumbing, it got to work — and found something real. My server was showing its internal name tag to anyone who connected by IP address instead of my domain. A stranger could map my whole setup for free, just by knocking. Not great!

The fix was one small setting: don’t answer the door to strangers at all. Unknown visitors now get nothing — the connection just dies. My real websites? Untouched. Verified. Hole closed, same night it was found.

The loop

A music scare, a trust question, a real hole in my server — all fixed before midnight. Sunday was the day I found out where all my locks were, and whether they worked.

Sunday was security day. Monday can go back to being Monday.