feat: add git-worktree lifecycle hooks (bootstrap, staleness, GC)#167
Merged
Conversation
Adopt and generalize the BlueStar monorepo's worktree lifecycle scripts as reusable plugin hooks. Claude Code creates session worktrees under .claude/worktrees/<name> with a bare `git worktree add` — no dependency install, no gitignored-env copy, and no cleanup after merge. The existing git-worktree skill only helps when a human runs its manager by hand; it does nothing for the worktrees the harness spins up itself (parallel/web sessions and isolation:"worktree" subagents). These hooks close that gap. - worktree-session.py (SessionStart/startup, ships): inside a .claude/worktrees/* tree, copies gitignored env files, runs an opt-in bootstrap command ($AGENTIC_WORKTREE_BOOTSTRAP_CMD), and emits a non-destructive staleness advisory when the branch is already merged (git cherry, so squash/rebase merges are caught). No-op everywhere else. - gc-worktrees.py (manual git post-merge hook, not auto-wired): destructive GC of merged worktrees + local branches, guarded by clean-tree, merged, and activity-window checks. Config is by environment variable (matching the sdd-cache precedent), so per-machine behavior can't ride a PR. Both fail open and always exit 0. Generalized from project-specific pnpm/Prisma/Node logic. Wired into plugin.json (Claude SessionStart) and documented in HOOKS.md with unittest coverage (tests/worktree_session_test.py). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <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.
What & why
Claude Code creates session worktrees under
.claude/worktrees/<name>with a baregit worktree add— no dependency install, no gitignored-env copy, and no cleanup after the branch merges. The plugin's existinggit-worktreeskill only helps when a human runs its manager script by hand; it does nothing for the worktrees the harness spins up itself (parallel/web sessions andisolation:"worktree"subagents). So every harness-created worktree currently starts unusable — missing.envfiles, uninstalled deps — and merged worktrees pile up locally forever.This PR adopts and generalizes the battle-tested worktree lifecycle scripts from the BlueStar monorepo (
Life-With-Data/bluestar-intel—setup-worktree.sh,check-stale-worktree.sh,gc-worktrees.sh) into two reusable, project-agnostic plugin hooks. Those scripts already solve the exact problem, but were hard-wired to that repo (pnpm, Prisma, Node 22,origin/main); this ports the reusable logic and strips the project specifics.Changes
scripts/worktree-session.py—SessionStart(startup), ships (wired intoplugin.json). No-op outside a.claude/worktrees/*tree (main tree, non-git dir, hand-made worktree → silent). Inside one it:.env,.env.local, one/two levels of*/.env*) from the main tree.$AGENTIC_WORKTREE_BOOTSTRAP_CMD, e.g."pnpm install"), gated on a marker so later sessions pay nothing.git cherryso squash/rebase merges (different SHAs) are caught, while a fresh commit-less branch or one with unmerged work stays silent.scripts/gc-worktrees.py— a destructive GC of merged worktrees + local branches for a gitpost-mergehook. Deliberately not auto-wired anywhere (every other plugin hook is a safety net; this deletes things). Guarded by clean-tree, fully-merged (git cherry), and activity-window (default 30 min) checks so a concurrent live session is never yanked. Install instructions in HOOKS.md.Design choices matching existing plugin conventions:
agentic-engineering.local.mdfrontmatter — mirrors thesdd-cacheprecedent: which command installs deps (and whether to bootstrap at all) is a per-machine choice that shouldn't ride a PR and flip behavior for every clone. This also keeps the scripts out of theconfig_registry.pysurface.exit 0— a broken bootstrap/GC hook can never block a session start or agit pull.SessionStartworktree event, so documented Claude-primary likeplan-tracker-guard.py.How to integrate / enable
worktree-session.pyships enabled and is inert until you're in a harness worktree. To auto-install deps there, exportAGENTIC_WORKTREE_BOOTSTRAP_CMD(e.g."pnpm install"). To enable GC, installgc-worktrees.pyas apost-mergegit hook (snippet in HOOKS.md).WORKTREE_BOOTSTRAP=0/WORKTREE_GC=0opt out.Tests
tests/worktree_session_test.py(6 cases) builds a real throwaway repo + harness-shaped worktree and pins: no-op fast paths, env-copy, missing-deps nudge, fresh-branch-not-stale, and merged-branch-stale (via a divergent-then-cherry-picked commit so the landed patch has a realistic squash-merge SHA).python3 -m unittest discover -s plugins/agentic-engineering/tests -p '*_test.py'→ 323 pass.bun test→ 491 pass,bun run docs:checkclean,bun run typecheckclean.Other opportunities surveyed (not included here)
While cataloging the source repos I also looked at
bluestar-intel'sralph-loopplugin (Stop-hook autonomous iteration loop) andagent-leverage'shookify.*.local.mddeclarative guard rules. Both overlap with capabilities the plugin/harness already provide (orchestrating-swarms//loop;block-no-verify) or depend on an external plugin, so I left them out to keep this PR focused on the one clear, self-contained gap. Happy to follow up on either if useful.🤖 Generated with Claude Code
Generated by Claude Code