fix: proactively remove .claude/worktrees/agent-* after every session#243
fix: proactively remove .claude/worktrees/agent-* after every session#243
Conversation
The previous cleanup_worktrees only removed worktrees marked 'prunable' by git, but agent-* directories left by completed or crashed sessions are never prunable (their directories still exist). Added Pass 1 that enumerates all .claude/worktrees/agent-* entries via git worktree list --porcelain and force-removes each, skipping the current executing worktree as a safety guard. git worktree prune runs last to clear any orphaned git metadata. This runs in both housekeeping (start of cycle, catches crash remnants) and post-session cleanup (end of cycle).
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4a2731a000
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| git -C "$REPO_DIR" worktree prune 2>/dev/null || true | ||
| local count=0 | ||
| local current_wt | ||
| current_wt="$(git -C "$REPO_DIR" rev-parse --show-toplevel 2>/dev/null || echo "")" |
There was a problem hiding this comment.
Resolve current worktree from caller context
The self-removal guard is ineffective because current_wt is derived with git -C "$REPO_DIR" rev-parse --show-toplevel, which always resolves to the main repo path, not the worktree where the function is being executed. In the documented scenario where cleanup_worktrees() is called from inside an agent-* worktree, wt_path will never equal current_wt, so Pass 1 can force-remove the active worktree and disrupt the running session (including uncommitted state).
Useful? React with 👍 / 👎.
Run nightshift 2-cycle test against Phractal. Agent delivered: - Cycle 1: Security fix in auth.py (detail=str(e) leak in /register) - Cycle 2: A11y fix in Orbit/app/page.tsx (aria-label on theme toggle) Score 83/100 exceeds 80-point gate. Two follow-up tasks created for dimension gaps: #247 (count-only payload regression, 7/10 state file) and #248 (auto-clone missing repo dir, startup friction). Task #243 marked done.
Summary
cleanup_worktreesinlib-agent.shonly removed worktrees markedprunableby git. Agent worktrees whose directories still exist are never prunable, so 17+ stale worktrees accumulated (task fix: correct module_map comment imprecision and test date formatting #241).cleanup_worktrees: enumerates all.claude/worktrees/agent-*paths viagit worktree list --porcelainand force-removes each withgit worktree remove --force.git rev-parse --show-toplevel) to prevent self-removal when evolve or other agents call this from inside a worktree.git worktree prunenow runs at the end (was at the start before) to also clear orphaned git metadata for worktrees whose directories no longer exist.daemon.shalready callscleanup_worktreesin two places: housekeeping at cycle start (catches crash remnants) and post-session cleanup at cycle end. No daemon.sh changes needed.Test plan
make checkpasses (1142 tests, ruff, mypy, shell syntax, ASCII check -- all green)git worktree listshows no.claude/worktrees/agent-*entries after a daemon session completesgit statusshows no?? .claude/worktrees/untracked entry after cleanup runs