On July 8th I retired the gateway my personal AI assistant ran on. Not casually: the way it failed became the first law of the system I replaced it with, written into that project's constitution, where I have read it a dozen times since.

Six weeks later I ran launchctl list for an unrelated reason and found it. Process 556. Started at boot, every boot, for forty-six days.

Nothing had broken, which is the part worth your attention. A retired service that crashes announces itself. One that simply runs costs a little memory, a little battery, an occasional API call, and never says anything at all.

Building with AI produces documentation at a rate that hand-written projects never did. My twenty-three repositories have vision files, roadmaps, status tables, a machine-readable tool registry. Most of it is accurate about what I meant. None of it can say what my computer is doing right now. And nobody writes down a stop: starting something produces a commit, while stopping usually produces silence.

So I stopped reading my notes and started asking the machine.

The audit 4 probes · 4 contradicted

What my docs said

The old gateway was retired on 8 July. Its replacement owns the message path now.

$ launchctl list | awk '$1 != "-" && $3 !~ /^com\.apple\./ {print $1, $3}'

What the machine said

Contradicted

556  ai.openclaw.gateway
572  ai.hermes.gateway

Running since boot for 46 days. The second one I had forgotten I ever installed.

What my docs said

Nightly jobs are healthy. Nothing has paged me.

$ launchctl list | awk '$2 > 0 && $3 !~ /^com\.apple\./ {print $2, $3}'

What the machine said

Contradicted

1  com.emre.fitness-coach.daily

Column two is the last exit status. A scheduled job that fails silently produces exactly as much output as one that never ran.

What my docs said

That side project is frozen. I stopped work on it this morning.

$ cat fleet/repos.json # whatever config your automation reads

What the machine said

Contradicted

"repos": { "hapnington": { ... } }

Still on the overnight agent's target list. Left alone it would have spent the night improving something I had just abandoned. An agent's target list is a status document that spends money when it is wrong.

What my docs said

Everything I build lives in a git repository with a remote.

$ for d in */; do [ -f "$d/package.json" ] || continue; [ -d "$d/.git" ] || echo "NO GIT: $d"; done

What the machine said

Contradicted

NO GIT: live-data/

An active piece of the stack I use. Not an unpushed branch. No repository at all.

AUDIT // LOCAL MACHINE // 2026-08-23 Four claims my documentation made, and what the machine said when each one was checked. The documents never changed while I did this. Only the questions did.

The drift no command could find

My portfolio file described one project as an active single-user live test. The user was my mom. I had even recorded its bottleneck: the speech API is too expensive for wider rollout.

She used it on day one, found out what it cost per minute to run, got scared of spending my money, and never opened it again. There had been no live test for weeks. The cost was never the real blocker either, because at five cents a minute I would run it all day.

Notice the asymmetry. The four drifts a command could find were cheap: idle memory, one wasted overnight cycle, a repository I got lucky with. The one that cost me weeks of building toward a user who was not there needed me to ask a person a direct question.

So run the human version of the audit too. Ask whoever you built the thing for whether they still use it, and be specific enough that politeness cannot answer for them.

What I changed

My workspace had a rule, written by me, saying not to infer a project's status from its folder location. It existed for a decent reason: folder locations kept going stale and lying about what was active. I had responded to unreliable folders by trusting the documents instead.

The better move, which took me until this week, is to make moving the folder be the status change. Active work sits at the root. Stopped work moves into an archive directory, keeping its history and its remote, available to harvest, dispatched to by nothing. Eight repositories moved that day.

This works for one reason, and it is not discipline. It is the only piece of state I cannot forget to update, because I have to move the folder to stop seeing it.

Run it on your own machine

# what is actually running
launchctl list | awk '$1 != "-" && $3 !~ /^com\.apple\./ {print $1, $3}'

# what is failing quietly (column 2 is the last exit status)
launchctl list | awk '$2 > 0 && $3 !~ /^com\.apple\./ {print $2, $3}'

# what is not under version control
for d in */; do
  [ -f "$d/package.json" ] || [ -f "$d/pyproject.toml" ] || continue
  [ -d "$d/.git" ] || echo "NO GIT: $d"
done

On Linux, systemctl --user list-units --state=running answers the first question. The third one your automation config has to answer for itself.

None of these findings were emergencies. That is exactly why they lasted. Systems you build for yourself fail politely, and politeness is what makes the failure durable.

I am building a voice-first assistant that dispatches work to the tools in that workspace, and writing it down as I go, including the parts that do not work yet. Every entry will carry at least one thing you can run on your own machine.