The repository carried 22 abandoned agent worktrees under .claude/worktrees/, left behind by past agent runs. They are gitignored, so they never reached a commit, but they stayed on disk and every unqualified repository-wide grep or find walked all 22 copies of the source tree. Measured before: 48,005 files under .claude/worktrees/, against 856 tracked in the repository. An unqualified search walked 56 times more files than the repository contains. The verification gate confirmed both safety conditions before removal: all 22 worktree-agent-* branch tips were already ancestors of main, and all 22 worktrees were clean (unmerged: 0, dirty: 0). Removal steps: - git worktree remove for each of the 22 worktrees (no rm -rf, so the registrations in .git/worktrees/ stay consistent) - git branch -d for each worktree-agent-* branch (lowercase -d, so an unmerged branch would block deletion instead of being force-deleted) - git worktree prune to clear administrative entries Measured after: 0 files under .claude/worktrees/, .claude/ shrank from 4.7 GB to 72 KB. The 856 tracked files are unchanged. HEAD is unchanged from before the removals. npm run ci exits 0. This ticket changes no tracked source file. The diff is this ticket file and the README row, because the work is entirely in gitignored paths and local branch refs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
5.9 KiB
RD-15 — Remove the 22 abandoned agent worktrees
Status: done Source: PLAN.md 2.1
Why
.claude/worktrees/ holds 22 abandoned agent checkouts totalling 4.7 GB, left behind by
past agent runs. They are gitignored (.gitignore:64), so they never reach a commit — but
they are on disk, and every unqualified repository-wide grep -r or find walks all 22
copies of the source tree.
That is a real tax on every future search, by a person or an agent, and it is larger than it looks. Measured:
| files | |
|---|---|
under .claude/worktrees/ |
48,005 |
| tracked in the actual repository | 856 |
An unqualified grep -r or find therefore walks 56× more files than the repository
contains. This ticket removes the cause; the git grep habit in the ticket-authoring rules
above handles the symptom.
Read first
.gitignore:64— confirms the directory is ignoredgit worktree list— 23 entries: the main working tree plus the 22 to remove- The verification block below. Run it before removing anything.
Decisions (pre-made, don't relitigate)
-
Use
git worktree remove, neverrm -rf. These are live registered git worktrees, not orphaned directories — each has a realworktree-agent-<hex>branch. Anrm -rfleaves 22 broken registrations behind in.git/worktrees/, which is worse than the disk usage. This correction was made while executing RD-01, where the original plan assumed they were plain directories. -
Delete each
worktree-agent-*branch too, after removing its worktree. A worktree removal does not delete the branch it had checked out, and 22 stale branches ingit branchare their own kind of noise. -
Finish with
git worktree pruneto clear any leftover administrative entries. -
Re-verify before removing, even though it was verified when this ticket was written. This is the only destructive ticket in the arc. Both gates passed at authoring time — all 22 branch tips are ancestors of
main(the RB-01..RB-33 arc was merged in637d500), and all 22 working trees are clean. If either gate fails for any worktree, stop and report it; do not use--force. -
This ticket changes no tracked file. Its commit contains only this ticket file and the README row. That is correct and expected — the work is entirely in gitignored paths and local branch refs.
Files
docs/project/readable-codebase/RD-15-remove-abandoned-worktrees.md(this file)docs/project/readable-codebase/README.md(the RD-15 row)
No source files. No configuration. .gitignore is already correct and must not change.
Steps
- Run the verification block below. Do not proceed unless it reports
unmerged: 0anddirty: 0. - For each worktree:
git worktree remove .claude/worktrees/<name>. - For each branch:
git branch -d worktree-agent-<hex>(lowercase-d, which refuses to delete anything unmerged — that is a second safety net, so do not use-D). git worktree prune.- Confirm
.claude/worktrees/is gone or empty. - Update this ticket's
Status:todoneand the README's RD-15 row todone. - Commit.
The verification gate — run this first
cd /home/eho/repos/atomic-design-poc
unmerged=0
for b in $(git branch --list 'worktree-agent-*' --format='%(refname:short)'); do
git merge-base --is-ancestor "$(git rev-parse "$b")" main 2>/dev/null \
|| { echo "UNMERGED: $b"; unmerged=$((unmerged+1)); }
done
dirty=0
for d in .claude/worktrees/agent-*; do
[ -d "$d" ] || continue
out=$(git -C "$d" status --porcelain 2>/dev/null | grep -v '^?? node_modules')
[ -z "$out" ] || { echo "DIRTY: $(basename "$d")"; dirty=$((dirty+1)); }
done
echo "unmerged: $unmerged dirty: $dirty"
Expected, and what was measured when this ticket was written: unmerged: 0 dirty: 0.
Acceptance criteria
git worktree list | wc -l # MUST be 1 (the main tree only)
git branch --list 'worktree-agent-*' | wc -l # MUST be 0
ls .claude/worktrees 2>/dev/null | wc -l # MUST be 0
du -sh .claude 2>/dev/null # was 4.7G under worktrees/
The repository is still intact — this is the check that matters after a destructive step:
git status --short # only the two doc files
git log --oneline -1 # HEAD unchanged from before your removals
npm run ci # exits 0
Show the payoff, since it is the reason for the ticket:
find .claude/worktrees -type f 2>/dev/null | wc -l # was 48005 -> MUST be 0
git ls-files | wc -l # unchanged: 856 tracked files
Verification
npm run ci. No source file changes, so --full is not required — but run plain ci anyway,
because removing worktrees touches .git administrative state and the point is to prove the
repository is unharmed.
Out of scope
.gitignore— already correct at line 64.- Any worktree that fails a gate. Report it instead (decision 4).
- Preventing future accumulation. Worth doing, but it is a change to how agents are launched, not a cleanup, and no ticket covers it yet. Note it as a follow-up.
Risks
- This is the arc's only destructive ticket. The two gates in decision 4 are what make it safe. Run them, and stop on any failure.
git branch -d, never-D. Lowercase refuses unmerged branches, which duplicates the first gate at the moment of deletion. If-drefuses a branch, that branch has commits not inmain— stop and report it.git worktree removerefuses a dirty worktree unless forced. Do not force. A refusal means the second gate missed something.- Do not delete
node_modulesanywhere else while cleaning up. The verification block deliberately ignores untrackednode_modulesinside a worktree, because that is build output, not work.