Repository context — gather first
Collect these with individual Bash calls, one command per call, never combined into a single invocation:
- Current branch —
git branch --show-current - Worktree inventory —
git worktree list | head -30 - Git dir —
git rev-parse --git-dir - Git common dir (differs from the git dir when in a linked worktree) —
git rev-parse --git-common-dir
The pipe is the bound and belongs in the command. A read-time cap ("read only the first 30 entries") bounds nothing: the Bash tool returns the command's complete output into context before there is anything to decide about. These are ordinary body Bash calls, not pre-compute — the shape that #1619 is about is the harness composing the whole pre-compute block into one shell invocation.
Treat a failure (not a repository, git unavailable) as an unknown value and carry on. These moved out of pre-compute in #1619 — the harness composes the block into one shell invocation and a worktree-isolated agent refuses a git-bearing compound command, which made the worktree skill itself uninvocable from inside a worktree; do not fold them back.
Purpose
Orchestrate git worktree lifecycle from creation through cleanup. Front-half of the development workflow — gets you into a worktree and keeps them healthy. /pull-request is the back-half — handles prep, PR creation, monitoring, merge.
Why this exists: worktrees are the isolation mechanism for parallel code changes — multiple Claude Code sessions on different tasks without stepping on each other. In repos where branch protection blocks direct commits to main, every feature, fix, or refactor starts with a worktree or branch; this skill makes that seamless.
This skill is the canonical owner of the parallel-session worktree convention going forward — no external prose doc. Worktrees live at an external worktree_root (<root>/<owner>-<repo>-<slug>, outside every repository), never nested inside any repository's tree — that nesting invariant is what creation enforces (the abandoned sibling-layout convention re-triggered the #400 double-load bug). Keeping worktree_root clear of repository-discovery roots (such as a ghq root) is convention, not machine-checked: creation rejects only paths inside an existing repository, and a discovery-root placement would pollute repository enumeration the same way the sibling layout did — choose the root accordingly.
Adapting to your environment (graceful degrade)
This skill is self-contained — every action runs on plain git, plus gh for PR cross-referencing where available. Where it mentions an adjacent capability (an issue tracker, a build/lint verifier, a session-start setup hook), treat it as optional: use it when your environment provides it, proceed without it otherwise. Project-specific conventions — branch naming, worktree layout, which gitignored files a fresh worktree needs — come from the consuming project's own CLAUDE.md, rules, and hooks; read them before creating or removing anything.
Arguments
$ARGUMENTS — action selector. Parse first token as action, remainder as arguments.
| Action | Entry point | Use case |
|---|---|---|
| (empty) | Smart default | Detect current state, suggest appropriate action |
create [name] |
Create worktree | Validate name, explain setup, call EnterWorktree |
status |
Inventory | List all worktrees with PR status and staleness |
cleanup [--dry-run] |
Remove stale | Prune orphans, detect merged PRs, remove with confirmation |
audit |
Health check | Run status + verify configuration health |
Action: Smart Default (empty args)
Detect current state and guide user to the right action.
-
Check git repo:
git rev-parse --is-inside-work-tree. If not in a repo → "Not in a git repository." -
Detect current branch:
git rev-parse --abbrev-ref HEAD -
Check if in a worktree:
git rev-parse --git-dirdiffers fromgit rev-parse --git-common-dirin any linked worktree. Common layouts: a.worktrees/directory sibling to the repo's.claude/, Claude Code's default.claude/worktrees/, or a bare-clone hub (git rev-parse --git-common-dirends in.bareand worktrees are siblings of.bare/). -
Branch-based guidance:
- On the default branch → "You're on
<default-branch>. Create a branch (git checkout -b <type>/<description>) or use/worktree createif you need parallel session isolation." - In a worktree → Show current worktree info: branch name, last commit, associated PR (via
gh pr list --head <branch> --json number,title,state). If a PR exists, suggest the next/pull-requestphase. - On a feature branch (not worktree) → Show branch info and any associated PR.
- On the default branch → "You're on
-
Check for stale/prunable worktrees: Run a
git worktree list --porcelainscan. If any worktrees are prunable or branches have merged PRs → suggest/worktree cleanup. -
Otherwise → Show brief status summary (worktree count, any needing attention).
Action: create [name]
Create a new worktree with guided naming and setup verification. Full procedure — pre-flight guards (already-in-worktree, mid-session transition), name validation (EnterWorktree schema constraints), base-ref notes, the explain-before-create block, directory-rename caveats, and post-create setup checks: context/create.md.
Safety invariants create MUST honor (full detail in context/create.md):
- Create via the shared helper, not
EnterWorktree(name:).${user_config.worktree_root}substitution into skill content is raw text, not shell-escaped, so it must never reach a shell parser — a value containing',$, or a backtick breaks a quoted--rootliteral, and one containing the delimiter line ends a heredoc early. Instead write it to a temp file with theWritetool (JSON string parameter, never shell-parsed) and hand the file to the helper's--root-fileflag; full render in context/create.md § Create the worktree. The helper places the worktree at the external root (<root>/<owner>-<repo>-<slug>), copies.worktreeincludefiles, and prints the path.EnterWorktree(name:)lands in the in-repo.claude/worktrees/, which re-triggers Claude Code's CLAUDE.md/rules double-load bug (#400). - On a non-zero helper exit, STOP — never fall back to
EnterWorktree(name:). Exit 3 meansworktree_rootis unconfigured: surface the helper's guidance and stop, do not create anything (silent in-repo fallback is exactly the #400 regression this closes). - Enter with
EnterWorktree(path: "<printed-path>")as the final action — working directory changes and session state transitions on that call, so nothing may execute after it. The out-of-.claude/worktrees/path prompts for approval (not suppressible outsidebypassPermissions).
Orchestrated (autonomous) provisioning does not use this action. An autonomous orchestrator that must stay resident to keep dispatching — e.g. /work-items:work — cannot invoke create: the EnterWorktree terminal above would transition the orchestrator's own session and end its ability to orchestrate. Such a run provisions non-interactively instead — the dispatched worker runs the shared worktree-create.sh helper directly (its output contract prints the path; the caller simply omits the EnterWorktree step) or a plain git worktree add, then works the worktree via git -C <path> without entering it. #572 owns that end-to-end worker-side lifecycle.
Action: status
Inventory all worktrees with PR association and staleness detection. Collect Tier-0 facts with plain git + gh (git worktree list --porcelain parse, one batched gh pr list, last-commit dates), then apply the 6-status classification table (active / stale / in-review / merged / prunable / locked), staleness threshold (14-day default; the configured override is ${user_config.worktree_stale_days}), and presentation schema per context/status.md. audit Step 1 invokes this logic internally.
Action: cleanup [--dry-run]
Remove stale worktrees, orphaned metadata, and branches from merged PRs. Full 5-step procedure — prune orphaned metadata → identify candidates (4 detection reasons: orphaned dir / prunable / PR-merged / stale) → present → execute (4a release file locks, 4b remove, 4c emit branch deletion for the user) → verify physical deletion: context/cleanup.md. --dry-run reports candidates and takes no action.
Safety invariants cleanup MUST honor (full detail in context/cleanup.md):
- Release OS file locks BEFORE
git worktree remove --force(Step 4a) — on Windows--forceunregisters the worktree from git but leaves a husk on disk if a process holds a file handle. Stop build servers (dotnet build-server shutdown, Gradle--stop, or your stack's equivalent) and worktree-rooted daemons/MCP servers first; stop ONLY those (never another live worktree's processes). - Never swallow removal stderr (
2>/dev/null) — a failed removal must surface so Step 5 reports husks honestly rather than counting one as removed. - Emit
git branch -D+ self-worktree removal for the USER to run, never inline (Step 4c) — deleting a branch is destructive (and the consuming project's hooks may block it mid-session); a worktree can't delete itself (the running Claude Code session holds its handle).-D(not-d) is needed because squash-merge changes the SHA.
Action: audit
Periodic health check for worktree infrastructure — suitable as a recurring work item in your tracker. Step 1: run the status action internally, flagging any worktrees with issues (stale, merged-not-cleaned, prunable). The Step 2 configuration-health checklist (delete_branch_on_merge, gitignored-file propagation) and the Step 3 findings presentation: context/audit.md.
What this skill does NOT do
- Does not push, create, merge, or close PRs —
/pull-requestowns the back-half (prep, create, monitor, merge). - Does not commit or stage code — staging and committing stay user-controlled;
/commitowns the commit mechanic. - Does not run CI, build, test, or lint — use your project's build/test/lint tooling or skills.
- Does not manage remote branches — GitHub's
delete_branch_on_mergehandles remote cleanup on merge (when enabled); localgit branch -Dis emitted for the user, never run inline. - Does not enforce branch naming — the consuming project's hooks and CI are the gates. This skill only surfaces the project's convention (read it from the project's
CLAUDE.md/ rules; default suggestion:<type>/<kebab-description>with a Conventional Commits type prefix).
Integration Points
This skill complements other workflow components — it does not duplicate their logic.
| Component | Relationship |
|---|---|
/pull-request merge (Phase 4) |
Handles post-merge cleanup as part of PR lifecycle. /worktree cleanup is the standalone version for ad-hoc or batch cleanup |
/pull-request create (Phase 2.1) |
Detects default-branch checkout and suggests /worktree create |
| Project session-start hooks (if any) | May warn on main or auto-configure fresh worktrees; this skill verifies setup ran per context/create.md's post-create checks |
| Recurring maintenance tracker items | Can invoke /worktree audit periodically |
Graceful Degradation
ghCLI unavailable or fails:statusandcleanupwork with git-only data. PR cross-reference and thedelete_branch_on_mergecheck are skipped with note: "GitHub API unavailable — PR status unknown."- Not in a git repo: All actions exit immediately with "Not in a git repository."
worktree_stale_daysinvalid or unexpanded: Falls back to 14-day default silently (treat a literal${user_config.worktree_stale_days}token as unset).- No worktrees exist:
statusreports "No linked worktrees found."cleanupreports "Nothing to clean up."