At 7:48 on a Thursday morning, my phone buzzed. Multiple iMessages arrived, one after another, from Bubbles, our family AI. I asked it nothing. Nobody asked it anything. It just texted me. My first message to my other computer that morning was, verbatim: “why did Bubbles just send me a bunch of texts.”

A machine that you built does things unprompted. That causes a special flavor of dread. Your own house haunts you, and you are also the ghost.

The texts were legitimate

The investigation was less spooky than the symptom. The texts were legitimate. That was the uncomfortable part. A scheduled morning-brief job and a memory-maintenance job both fired at 7:48. Both did their work correctly. Then both delivered their output the way the system delivered everything: straight to my phone.

Nothing was broken. I built a system where “the cron job finished” and “your family texts you” arrive through the same door. They also wear the same clothes.

One loose thread

That morning became a cleanup of six and a half hours. I pulled one thread, and the thread exposed the sweater. At the time, Bubbles ran two agent frameworks side by side: an older one, and the newer gateway from my migration. The old framework still had five live launch agents on the machine. Their names included Julian, Ricky, and Lahey. If you have background processes that you cannot fully account for, name them after people you cannot fully account for.

The model backend also crashed in a loop. I downgraded it one version to stop a cascade of errors while I was in there.

iMessage is for humans

By the end of the day, all five launch agents of the old framework were unloaded. One runtime remained instead of two. And I wrote down the real keeper: a delivery rule, in a place that the system cannot forget. Automated output goes to a Discord channel. iMessage is for humans. If Bubbles texts my phone, a person asked it to relay something. A chatty scheduler at dawn is not a reason. An unprompted text from your own automation is a robocall that you paid to build.

Loud by default

That rule sounds obvious afterward. It is obvious. But nobody designs the notification architecture of a home AI on day one. You bolt on channels while you build. Each channel defaults to the loudest option, because loud is convenient during tests. Then one morning all your conveniences fire at the same time, at 7:48, and you find out what you built.

The texts stopped. The jobs still run. Now, when my phone buzzes, a person caused it. That is a feature. You must engineer it on purpose.