v1.33.2.0 fix: setup guards against Conductor worktree pollution of global install#1446
Merged
Conversation
…f the global install Add a guard before `ln -snf "$SOURCE_GSTACK_DIR" "$HOME/.claude/skills/gstack"` that detects whether the target already exists as a separate real directory. On macOS/BSD, `ln -snf SRC DST` does not replace a real DST — it creates DST/$(basename SRC) → SRC inside it. Running ./setup from each Conductor worktree of the gstack repo was leaking per-worktree child symlinks into the global install, which Claude Code then picked up as separate top-level skills. The guard uses `cd ... && pwd -P` to resolve the existing real dir and compare against the source (mirroring setup's own `SOURCE_GSTACK_DIR` resolution). When they differ, prints a four-line remediation hint naming both paths and exits the Claude registration branch cleanly. Binaries still build locally. The four other code paths through this branch are unchanged: fresh install, retarget an existing symlink, self-rerun where the existing dir resolves to the same source, and --local installs. Includes 8 tests covering static guard placement, `pwd -P` resolution, the remediation message, a behavioral reproduction of the BSD `ln -snf` child- symlink bug, and every branch of the guard (skip on real-dir-elsewhere, allow on fresh, allow on existing symlink, allow on self-rerun).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
E2E Evals: ✅ PASS0/0 tests passed | $0 total cost | 12 parallel runners
12x ubicloud-standard-2 (Docker: pre-baked toolchain + deps) | wall clock ≈ slowest suite |
Willardgmoore
added a commit
to Willardgmoore/gstack
that referenced
this pull request
May 12, 2026
Brings in: - v1.33.2.0: setup guard against Conductor worktree pollution (garrytan#1446) - v1.33.1.0: learnings token-OR query + task-shaped retrieval (garrytan#1442) - v1.33.0.0: /sync-gbrain memory stage batch-import refactor (garrytan#1432) VERSION stays at 1.34.0.0 (no collision — queue-aware check confirms). CHANGELOG: our [1.34.0.0] entry at top, three new main entries below. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
./setupno longer pollutes the global install when run from a Conductor worktree of the gstack repo itself. Six-line bash guard atsetupcatches the BSD/macOSln -snffootgun.When the destination is an existing real directory (your global git clone),
ln -snf SRC DSTdoes NOT replace it — it createsDST/$(basename SRC) → SRCinside the dir. Each Conductor worktree's./setuprun was leaking a child symlink (dublin-v1,wellington,santiago-v1, ...) into~/.claude/skills/gstack/, and Claude Code was picking each up as a separate top-level skill.The guard resolves the existing real dir via
pwd -P(mirroring howsetupalready resolvesSOURCE_GSTACK_DIR). If it differs from the source, skip Claude registration and print a remediation hint. Binaries still build locally.Test Coverage
8 tests in
test/setup-conductor-worktree.test.ts(27 expect calls):setupBEFOREln -snfpwd -Pto compare against$SOURCE_GSTACK_DIRln -snfchild-symlink bug in a tmpdirAll 8 pass. Tests: 1100 → 1108 (+8 new).
Pre-Landing Review
No issues found. Diff is 30 lines net in
setupplus the test file. All four pre-existing code paths through the affected branch are unchanged (fresh install, retarget existing symlink, self-rerun,--local).Eval Results
No prompt-related files changed — evals skipped.
Plan Completion
No plan file — this was an ad-hoc fix triggered by manual cleanup during
/gstack-upgrade.TODOS
No TODO items completed in this PR.
Test plan
bun test test/setup-conductor-worktree.test.ts— 8/8 passbun test(full free suite) — exit 0~/.claude/skills/gstack/in this session before fix./setupfrom a sibling Conductor worktree and confirm it prints the skip message without polluting the global install🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmithwith what you need.