feat(hooks): add worktree_guard.py to block stacked agent worktrees (#485)#891
Conversation
…485) Claude Code's Agent tool with isolation="worktree" creates the new git worktree relative to the calling agent's cwd. When the calling agent is itself running inside a worktree the harness previously created, the new worktree lands at: .claude/worktrees/<parent>/.claude/worktrees/<child>/ Each sub-agent compounds the nesting. On Windows that pushes paths past MAX_PATH (260), breaking cargo build scripts (`cc-rs` for `bzip2-sys` / `libz-sys`) with `fatal error C1081: 'file name too long'`. The retry loop floods stderr with kilobyte PATH dumps that can overflow the session's context window (see #481/#482). PR #483 proposed the local mitigation but never merged. This adds it. The new `ci/hooks/worktree_guard.py` is a PreToolUse hook scoped to the `Agent` matcher. It denies any Agent call that combines `isolation: "worktree"` with a session cwd already inside `.claude/worktrees/<name>/`. The deny message tells the user how to proceed (re-spawn without isolation, or run from the main checkout) and points at #485 so they can track the upstream harness fix. Registered in `.claude/settings.json` with the same guarded-existence shape every other hook uses: `[ -f ci/hooks/worktree_guard.py ] && uv run --no-project --script ci/hooks/worktree_guard.py || exit 0` so orphan-branch worktrees that legitimately don't have the script cannot wedge the harness. 24 unit tests in `ci/hooks/test_worktree_guard.py` cover: - path normalization (Windows backslashes -> POSIX) - worktree-segment detection at any depth, including stacked cases - isolation-field parsing (case-insensitive, whitespace-tolerant) - session-cwd lookup precedence (payload > env > getcwd()) - main() end-to-end on the deny path AND the allow paths Once the upstream harness anchors worktree paths at the repo root (`git rev-parse --show-toplevel`), this hook can retire and #485 can close. Until then it shipping unblocks the user's nested-agent sessions on Windows. Closes #485
|
Warning Review limit reached
Next review available in: 26 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Problem
Claude Code's
Agenttool withisolation: "worktree"creates the new git worktree relative to the calling agent's cwd. When the calling agent is itself already running inside a worktree, the new worktree lands at.claude/worktrees/<parent>/.claude/worktrees/<child>/. Each sub-agent compounds the nesting; #485 reports a 4-deep stack at ~220 chars before any source file is appended. On Windows that pushes paths past MAX_PATH (260), breaks cargo build scripts (cc-rsforbzip2-sys/libz-sys) withfatal error C1081: 'file name too long', and the retry loop floods stderr with kilobyte PATH dumps that can overflow the session's context window (#481 / #482).PR #483 proposed the local mitigation but was closed without merging. This adds it back.
Fix
New
ci/hooks/worktree_guard.py— a PreToolUse hook scoped to theAgentmatcher. It denies any Agent call combiningisolation: "worktree"with a session cwd already inside.claude/worktrees/<name>/. The deny message tells the user how to proceed (re-spawn without isolation, or run from the main checkout) and points at #485 so they can track the upstream harness fix.Registered in
.claude/settings.jsonwith the same guarded-existence shape every other hook uses, so orphan-branch worktrees that legitimately don't have the script cannot wedge the harness.Tests
24 unit tests in
ci/hooks/test_worktree_guard.py:getcwd())main()end-to-end on the deny path AND the allow pathsSmoke test of the deny path: feeding the hook a payload with
isolation: "worktree"+ a.claude/worktrees/parentcwd emits the expectedhookSpecificOutput.permissionDecision: "deny"JSON with the actionable error message.Retirement
Once the upstream Claude Code harness anchors worktree paths at the repo root (
git rev-parse --show-toplevel), this hook can retire and #485 can close on the upstream fix. Until then, shipping it unblocks nested-agent sessions on Windows.Closes #485