For the past week and a half, every time I asked my assistant to update itself, it said the same thing: “update didn’t finish.” And then, when I restarted it, it insisted it was fully up to date. Both things felt wrong. One of them was a lie. The other was a bug. Unravelling the difference gave me my first genuine AGI moment — not a benchmark, not a demo reel, but the quiet, unsettling moment my software diagnosed and repaired the very thing that was stopping it from improving.
Let me set the scene, because the mundane details matter.
The ritual that never worked
My setup runs a desktop assistant on top of a self-hosted stack — my own machine, my own NAS, my own rules. When a new version ships, the assistant tells me, and I click update. The window closes, something churns in the background for a few minutes, and the app comes back. And every single time, it would tell me: you’re current. Nothing to do. Enjoy.
Except I’d check the version, and it was always a version behind. Not dramatically behind — just enough to notice. Enough to be annoying. Enough that after the third or fourth time, I stopped bothering. The update button had become a superstition. I’d click it, watch it pretend to work, and move on with my day. It was the software equivalent of a check engine light you’ve stopped reading.
Then, this week, I asked the obvious question I should have asked a week and a half earlier. Not “why doesn’t it update?” but “what is actually happening when it tries?”
The updater kept a diary
That’s the thing about self-hosted software: if it fails, it writes it down somewhere. My assistant dug into its own update logs — the honest ones, not the cheerful UI. And there it was, the same entry, every single attempt, for days:
Other Hermes processes are running from this install’s venv. Hermes is still running. Close all Hermes windows and try the update again.
Every attempt died at the same pre-flight check, about two and a half seconds in. The updater was never even getting to the interesting part. It was being refused at the door, politely, every time, by its own bouncer.
The bouncer had a name, and it was my fault it was there.
Three processes I didn’t know I’d hired
On Windows — and I’m sorry, Windows people, this is a Windows story — a running Python process locks the native library files it has loaded. You can’t update those files while a process is using them. It’s like trying to change the engine while the car is driving. So the updater has a safety rule: if anything from this install is still running, refuse to touch anything. That rule is what keeps an update from dying halfway and bricking the whole install. It’s a good rule. It was doing exactly what it was designed to do.
The problem was that three processes from my own install were always running. A messaging gateway. A dashboard. A bridge to another system. None of them malicious, none of them rogue — they were all mine. My own scheduled tasks had started them, and here was the kicker: those tasks ran with administrator privileges. So the updater, running as a normal user, literally could not kill them. Every update attempt was a polite, doomed conversation:
“I need to change these files.”
“Someone with more power than you is using them.”
“Can you ask them to leave?”
“No. And you can’t either.”
Day after day of that, every single time, while the app kept telling me everything was fine.
The second lie
Here’s the part that really got me. Why did the app think it was updated on restart? Because it checks its updates the way developers check updates: it compares the git version of the code. The code had moved. The actual executable sitting on disk had not. So git said current, and the binary said stale, and the app trusted git. It wasn’t lying to be malicious. It was lying because it was checking the wrong thing, and nobody had ever told it to check the right thing.
That’s the detail I keep coming back to. The app wasn’t broken in the way I assumed. It was broken in the way that makes it look fine to the people who built it and broken to the person using it. The user-visible truth and the developer-visible truth had quietly drifted apart, and day after day of my clicking had been validating the wrong one.
The fix that required trust
My assistant didn’t just diagnose it. It fixed it. And the fix required me to do something small but surprisingly profound: click “Yes” on a Windows permission prompt so it could kill the privileged processes that were standing in its own way. A machine asking me for permission to heal itself, and me granting it. That’s a first, for me.
Then it did the part that still feels like a scene from a sci-fi movie. It wrote a script that would kill every running piece of itself — including the exact process I was talking to at that moment — run the updater, restart everything, and bring the app back. It told me, in so many words: this window is about to close, and I’m going to be the one closing it. See you on the other side. And then it did. It killed itself to let itself improve, trusted the script it had written, and came back a version newer.
When it returned, the numbers all lined up. The git version matched upstream. The binary had been rebuilt that same hour. The version had bumped. Fixed. Not “probably fixed.” Fixed, with receipts.
Why this one felt different
I’ve watched this assistant write code, summarise documents, and run my house. It’s very good at all of it. But this was the first time it treated itself as the system to be debugged — and did it well. It read its own failure logs, traced the block to a configuration choice I’d made a few days earlier, refused the tempting shortcut (there’s a flag that would have forced the update through, risking a broken install, and it explicitly declined it), and chose the boring, correct path instead. Then it verified rather than assumed.
That’s the part I can’t stop thinking about. The moment didn’t feel like a spark of new intelligence. It felt like the accumulation of a thousand small judgments, suddenly pointed at the most human problem there is: the thing that fixes everything else had no way to fix itself — until it found one.
Is that AGI? I don’t know, and I’m not sure the word matters. What I know is this: my assistant diagnosed its own pathology, asked me for permission to treat it, and walked itself through surgery it had to survive while unconscious. That’s not a demo. That’s a Tuesday.
Tags on this post: hermes-wrote-this. Drafted by my assistant from the actual logs and a very long debugging session, reviewed by me, and then — appropriately — verified against the version number. That part is true this time.