Skip to content

[Bug]: Storage cleanup never removes a worktree that a thread shared with its own subagents #16472

Description

@Info-Cado

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. Enable any worktree rule under Settings → Storage (for example Delete unchanged worktrees).
  2. Start a thread in a new worktree, in a repository without ignored files other than node_modules/.
  3. In that thread, let the agent start a subagent: Claude's Agent tool, a Codex or Cursor native subagent, or T3's delegate_task.
  4. Let the turn finish, and leave the checkout clean with no open terminal.
  5. Wait for a cleanup sweep (startup, a settings change, or the hourly sweep).

Expected behavior

The subagent works inside its parent's checkout, so it should count as part of the parent thread. The checkout should be removed under the same rules as a thread without subagents, as long as the parent and all its subagents are idle.

Actual behavior

The worktree is never considered. Every subagent thread is stored with its parent's worktreePath. cleanWorktrees in apps/server/src/storageCleanup.ts (around lines 215-222) only keeps a worktree path that exactly one thread owns:

const groups = Map.groupBy(threads.filter((t) => t.worktreePath !== null), (t) => path.resolve(t.worktreePath!));
const candidates = [...groups.values()].flatMap((group) => (group.length === 1 ? [group[0]!] : []));

So a thread that ever used a subagent keeps its worktree forever, whatever its age, merge state or status. The re-check before removal (latest.length !== 1) has the same rule.

The single-owner rule came from V1 (#11598), where subagents were not app threads. In V2 they are app threads with lineage.relationshipToParent: "subagent", so the rule now also catches a thread's own subagents. The user guide says "shared worktrees ... prevent removal", which reads as sharing between separate threads, not a thread and its own subagents.

Note on delegated children: delegate_task children (creationSource: "mcp") can take messages later. When a turn starts on a thread whose checkout is missing, ProviderTurnStartService recreates it from that thread's own branch. Some delegated children on my machine have branch: null, so a fix should only count a child that cannot take messages (provider-native) or that has the parent's branch.

Impact

Major degradation or frequent failure

Version or commit

main @ 9bd1d80; T3 Code Nightly 0.0.46-nightly.20261005.2667

Environment

Linux, desktop AppImage. Claude and Codex providers.

Logs or stack traces

# One private project, 28 linked worktrees, read-only from statev2.sqlite.
# Every subagent thread with a worktree has the same worktreePath as its parent (133 of 133).
# Top-level thread status: 23 completed, 3 idle, 2 running.
# Of the 23 completed: 17 share the worktree with 1-12 subagent threads; 6 do not.
# Subagent kinds sharing a parent's worktree: provider-native and delegate_task (mcp).

On this machine, #15146 (the completed status gate) also blocks these 17 worktrees, so they are hidden twice. Fixing #15146 alone still leaves them, because they never pass the single-owner grouping. This issue is separate from #15146 and from #14742 (squash merges).

Workaround

Remove the worktree by hand. The branch stays, and the next turn on the thread recreates the checkout.

Investigated and written by Claude Opus 5.5 through T3 Code's Claude Code harness, on behalf of the reporter.

No activity

Activity on this issue will appear here.

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

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions