Skip to content

fix(cleanup): keep a runtime-done session live while its process runs - #94

Merged
baldurpan merged 1 commit into
mainfrom
73-cleanup-can-remove-a-worktree-whose-agent-the
Oct 2, 2026
Merged

baldurpan merged 1 commit into
mainfrom
73-cleanup-can-remove-a-worktree-whose-agent-the

Conversation

@baldurpan

Copy link
Copy Markdown
Contributor

Closes #73

What changed

The agent runtime has been seen reporting state: "done" for a session whose pid was still running with its cwd in the worktree, so cleanup swept that worktree as ordinary stale work.

A runtime done is now believed only when no process is running behind it:

  • isProcessRunning(pid) (src/lib/cli.ts) probes with kill(pid, 0), which sends no signal. Only a positive safe integer is probed, because 0 and negative pids address process groups. ESRCH counts as not running. EPERM and any unrecognised error count as running, so an unclear answer fails safe.
  • withoutStaleDone (src/lib/agent.ts) drops a done whose pid is running. It does this when the runtime listing is read, the same safe-direction move joinSessions already makes for a session Herdr still shows. The predicates stay pure.
  • After that, the session is weighed like any other live one by the unchanged isSessionBlocking. An idle session still does not hold cleanup back (cleanup holds back a merged worktree whose agent session is only idle #89). Busy, unrecognised or missing status does. list --agents shows [waiting] (idle) or no marker instead of [done].
  • A done with no pid, an unusable pid or a pid that has exited still reads as finished, as before.

Docs updated in the same change: README.md, the list and cleanup command pages, skills/worktree/SKILL.md, context/executors.md. The context/verify.md test-count snapshot was corrected in passing.

Release note: .changeset/stale-pids-linger.md (patch).

Gates

  • Gate 1 (context/verify.md): pnpm check, pnpm typecheck and pnpm build all exit 0. pnpm test passes 987 tests and pnpm docs:test passes 68.
  • Gate 2 (reviewer subagent): PASS WITH NOTES. Nothing blocking.

The runtime has been seen reporting `state: "done"` for a session whose
pid was still running with its cwd in the worktree, so `cleanup` swept
the worktree as ordinary stale work. A `done` is now believed only when
no process is running behind it: where the reported pid is a positive
integer and `kill(pid, 0)` finds it, the `done` is dropped when the
runtime listing is read, and the session is weighed like any other live
one. Idle still does not hold `cleanup` back (#89); busy, unrecognised
or no status does. `list --agents` no longer marks such a session
`[done]`.

Closes #73

@craig-o-curtis craig-o-curtis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh ya, you betcha, this one's good to go.

Read through the whole diff, and it's a pretty tidy piece of work:

  • isProcessRunning only ever sends signal 0, won't touch a zero or a negative pid (so no process groups get poked, don'tcha know), and anything it can't make sense of counts as running. Fails safe, which is just what a fella wants from a thing that decides what gets deleted.
  • withoutStaleDone does its probing where the runtime listing is read, so the predicates stay pure, and it lines up real nice with what joinSessions already does for a session Herdr still shows.
  • Tests never look at the real process table (the default mock says nothing's running), so it won't go flaky on somebody's laptop. The cli.test.ts cases run against the real module through the vi.unmock that's already there.
  • Docs, the skill file, and a patch changeset all came along in the same change. ci and changeset are both green.

Couple things, not holding anything up:

  1. The session #73 actually caught was state: done, status: idle with a live pid. After this it's live but idle, so per #89 cleanup will still take that worktree. The PR body says so plainly, and I figure that's what you meant, but it might be worth a line on #73 so nobody's surprised later.
  2. If a finished session's pid gets handed out again to some other process, that session will read as live until the other process quits. It errs on the careful side, so that's fine by me.
  3. Heads up, #95 and #96 may bump the same test-count line in context/verify.md, so whichever goes in second could need a quick rebase.

I didn't run the suite on my own machine, just went by the diff and the green CI on this head.

Not too bad at all. Thanks for this!

@baldurpan
baldurpan merged commit 7e2f80e into main Oct 2, 2026
2 checks passed
@baldurpan
baldurpan deleted the 73-cleanup-can-remove-a-worktree-whose-agent-the branch October 2, 2026 21:48
baldurpan added a commit that referenced this pull request Oct 2, 2026
…ve-agent-as

Brings in #94 (#73): a runtime `done` session whose pid is still running
counts as live. Combined with this branch's waiting rule, such a session
is weighed by its status: idle is waiting and does not block, blocked is
waiting and blocks, busy or no status blocks and is not waiting, and one
whose process is gone stays done.

Conflicts in README.md and the list docs page are resolved to keep both
changes and describe the combination; the skill's `list --agents` comment
says the same. Adds a test pinning the non-idle side of the combination,
and corrects verify.md's test-count snapshot in passing.
@baldurpan baldurpan mentioned this pull request Oct 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cleanup can remove a worktree whose agent the runtime calls done while its process is alive

2 participants