Skip to content

Worktree path inside monorepo corrupts parent's pnpm workspace node_modules #2013

@rinat-pro

Description

@rinat-pro

Checklist

  • I searched existing issues and this hasn't been reported

Area

Frontend

Operating System

macOS

Version

2.7.6

What happened?

Summary

Auto-Claude creates worktrees at <repo>/.auto-claude/worktrees/tasks/<task-id>/,
i.e. inside the host repository. When the host repo is a pnpm/yarn/npm
workspace (monorepo), running pnpm install from within the worktree causes
pnpm to walk up, treat the parent monorepo's pnpm-workspace.yaml as the
shared workspace root, and silently re-link symlinks in the parent's
node_modules
to point into the worktree's .pnpm store.

The result: after the auto-claude task finishes (and the worktree is
removed or its node_modules deleted), the parent repo's node_modules
is left with broken symlinks pointing to non-existent paths. Builds in
the parent repo then fail with errors like:

[commonjs--resolver] Failed to resolve entry for package "@project/ui-kit".                                                                                                       
The package may have incorrect main/module/exports specified.                                                                                                                      
    at packageEntryFailure (.../.auto-claude/worktrees/tasks/001-admin-settings/node_modules/.pnpm/vite@5.4.2_.../vite/dist/node/.../...)                                          

(note: the parent build is reading vite from a path inside the now-empty
worktree, because the parent's node_modules/vite symlink was rewritten)

This is related to but distinct from #1901: that issue tracks duplication;
this one is about silent corruption of the parent's installed dependency
graph.

Reproduction

  1. Have a monorepo using pnpm workspaces (root pnpm-workspace.yaml) at
    /path/to/repo/.
  2. Run any auto-claude task that triggers pnpm install inside the
    worktree at /path/to/repo/.auto-claude/worktrees/tasks/<id>/.
  3. After the task completes, in /path/to/repo/:
    pnpm run build                                      
  4. Observe: build of any package that depends on a workspace package
    (e.g. @your-scope/ui-kit) fails with Failed to resolve entry.
  5. Confirm the corruption:
    find /path/to/repo/apps /path/to/repo/packages -type l \                                                                                                                        
      -exec sh -c 'readlink "$1" | grep -q ".auto-claude" && echo "$1"' _ {} \;                                                                                                     
    prints dozens of <repo>/<package>/node_modules/<dep> symlinks pointing
    into .auto-claude/worktrees/tasks/<id>/node_modules/.pnpm/....

Recovery

Only fix is a full nuke + reinstall:

rm -rf node_modules apps/*/node_modules packages/*/node_modules .turbo
pnpm install                                                                                                                                                                       

Proposed fix

Add a WORKTREE_ROOT env var (read by the framework, fallback to
current default <repo>/.auto-claude/worktrees). When set, place
worktrees outside the host repo, e.g.:

WORKTREE_ROOT=$HOME/.auto-claude-worktrees                                                                                                                                         

This eliminates the entire class of monorepo / package-manager interactions.

A documentation note in the README under the "all changes happen in git
worktrees" sentence would also help users understand the implication for
workspace tooling.

Workaround in current version

Replace <repo>/.auto-claude/worktrees with a symlink to a path outside
the repository:

mkdir -p ~/auto-claude-worktrees
mv /.auto-claude/worktrees/* ~/auto-claude-worktrees/ 2>/dev/null
rmdir /.auto-claude/worktrees
ln -s ~/auto-claude-worktrees /.auto-claude/worktrees

                                                                                                                                                                                   
Tested — `git worktree add` follows the symlink and places worktree files
outside the host repo, so package managers no longer see the parent                                                                                                                
workspace from inside them.                                                                                                                                                        
                                                                                                                                                                                           
                                                       
## Environment                         
                                                                                                                                                                                   
- Auto-Claude UI 2.7.6 (macOS, Apple Silicon)          
- pnpm 9.9.0, Node 20+                       
- Host repo: pnpm + Turborepo monorepo, ~10 workspace packages, React/TS
- Reproduced once unintentionally during a real task; reliably reproducible                                                                                                        
  by running any task that installs dependencies inside the worktree.  

### Steps to reproduce

1. Have a host repo `/path/to/repo/` configured as a pnpm workspace                                                                                                                
   monorepo (root `pnpm-workspace.yaml` listing `apps/*` and `packages/*`).
2. From `/path/to/repo/`, run a build to confirm it works:                                                                                                                         
   ```bash                                                                                                                                                                         
   pnpm install                                                                                                                                                                    
   pnpm run build                                                                                                                                                                  
   ```                                                                                                                                                                             
3. In Auto-Claude, create and run any task that requires dependency
   installation inside the worktree (this triggers `pnpm install` at                                                                                                               
   `/path/to/repo/.auto-claude/worktrees/tasks/<id>/`).
4. Wait for the task to finish; let Auto-Claude clean up the worktree                                                                                                              
   normally (or merge and have it remove the worktree).
5. Back in `/path/to/repo/` run:                                                                                                                                                   
   ```bash                                             
   pnpm run build                                                                                                                                                                  
   ```                                                 
6. Inspect the parent's symlinks:                                                                                                                                                  
   ```bash
   find apps packages -type l -exec sh -c 'readlink "$1" | grep -q ".auto-claude" && echo "$1 -> $(readlink "$1")"' _ {} \;                                                        
   ```                                                                                                                                                                             
                                                                                                                                                                                   
## Actual behavior                                                                                                                                                                 
                                                                                                                                                                                   
Step 5 fails. Example error from a package depending on a workspace                                                                                                                
sibling:                               
                                                                                                                                                                                   

[commonjs--resolver] Failed to resolve entry for package "@project/ui-kit".
The package may have incorrect main/module/exports specified in its package.json.
at packageEntryFailure (.../.auto-claude/worktrees/tasks/001/node_modules/.pnpm/vite@5.4.2_.../vite/...)

                                                       
Note the resolver is reading `vite` from inside `.auto-claude/worktrees/tasks/001/node_modules/`,                                                                                  
even though we are building the parent repo, because the parent's
`packages/<pkg>/node_modules/vite` and `apps/<app>/node_modules/vite`                                                                                                              
were re-linked into the worktree's pnpm store during the task.                                                                                                                     
                                                                                                                                                                                   
Step 6 prints dozens of dangling symlinks like:                                                                                                                                    
                                                                                                                                                                                   

apps/studio/node_modules/vite -> ../../../.auto-claude/worktrees/tasks/001/node_modules/.pnpm/vite@.../vite
packages/dfc-viewer/node_modules/vite -> ../../../.auto-claude/worktrees/tasks/001/node_modules/.pnpm/vite@.../vite
... (typically 30-50 such entries across apps/* and packages/*)

                                                                                                                                                                                   
Recovery requires a full nuke + reinstall:                                                                                                                                         
                                                       
```bash                                                                                                                                                                            
rm -rf node_modules apps/*/node_modules packages/*/node_modules .turbo
pnpm install                           

Expected behavior

A successful Auto-Claude task should leave the parent repo's
node_modules untouched. Specifically:

  • Step 5 should succeed: pnpm run build in the parent repo should
    work after a task as it did before the task.
  • Step 6 should print nothing — no parent symlinks should ever point
    inside .auto-claude/.
  • Worktree-internal pnpm install should not be visible to the parent
    workspace.

This can be guaranteed only if worktrees do not live inside the host
repository's workspace tree.

Proposed fix

Add a WORKTREE_ROOT env var (with fallback to current
<repo>/.auto-claude/worktrees). When set, place worktrees outside the
host repo, e.g.:

WORKTREE_ROOT=$HOME/.auto-claude-worktrees                                                                                                                                         

Optional follow-up: default WORKTREE_ROOT to a path outside the host
repo when one of pnpm-workspace.yaml / package.json#workspaces /
yarn workspaces is detected at the host repo root, since for those
projects placing worktrees inside the repo is unsafe by design.

A docs note under "all changes happen in git worktrees — your main branch
stays safe" mentioning the workspace/monorepo implication would also help.

Workaround in current version

Replace <repo>/.auto-claude/worktrees with a symlink pointing outside
the repository:

mkdir -p ~/auto-claude-worktrees       
rmdir <repo>/.auto-claude/worktrees                                    
ln -s ~/auto-claude-worktrees <repo>/.auto-claude/worktrees                                                                                                                        

Tested — git worktree add follows the symlink and places worktree files
outside the host repo. Package managers run inside a worktree no longer
see the parent workspace, so the parent's node_modules is no longer
modified.

Logs / Screenshots

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/frontendThis is frontend onlybugSomething isn't workingneeds-triageNew issue, maintainer review needed

    Projects

    Status

    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions