Extracts the fail-closed worktree branch-check guard into a single canonical fragment (get-shit-done/references/worktree-branch-check.md) and repoints all five sites at it; orchestrator embeds the runnable block at dispatch. All safety invariants preserved; adversarially reviewed; full matrix green. Closes #588.
2.6 KiB
Worktree Path Safety
Guards for executor agents running inside Claude Code worktrees. Three checks must run before any staging, Edit, or Write operation in worktree mode.
Worktree branch check (run once at spawn-time)
The spawn-time HEAD/base guard now lives in the canonical fragment
get-shit-done/references/worktree-branch-check.md, which the orchestrator embeds directly
into your prompt at dispatch. Run that block FIRST, before any reset/checkout or staging.
If your prompt contains a <worktree_branch_check> embed instruction rather than the block itself, complete that read-and-embed step before any reset/checkout or staging.
cwd-drift sentinel — step 0a (#3097)
A prior Bash call may have cd'd out of the worktree into the main repo. When
that happens [ -f .git ] is false (main repo's .git is a directory), silently
skipping all worktree guards. The sentinel captures the spawn-time toplevel and
detects drift before every commit.
if [ -f .git ]; then # we are in a worktree
WT_GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
case "$WT_GIT_DIR" in
*.git/worktrees/*)
SENTINEL="$WT_GIT_DIR/gsd-spawn-toplevel"
[ ! -f "$SENTINEL" ] && git rev-parse --show-toplevel > "$SENTINEL" 2>/dev/null
EXPECTED_TL=$(cat "$SENTINEL" 2>/dev/null)
ACTUAL_TL=$(git rev-parse --show-toplevel 2>/dev/null)
if [ -n "$EXPECTED_TL" ] && [ "$ACTUAL_TL" != "$EXPECTED_TL" ]; then
echo "FATAL: cwd drifted from spawn-time worktree root (#3097)" >&2
echo " Spawn-time: $EXPECTED_TL" >&2
echo " Current: $ACTUAL_TL" >&2
echo "RECOVERY: cd \"$EXPECTED_TL\" before staging, then re-run this commit." >&2
exit 1
fi
;;
esac
fi
Absolute-path guard — step 0b (#3099)
Edit/Write calls using absolute paths constructed from the orchestrator's pwd
(main repo root) will resolve to the main repo, not the worktree. Writes land in
the wrong directory; git commit from the worktree sees a clean tree and the work
is silently lost.
Before any Edit or Write using an absolute path:
WT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
# Fail fast if ABS_PATH resolves outside the worktree
if [[ "$ABS_PATH" != "$WT_ROOT"* ]]; then
echo "WARNING: $ABS_PATH is outside the worktree ($WT_ROOT)" >&2
echo "Use a relative path or recompute the absolute path from WT_ROOT." >&2
fi
Prefer relative paths for all Edit/Write operations. When an absolute path is
unavoidable, always derive it from git rev-parse --show-toplevel run inside the
worktree — never from pwd captured in the orchestrator context.