What's wrong with this entry?
Claude Code now automatically detects and releases worktree locks that were left behind by processes that have since exited, rather than leaving them to block future operations.
- On each sweep, the worktree registry is scanned for locks whose lock-reason string encodes a PID. Only reasons matching the pattern
^claude (?:agent|session) .{1,255} \(pid (\d{1,10})(?: start .{1,255})?\)$(and no longer than 512 characters) are eligible; lock reasons that don't follow this format are skipped entirely. - If
process.kill(pid, 0)returnsESRCH(no such process), the lock is treated as stale and released. Any other result (process exists, or PID ≤ 1 / non-integer) is treated as live and left alone. - The per-sweep cap is 50 releases: once 50 stale locks have been released in one sweep, the remainder are logged and deferred to a later sweep with the message
"releaseStaleClaudeWorktreeLocks: per-sweep cap of 50 reached; remaining stale locks will be reconciled on later sweeps". - Worktrees with no
.gitfile at their path are also skipped, preventing cleanup of already-removed trees. - The registry is re-read at release time (double-checked before each individual unlock) to prevent TOCTOU races where another process might have claimed the lock between the scan and the release.
- The current session's own worktree is always excluded from cleanup (matched by resolved real path).
- When at least one lock is released, a
tengu_worktree_stale_lock_releasedtelemetry event is emitted with{ attempted: N }, and a debug log reports the count:"releaseStaleClaudeWorktreeLocks: attempted release of N stale liveness lock(s)".
Cleanup function (search for "releaseStaleClaudeWorktreeLocks: attempted release of") and PID check logic (search for "stale liveness lock(s) in"); cap constant ($zc = 50); lock-reason regex (Mtt)
Strings lifted out of the shipped bundle, so the claim above can be checked against them.