Skip to content

afx cleanup cannot remove an orphaned builder worktree, so orphans accumulate forever #100

Description

@pseudoseed

Problem. A worktree under .builders/ whose global.db row is gone can be seen by every surface and removed by none.

Measured in codev-1455, 13 of them:

air-14  air-22  air-78  bugfix-1455  experiment-39  experiment-62
experiment-63  experiment-74  experiment-77  pir-12  pir-2  pir-4  spir-52
  • afx cleanup -p 78Builder not found for project: 78. Same for 62, 63, 74, 77.
  • git worktree remove is forbidden by CLAUDE.md's irreversible-acts rule: "Never destroy builder worktrees."
  • So there is no documented path that removes them, and nothing prunes them on its own.

Why they are visible. discoverBuilders finds worktrees Tower has no row for — deliberate, and useful for recovery. GET /v2/events therefore reports all 13 as builders with status: offline, parented to the workspace because a row-less worktree has no spawnedByArchitect.

That is honest — the directories are on disk. It is also permanent. The v2 site view will show 13 dead builders above 2 live ones, forever, and the ratio only gets worse.

How this already cost time. I filed #97 claiming FR-3 was unmet, having measured parentId at a moment when the workspace had zero live builders — so every row I saw was an orphan, and a missing DB row read as a missing feature. Re-measured with live builders present: 2 of 15 parent correctly to architect:<path>#uiv2. FR-3 works. The orphans produced a false bug report against a working feature, and they will do it again.

Scope of a fix. afx cleanup should be able to act on what it can see. Resolving a target by worktree directory when no project row exists — with the merged/unmerged check still applied, and the same confirmation any destructive path gets — closes the gap without weakening the rule that a human decides what is expendable.

Worth deciding separately: whether a row-less, session-less worktree should still be reported as a builder by discoverBuilders, or reported as something else. The current answer makes recovery possible, so it should not be changed casually.

Testing. Create a worktree under .builders/ with no global.db row. Assert afx cleanup can target it, that it refuses when the branch is unmerged without --force, and that GET /v2/events stops reporting it afterwards.

Note on the 13 in this workspace: 6 are merged and hold nothing but Agent Farm scaffolding (.builder-prompt.txt, .builder-role.md, .builder-start.sh, opencode.json, node_modules). 7 are unmerged. Nothing is decided about them here — that is the human's call.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/towerTower, afx, terminals, messagingbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions