You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Automatic worktree cleanup never removes worktrees set up by t3.json's Setup Worktree action #13836
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
In pingdotgg/t3code, import the t3.json "Setup Worktree" action and start a thread in a new worktree. scripts/setup-worktree.ts symlinks $T3CODE_PROJECT_ROOT/.env into the worktree.
Settle or delete the thread, leaving the worktree clean (no working-tree changes).
Enable Settings → Storage → automatic worktree cleanup (for example "Delete worktrees with deleted threads", or an inactivity rule).
Wait for the next cleanup pass.
Expected behavior
The worktree is removed: it has no local changes, and everything in it can be recreated by running the setup action again.
Actual behavior
The worktree is kept. Before removing a worktree, storageCleanup.ts lists its gitignored files, and any entry other than node_modules/ blocks removal (L226–L239, repeated at L331–L342):
The .env symlink created by the setup action is gitignored, so it always appears in that list. In practice, every worktree the recommended setup action has run in is ineligible. Other repos hit the same thing with ordinary generated output; in ours, setup also leaves .husky/_/ (written by husky's prepare script during install) and .react-router/ (route type generation).
The guard exists for a good reason, since ignored files can hold secrets or local data. But its only exception is a hardcoded, Node-specific node_modules/. Two changes that could each land independently:
Treat symlinks pointing outside the worktree as safe to remove. Removing the worktree deletes the link, not its target. This is small and fixes this repo's own .env and infra/relay/.env links.
Replace the node_modules/ special case with a general rule for reproducible paths, so it works for any language (.venv/, target/, __pycache__/, .next/, vendor/, generated types, git hook shims). Two possible shapes:
Baseline after setup (preferred). T3 already runs runOnWorktreeCreate, so it can record the ignored-path listing right after setup succeeds. Anything in that baseline can be recreated by running setup again and shouldn't block removal. It needs no configuration, and paths created later still block: .t3/ dev userdata only appears once a dev server runs, so it stays protected. Worktrees created before this change have no baseline and keep today's behavior.
Declared in t3.json. For example cleanup.reproduciblePaths: ["node_modules/", ...], defaulting to today's ["node_modules/"]. More explicit and reviewable, but each repo has to maintain the list. This follows feat(settings): resolve t3.json inside the project settings resolver #12954's pattern of letting t3.json provide settings.
Impact
Minor bug or occasional failure
Version or commit
Read from source at 6530de0339d2 (v0.0.43-nightly.20260926.2282), not yet run on a nightly. The ignored-files listing was checked locally: a symlinked .env appears in it.
Environment
Linux, T3 Code desktop 0.0.42 (AppImage).
Workaround
Delete threads by hand and confirm "Delete the worktree too?", or run git worktree remove yourself.
Before submitting
Area
apps/server
Steps to reproduce
pingdotgg/t3code, import thet3.json"Setup Worktree" action and start a thread in a new worktree.scripts/setup-worktree.tssymlinks$T3CODE_PROJECT_ROOT/.envinto the worktree.Expected behavior
The worktree is removed: it has no local changes, and everything in it can be recreated by running the setup action again.
Actual behavior
The worktree is kept. Before removing a worktree,
storageCleanup.tslists its gitignored files, and any entry other thannode_modules/blocks removal (L226–L239, repeated at L331–L342):The
.envsymlink created by the setup action is gitignored, so it always appears in that list. In practice, every worktree the recommended setup action has run in is ineligible. Other repos hit the same thing with ordinary generated output; in ours, setup also leaves.husky/_/(written by husky'spreparescript during install) and.react-router/(route type generation).The guard exists for a good reason, since ignored files can hold secrets or local data. But its only exception is a hardcoded, Node-specific
node_modules/. Two changes that could each land independently:.envandinfra/relay/.envlinks.node_modules/special case with a general rule for reproducible paths, so it works for any language (.venv/,target/,__pycache__/,.next/,vendor/, generated types, git hook shims). Two possible shapes:runOnWorktreeCreate, so it can record the ignored-path listing right after setup succeeds. Anything in that baseline can be recreated by running setup again and shouldn't block removal. It needs no configuration, and paths created later still block:.t3/dev userdata only appears once a dev server runs, so it stays protected. Worktrees created before this change have no baseline and keep today's behavior.t3.json. For examplecleanup.reproduciblePaths: ["node_modules/", ...], defaulting to today's["node_modules/"]. More explicit and reviewable, but each repo has to maintain the list. This follows feat(settings): resolve t3.json inside the project settings resolver #12954's pattern of lettingt3.jsonprovide settings.Impact
Minor bug or occasional failure
Version or commit
Read from source at
6530de0339d2(v0.0.43-nightly.20260926.2282), not yet run on a nightly. The ignored-files listing was checked locally: a symlinked.envappears in it.Environment
Linux, T3 Code desktop 0.0.42 (AppImage).
Workaround
Delete threads by hand and confirm "Delete the worktree too?", or run
git worktree removeyourself.