All articles

The wait loop that waited for itself

4 min readAgents

nitrateX Building with agents

I asked Claude to render a film as soon as Codex finished building it. Codex finished at 18:35. At 19:17 I asked for a status update, and the render had not started. Nothing had crashed. The wait loop was watching itself.

What happened

The setup was ordinary. Codex was building the third version of a short Salvor film in the background. Claude's job was to wait until Codex finished, then render the frames and send me the video. To wait, Claude started a small background loop:

while pgrep -f "codex exec.*film3d" >/dev/null; do sleep 20; done
node render.cjs

pgrep -f searches the full command line of every running process and succeeds as long as something matches. The idea was simple: while Codex is running, keep sleeping, and render once it is gone.

Codex finished at 18:35 and wrote its final report. The loop kept sleeping. At 19:17 I asked "what's the status?", and Claude found the reason: the only processes still matching the pattern were its own wait loops.

Why it never ended

Claude's shell tool runs each command as bash -c "<the whole command>". So the loop's own command line contains the text codex exec.*film3d, and pgrep -f finds the loop itself. The loop waits for a process, and that process is the loop. It can never end.

The same mistake was in three wait loops that session. Two had looked fine only because I had moved on before they mattered. The third one held up the render for 45 minutes.

The fix is to wait for a specific process number instead of a pattern:

nohup codex exec ... > codex.log 2>&1 &
echo $! > codex.pid
while kill -0 "$(cat codex.pid)" 2>/dev/null; do sleep 20; done

$! is the process number of the job that was just started. kill -0 only checks whether that process is still alive and sends no signal. If a pattern search is unavoidable, the bracket trick (pgrep -f "[c]odex exec") stops the pattern from matching its own text.

"Isn't Salvor installed? Why does this happen?"

That was my reaction, and it is a fair question. I use Salvor so that agents don't repeat the same mistakes between sessions. It didn't help here, for two reasons.

  • Salvor lives inside a project. It works in repositories that have a .salvor folder: my game site, my blog, this site. The film was built in a plain working folder with no Salvor brain. There was no project memory to read.
  • Salvor prevents repeats, not first times. A learned failure is written down after the mistake happens and a human says yes to saving it. This was the first time this mistake happened, so there was nothing to read yet. That is how the tool works: the first mistake is the price of the lesson, and memory makes sure it is only paid once.

This is exactly where Salvor comes in. A mistake an agent makes once should never cost a second session. Salvor turns that first failure into a written rule in the repository, approved by a human, and every agent that opens the project reads it before it starts work: Claude Code tonight, Codex tomorrow, Gemini CLI the day after.

Writing it down

The lesson is now saved in two places. Claude's own long-term memory has a note: wait loops built with pgrep -f match themselves, so wait on a saved process number with kill -0. Every future session reads that note at the start. And this article is the public record of the same lesson, for anyone else whose agent waits in the background.

The film finally rendered once the loop was fixed. The process was the same as in the film itself: a failure, a saved lesson, and the next run that doesn't repeat it.

What I took from it

  • A silent wait looks like progress. Nothing crashed and nothing printed an error. Ask for status when a job takes longer than it should.
  • Check the tool's own footprint. A command that searches running processes can find itself, especially when it runs inside another shell.
  • Memory needs a first entry. A memory layer is only as good as what has been written into it. Saving the lesson right after the mistake is the step that makes it work.

Share on X

nitrateX Building with agents

Get new articles by email

Only when a new article is out. No ads. Details →