agent-watch — telling DONE, FAILED and STALL apart when you run codex exec in the background #42041
Replies: 2 comments
|
Nice separation of process state, recorded exit code, and a completion conclusion. One Codex-specific hardening looks worthwhile: current |
|
You are right, and I shipped it: v0.2.0 adds a I checked the current event stream and the terminal shapes are exactly as you described: So the watcher now takes the last last_event=$(tail -n 200 "$log" | grep -oE '"type":"turn\.(completed|failed)"' | tail -n 1)To your question — yes, a separate kind was the right call rather than changing ./worker_launch.sh api_task ./logs -- codex exec --json --skip-git-repo-check -C "$PWD" -m <MODEL> -s workspace-write "<brief>"
./worker_watch.sh api_task "$(cat logs/api_task.pid)" logs/api_task.log codex-json logs/api_task.exitYour point about the phrase appearing within the last 40 lines is the real hole — tail-only narrows it but never closes it, which is exactly why the structured path had to exist. Fixtures for the echoed-marker case and a truncated JSONL stream are the next thing I will add. Thanks for the sharp review: https://github.com/soul-sol/agent-watch/releases/tag/v0.2.0 |
Uh oh!
There was an error while loading. Please reload this page.
When I started running
codex execin the background for parallel work, the thing that cost me the most time wasn't a bad diff — it was not knowing whether a worker was done, dead, or just stuck.A background worker that silently stopped to ask for approval looks exactly like one that is still thinking. And a worker that crashed looks exactly like one that finished, if the only thing you check is that the process is gone.
So I wrote two small POSIX scripts that answer that question honestly, and open-sourced them (MIT): https://github.com/soul-sol/agent-watch
Four states, not two
STALLis the state I kept missing. The process is gone, the recorded exit code is 0, and yet the worker never actually concluded — it stopped to ask something, or died mid-thought. Treating that as "done" is how you lose an afternoon.Usage
And a whole wave at once:
Three details that turned out to matter
1. Record the exit code to a file. A background process's status is gone the moment you stop waiting on it, so
worker_launch.shwrites$?into<name>.exit. Without that, you cannot distinguish "finished cleanly" from "crashed" after the fact.2. Look for completion markers only in the log tail. codex prints a token-usage line when it finishes normally, which makes a great marker — until the worker reads a document that mentions that phrase and echoes it mid-run. Matching anywhere in the file gives false DONEs; matching in the last 40 lines does not. (I got burned by exactly this.)
3. Markers differ per tool. codex has one;
claude -pand gemini-family CLIs don't, so for those the honest test is "process exited AND the log tail contains a conclusion". The script takescodexorotheras an argument rather than pretending one rule fits all.Prompt-side half
The scripts only work if the worker is told to produce a terminal state. Two lines in the brief do most of the work:
Without the first line, codex will happily stop and wait for a human who isn't watching. That single sentence eliminated most of my stalls.
No dependencies beyond a POSIX shell and coreutils. Feedback and PRs welcome — especially on markers for CLIs I don't use.
All reactions