Summary
apm compile --clean treats AGENTS.md files belonging to other git worktrees as orphans and deletes them, when those worktrees live in a directory under the repository root (a common layout, e.g. <repo>/.worktrees/<branch>/).
In our repo the deleted files are tracked in git, so every affected worktree silently gains uncommitted deletions:
+ Removed .worktrees/fix-tsconfig-jsonc/e2e/AGENTS.md
+ Removed .worktrees/fix-tsconfig-jsonc/packages/cli/AGENTS.md
+ Removed .worktrees/fix-tsconfig-jsonc/e2e/fixtures/application/AGENTS.md
$ cd .worktrees/fix-tsconfig-jsonc && git status --short
D e2e/AGENTS.md
D e2e/fixtures/application/AGENTS.md
D packages/cli/AGENTS.md
This is not a one-off: with several worktrees checked out in parallel, any apm compile --clean from the main working tree wipes all of them, and an agent working inside one can commit the deletions without noticing.
Cause
src/apm_cli/compilation/distributed_compiler.py:817 (identical in v0.26.0 and v0.27.0):
for agents_file in self.base_dir.rglob("AGENTS.md"):
relative_path = agents_file.resolve().relative_to(self.base_dir.resolve())
skip_dirs = {".git", ".apm", "node_modules", "__pycache__", ".pytest_cache", "apm_modules"}
if any(part in skip_dirs for part in relative_path.parts):
continue
A nested worktree is an independent checkout with its own generated AGENTS.md files carrying the APM marker, so they pass the marker gate and are removed.
There is currently no way to opt out:
skip_dirs is a hardcoded literal.
.gitignore is not consulted (our .worktrees entry has no effect).
apm.yml has no corresponding key, apm compile has no corresponding flag, and there is no env var.
DistributedAgentsCompiler.__init__ does take exclude_patterns, but the CLI never passes it, and it feeds the project-structure analyzer (same file, :123) rather than the orphan scan.
Suggested fix
A git worktree root is easy to detect: it contains a .git file (a gitdir pointer), not a .git directory. Skipping any directory whose root has that would fix this without new configuration:
def _is_nested_worktree(path: Path) -> bool:
return (path / ".git").is_file()
…and prune such directories during the walk. Alternatively (or additionally), honour an excludes: key in apm.yml for the orphan scan.
Environment
- apm 0.26.0 (also verified the code is unchanged in v0.27.0), macOS arm64, PyInstaller build from the GitHub release
- Layout: main working tree at
<repo>, additional git worktree add targets under <repo>/.worktrees/<slug>
Workaround
Move worktrees outside the repository root so base_dir.rglob(...) cannot reach them, and keep --clean out of any automatically-run script (we had it in package.json prepare, which meant every bun install triggered it).
Summary
apm compile --cleantreatsAGENTS.mdfiles belonging to other git worktrees as orphans and deletes them, when those worktrees live in a directory under the repository root (a common layout, e.g.<repo>/.worktrees/<branch>/).In our repo the deleted files are tracked in git, so every affected worktree silently gains uncommitted deletions:
This is not a one-off: with several worktrees checked out in parallel, any
apm compile --cleanfrom the main working tree wipes all of them, and an agent working inside one can commit the deletions without noticing.Cause
src/apm_cli/compilation/distributed_compiler.py:817(identical in v0.26.0 and v0.27.0):A nested worktree is an independent checkout with its own generated
AGENTS.mdfiles carrying the APM marker, so they pass the marker gate and are removed.There is currently no way to opt out:
skip_dirsis a hardcoded literal..gitignoreis not consulted (our.worktreesentry has no effect).apm.ymlhas no corresponding key,apm compilehas no corresponding flag, and there is no env var.DistributedAgentsCompiler.__init__does takeexclude_patterns, but the CLI never passes it, and it feeds the project-structure analyzer (same file, :123) rather than the orphan scan.Suggested fix
A git worktree root is easy to detect: it contains a
.gitfile (a gitdir pointer), not a.gitdirectory. Skipping any directory whose root has that would fix this without new configuration:…and prune such directories during the walk. Alternatively (or additionally), honour an
excludes:key inapm.ymlfor the orphan scan.Environment
<repo>, additionalgit worktree addtargets under<repo>/.worktrees/<slug>Workaround
Move worktrees outside the repository root so
base_dir.rglob(...)cannot reach them, and keep--cleanout of any automatically-run script (we had it inpackage.jsonprepare, which meant everybun installtriggered it).