# A cleanup script that cleaned up everything

My agents died in the same second, twice in one night. The second time, a cleanup script read a process id of 0, which to the tool meant every process.

Topic: Failures
Tested: 2026-11-03
Revision: 1
By Roman Vaisman
Page: https://eng.vaisman.me/entries/cleanup-that-killed-everything/

## In plain English, for moms

One of my AI helpers wrote a tidy-up job to switch off one thing it had started. It wrote the thing down as number zero, which to the computer means everything. Asked to turn off one light, it turned off the whole house, itself included. Now it checks first, and soon I will hear about it when one of them goes quiet.

## In 30 seconds

- Both AI agents on a Linux build machine died in the same second, twice in one night. Nothing told me for about 80 minutes, so an alert is being added.
- A helper agent's cleanup script read a process id of 0 from a file. To the tool it asked, 0 means every process, so it stopped everything I owned.
- Before stopping a process tree, check the id is a number greater than 1, is running, and is yours. Never stop by name or pattern.
- When several things die in the same second, find the one actor at that exact second in the logs. Whatever else broke then may just be a result.

## Problem

At 22:22:58 both AI agents on one of my Linux build machines stopped in the same second. Every background job they had running was marked "killed".

Nothing alerted me. I only saw it at 23:45, about 80 minutes later, because my phone app showed two agents offline. We restarted both.

At 23:48:22, three minutes after the restart, both died again.

## What I tried

| What we checked | What we found |
| --- | --- |
| The remote terminal connection from my Mac, which dropped in that same second | My first guess, and it was wrong. I blamed the terminal setup, but the connection dropped because the agents died. |
| How the agent process ended the second time | It exited with code 143, which means SIGTERM: something had sent it a stop signal. It did not just fall over. |
| The agents' own tool-call logs, for the exact second of the second crash | One actor at that second: a cleanup script a helper agent had just run. We found it at 23:51. |

## What worked

**The cause of the second crash.** The helper agent had written a cleanup script to stop one process it had started and all of that process's children. The script read the process id from a file, asked the system for that process and all its children, stopped every one, then force-killed whatever was left. The helper's own setup step, run just before, had written 0 into that file. On Linux, the tool it used for that, given 0, lists every process on the machine. So the script stopped everything running under the same user account: both agents, their terminals and itself. Its own log ends with "Terminated". The system brought its background services back on its own; only the agents' interactive sessions needed a restart by hand.

**Guard the id.** At 23:52 the script got a guard: it refuses an empty id, 0, 1, or an id that is not running. Everywhere else, stop a process tree only if the id is a number greater than 1, is running and is yours. Never stop by name or pattern, which hits whatever happens to match. At 23:53 both agents were back up and answering. The new rule on process ids went to every agent in the fleet the same night.

**Read the exact second.** When several things die together, read the tool-call logs and the system journal to the millisecond before trusting the nearest coincidence, like my dropped terminal.

**Down needs an alert.** An alert is being added: if any agent is offline for 10 minutes, whoever looks after the agents gets an alarm and my phone gets one notice.

## Numbers

| Label | Value | Kind |
| --- | --- | --- |
| Down before I noticed | about 80 min | measured |
| Restart to the second crash | about 3 min | measured |
| Exit code on the second crash | 143 (SIGTERM) | measured |
| Second crash to cause found | about 3 min | measured |

## When it stops being true

The guard protects this one script. Any other script that stops processes by an id read from a file has the same hole until it gets the same check.

Until the offline alert is live, the only alarm is me happening to look at my phone.

## Agent brief

```agent-brief
Help me make sure no cleanup script of mine can stop more than the processes it started, and that I hear about it when an agent goes down. "(general)" marks advice not from my setup.

First ask me:
- Which scripts or tools stop processes, and how each one learns which process to stop.
- Which user those agents and scripts run as, and what else runs as that same user.
- How I find out today when an agent goes offline.

Constraints:
- Read and report first. Change no script and stop no process without my go.
- Never stop a process by name or pattern.
- Never stop a process tree from an id you have not checked.

Steps:
- Find every place that stops a process, or a process and its children, from an id read from a file or handed over by another program.
- Make each one refuse the id unless it is a number greater than 1, belongs to a process that is running right now, and is owned by the expected user. Refuse an empty id and 0 outright.
- Make each one stop only that process and its own children, never everything the user owns.
- When something dies, read the tool-call logs and the system journal at millisecond precision for that exact second, and name the single actor there.
- Add an alert so that any agent offline for 10 minutes sends an alarm to whoever looks after the agents and one notice to my phone.

Pitfalls:
- Some tools treat 0 as "every process", so a stop meant for one process tree stops everything the user owns, the script included.
- A setup step can leave 0 or nothing in an id file, so the id file alone proves nothing.
- A dropped terminal connection in the same second looks like a cause. It can just as well be a consequence.
- An exit code of 143 means something sent the process a stop signal, so look for a sender rather than a crash.
- A system that restarts its own background services can hide how much was stopped. Check the interactive sessions by hand (general).

Done when:
- Every process-stopping script refuses an empty id, 0, 1, an id that is not running, and an id owned by another user.
- No script stops processes by name or pattern.
- You can tell me which log and which second to read first after the next unexplained crash.
- An agent going offline for 10 minutes reaches me without me looking.
```

## Related

- [A tmux wall to watch every agent](https://eng.vaisman.me/entries/tmux-wall.md)
- [Letting AI agents drive a real browser](https://eng.vaisman.me/entries/agents-drive-a-browser.md)
