Great question, Kartik.
Foreman is a daemon, but the Claude session isn't something it watches from outside, the daemon process contains both, with the Claude run executing in-process through the Agent SDK. So foreman never infers that a run ended; it's holding the return value, and that value is always one of a short list: success, timeout, max turns, max budget, paused for a human (ask_human or the plan gate), cancelled, or error. As long as the process runs to completion, a decision is guaranteed. Whether the work was any good is a separate question, answered outside the transcript by the test exit code and the PR's CI status; a "success" with no commits and no PR is treated as a failure, not a delivery.
If it doesn't run to completion, note that "Claude crashed" and "foreman crashed" are the same event; there's no orphan to detect. Job state lives in MongoDB, so on restart foreman picks up anything that was mid-run, marks it failed and retries it; the worktree survives, so the retry just runs again in place. Retries are capped, and when they're exhausted the job goes dead and reports the failure on the ticket and in Slack. Then it's the human's call.
Kartik N V J K
AI Developer | Making AI reliable, trustworthy & accessible to everyone | Active community contributor
Running each agent in its own git worktree under a Foreman style daemon is the detail that makes this practical, because isolation is what lets a bad run be thrown away cheaply. Once the model itself is a commodity, the harness is where retries, checkpoints, and rollback actually live. How do you decide when a worktree run is finished rather than stuck?