Skip to content

feat(fleet): reclaim the checkouts whose work already shipped - #42

Merged
github-actions[bot] merged 1 commit into
masterfrom
feat/gc-merged-worktrees
Aug 26, 2026
Merged

feat(fleet): reclaim the checkouts whose work already shipped#42
github-actions[bot] merged 1 commit into
masterfrom
feat/gc-merged-worktrees

Conversation

@catomean

Copy link
Copy Markdown
Collaborator

The fleet creates a git worktree per agent session and removes none of them. Today there were 24 holding 5.2 GB — and every one belonged to a PR that had already merged. 23 were byte-for-byte clean.

Companion to fleet-stranded. That one asks "is any work trapped on this disk?"; this asks "is any checkout still here after its work shipped?" They turn on the same git distinction — an upstream that is configured but no longer resolves means the branch was pushed and its remote branch deleted. Reading that backwards is what made fleet-stranded report 24 merged PRs as stranded in #40.

The design is the refusal list

This deletes checkouts, so the only interesting failure is a false positive. Removable requires all four:

requires because otherwise
pushed the branch exists on exactly one disk
clean a worktree is where the unfinished edit lives
unused someone is working in it right now
MERGED CLOSED is abandoned, not gone; empty is gh failing, not consent

safe_to_remove() is pure, so all nine tests run with no repo, no network, no session. Each refusal is pinned separately — a combined "unsafe" fixture is exactly what hides one guard silently inverting. Includes "no argument means dry-run": if that inverts, the first person to run it bare loses every checkout.

Verified on the real fleet

23 removed, 5234 MB freed
kept: 1 never-pushed · 1 live session · 1 dirty tree · 1 superseded branch

Wired into CI, and exposed as fleet-gc alongside fleet-stranded.

🤖 Generated with Claude Code

The fleet creates a git worktree per agent session and removes none of them.
On 2026-08-26 there were 24, holding 5.2 GB, and every single one belonged to a
PR that had already merged — 23 were byte-for-byte clean. That is a recurring
manual sweep, so it becomes a script rather than something re-derived from
scratch each time the disk gets tight.

stranded-work.sh and this are the two halves of one question. That one asks "is
any work trapped on this disk?"; this asks "is any checkout still here after its
work shipped?" They turn on the same distinction, too: an upstream that is
configured but no longer resolves means the branch was pushed and its remote
branch deleted. Reading that backwards is what made stranded-work report 24
merged PRs as stranded yesterday.

Because this one deletes checkouts, the entire design is the refusal list. A
worktree is removable only if it was PUSHED, is CLEAN, is UNUSED, and GitHub
says MERGED — and each of those is a case where removing it would have
destroyed the only copy of something:

  no upstream    the branch exists on exactly one disk
  any dirt       a worktree is where the unfinished edit lives
  live session   someone is working in it right now
  not MERGED     CLOSED is abandoned, not gone; empty is gh failing, not consent

The predicate is pure so all nine tests run without a repo, a network call or a
session, including "no argument means dry-run" — if that ever inverts, the first
person to run it bare loses every checkout.

Verified on the real fleet: 23 removed, 5.2 GB freed, the four it refused being
one never-pushed branch, one live session, one dirty tree, and one superseded
local branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions
github-actions Bot merged commit b03e5ec into master Aug 26, 2026
1 check passed
@github-actions
github-actions Bot deleted the feat/gc-merged-worktrees branch August 26, 2026 08:46
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.

1 participant