feat: add parallel issue implementation capability with worktrees
Add complete capability set for orchestrating parallel issue implementation with automated review cycles using git worktrees. Components: - worktrees skill: Git worktree patterns + bundled scripts for reliable operations - spawn-issues skill: Event-driven orchestrator (Haiku) for parallel workflow - issue-worker agent: Implements issues autonomously (Sonnet) - code-reviewer agent: Reviews PRs with quality checks (Haiku, read-only) - pr-fixer agent: Addresses review feedback automatically (Haiku) Workflow: /spawn-issues creates worktrees → spawns workers → reviews PRs → fixes feedback → iterates until approved → cleans up worktrees Scripts handle error-prone worktree operations. Orchestrator uses event-driven approach with task notifications for efficient parallel execution. Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
229
skills/worktrees/SKILL.md
Normal file
229
skills/worktrees/SKILL.md
Normal file
@@ -0,0 +1,229 @@
|
||||
---
|
||||
name: worktrees
|
||||
description: >
|
||||
Git worktree patterns for parallel development workflows. Use when managing
|
||||
multiple concurrent branches, implementing issues in parallel, or isolating
|
||||
work contexts.
|
||||
user-invocable: false
|
||||
---
|
||||
|
||||
# Git Worktrees
|
||||
|
||||
Patterns and scripts for managing git worktrees in parallel development workflows.
|
||||
|
||||
## What are Worktrees?
|
||||
|
||||
Git worktrees allow multiple working directories from a single repository. Each worktree can have a different branch checked out, enabling true parallel development.
|
||||
|
||||
**Use cases:**
|
||||
- Implementing multiple issues simultaneously
|
||||
- Isolated review environments for PRs
|
||||
- Switching contexts without stashing
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
**Directory structure:**
|
||||
```
|
||||
project/
|
||||
├── .git/ # Main repo
|
||||
├── src/ # Main working tree
|
||||
└── ../worktrees/ # Sibling worktrees directory
|
||||
├── project-issue-42/ # Issue implementation
|
||||
├── project-issue-43/ # Another issue
|
||||
└── project-review-55/ # PR review
|
||||
```
|
||||
|
||||
**Naming patterns:**
|
||||
- Issue work: `${REPO_NAME}-issue-${ISSUE_NUMBER}`
|
||||
- PR review: `${REPO_NAME}-review-${PR_NUMBER}`
|
||||
- Feature work: `${REPO_NAME}-feature-${FEATURE_NAME}`
|
||||
|
||||
**Why sibling directory:**
|
||||
- Keeps main repo clean
|
||||
- Easy to identify worktrees
|
||||
- Simple bulk operations
|
||||
- Works with tooling that scans parent directories
|
||||
|
||||
## Creating Worktrees
|
||||
|
||||
### For Issue Implementation
|
||||
|
||||
```bash
|
||||
REPO_PATH=$(pwd)
|
||||
REPO_NAME=$(basename "$REPO_PATH")
|
||||
WORKTREES_DIR="${REPO_PATH}/../worktrees"
|
||||
ISSUE_NUMBER=42
|
||||
|
||||
# Create worktrees directory
|
||||
mkdir -p "$WORKTREES_DIR"
|
||||
|
||||
# Fetch latest
|
||||
git fetch origin
|
||||
|
||||
# Get issue title for branch name
|
||||
ISSUE_TITLE=$(tea issues $ISSUE_NUMBER | grep -i "title" | head -1 | cut -d: -f2- | xargs)
|
||||
BRANCH_NAME="issue-${ISSUE_NUMBER}-$(echo "$ISSUE_TITLE" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd '[:alnum:]-' | cut -c1-50)"
|
||||
|
||||
# Create worktree with new branch from main
|
||||
git worktree add "${WORKTREES_DIR}/${REPO_NAME}-issue-${ISSUE_NUMBER}" \
|
||||
-b "$BRANCH_NAME" origin/main
|
||||
```
|
||||
|
||||
### For PR Review
|
||||
|
||||
```bash
|
||||
# For reviewing existing PR branch
|
||||
PR_NUMBER=55
|
||||
BRANCH_NAME="issue-42-feature-name" # Get from PR details
|
||||
|
||||
git fetch origin
|
||||
git worktree add "${WORKTREES_DIR}/${REPO_NAME}-review-${PR_NUMBER}" \
|
||||
"origin/${BRANCH_NAME}"
|
||||
```
|
||||
|
||||
## Bundled Scripts
|
||||
|
||||
Use bundled scripts for error-prone operations:
|
||||
|
||||
### Create Worktree
|
||||
|
||||
```bash
|
||||
# Usage: ./scripts/create-worktree.sh issue <issue-number>
|
||||
# Usage: ./scripts/create-worktree.sh review <pr-number> <branch-name>
|
||||
|
||||
./scripts/create-worktree.sh issue 42
|
||||
./scripts/create-worktree.sh review 55 issue-42-feature-name
|
||||
```
|
||||
|
||||
Returns worktree path on success.
|
||||
|
||||
### List Worktrees
|
||||
|
||||
```bash
|
||||
./scripts/list-worktrees.sh
|
||||
```
|
||||
|
||||
Shows all active worktrees with their branches.
|
||||
|
||||
### Cleanup Worktrees
|
||||
|
||||
```bash
|
||||
# Remove specific worktree
|
||||
./scripts/cleanup-worktrees.sh "${WORKTREES_DIR}/${REPO_NAME}-issue-42"
|
||||
|
||||
# Remove all worktrees in directory
|
||||
./scripts/cleanup-worktrees.sh "${WORKTREES_DIR}"
|
||||
|
||||
# Force remove even if dirty
|
||||
./scripts/cleanup-worktrees.sh --force "${WORKTREES_DIR}"
|
||||
```
|
||||
|
||||
## Patterns
|
||||
|
||||
### Pattern: Parallel Issue Implementation
|
||||
|
||||
**Orchestrator creates all worktrees upfront:**
|
||||
```bash
|
||||
for issue in 42 43 44; do
|
||||
worktree_path=$(./scripts/create-worktree.sh issue $issue)
|
||||
# Spawn worker with worktree_path
|
||||
done
|
||||
```
|
||||
|
||||
**Worker uses provided worktree:**
|
||||
```bash
|
||||
cd "$WORKTREE_PATH" # Provided by orchestrator
|
||||
# Do work
|
||||
git add -A && git commit -m "..."
|
||||
git push -u origin $(git branch --show-current)
|
||||
```
|
||||
|
||||
**Orchestrator cleans up after all complete:**
|
||||
```bash
|
||||
./scripts/cleanup-worktrees.sh "${WORKTREES_DIR}"
|
||||
```
|
||||
|
||||
### Pattern: Review in Isolation
|
||||
|
||||
**Create review worktree:**
|
||||
```bash
|
||||
worktree_path=$(./scripts/create-worktree.sh review $PR_NUMBER $BRANCH_NAME)
|
||||
cd "$worktree_path"
|
||||
git diff origin/main...HEAD # Review changes
|
||||
```
|
||||
|
||||
### Pattern: Error Recovery
|
||||
|
||||
**List stale worktrees:**
|
||||
```bash
|
||||
./scripts/list-worktrees.sh
|
||||
```
|
||||
|
||||
**Force cleanup:**
|
||||
```bash
|
||||
./scripts/cleanup-worktrees.sh --force "${WORKTREES_DIR}"
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
**Always provide worktree paths to agents:**
|
||||
- Orchestrator creates worktrees
|
||||
- Agents receive path as parameter
|
||||
- Agents work in provided path
|
||||
- Orchestrator handles cleanup
|
||||
|
||||
**Never nest cleanup:**
|
||||
- Only orchestrator cleans up
|
||||
- Agents never remove their own worktree
|
||||
- Cleanup happens after all work complete
|
||||
|
||||
**Track worktree paths:**
|
||||
```bash
|
||||
# In orchestrator
|
||||
declare -A worktrees
|
||||
worktrees[42]=$(./scripts/create-worktree.sh issue 42)
|
||||
worktrees[43]=$(./scripts/create-worktree.sh issue 43)
|
||||
|
||||
# Pass to agents
|
||||
spawn_agent --worktree="${worktrees[42]}"
|
||||
```
|
||||
|
||||
**Handle errors gracefully:**
|
||||
- Use scripts (they handle errors)
|
||||
- Always cleanup, even on failure
|
||||
- Force-remove if necessary
|
||||
|
||||
## Common Issues
|
||||
|
||||
**Worktree already exists:**
|
||||
```bash
|
||||
# Remove old worktree first
|
||||
./scripts/cleanup-worktrees.sh "${WORKTREES_DIR}/${REPO_NAME}-issue-42"
|
||||
|
||||
# Then create new one
|
||||
./scripts/create-worktree.sh issue 42
|
||||
```
|
||||
|
||||
**Branch already exists:**
|
||||
```bash
|
||||
# Delete branch if safe
|
||||
git branch -d issue-42-old-name
|
||||
|
||||
# Or force delete
|
||||
git branch -D issue-42-old-name
|
||||
```
|
||||
|
||||
**Stale worktrees after crash:**
|
||||
```bash
|
||||
# List and force remove
|
||||
./scripts/list-worktrees.sh
|
||||
./scripts/cleanup-worktrees.sh --force "${WORKTREES_DIR}"
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
- Keep worktrees short-lived (hours, not days)
|
||||
- Clean up regularly to avoid clutter
|
||||
- Use scripts for reliability
|
||||
- Let orchestrator manage lifecycle
|
||||
- Check `git worktree list` if unsure about state
|
||||
56
skills/worktrees/scripts/cleanup-worktrees.sh
Executable file
56
skills/worktrees/scripts/cleanup-worktrees.sh
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Clean up git worktrees
|
||||
#
|
||||
# Usage:
|
||||
# ./cleanup-worktrees.sh <path> # Remove specific worktree
|
||||
# ./cleanup-worktrees.sh <directory> # Remove all worktrees in directory
|
||||
# ./cleanup-worktrees.sh --force <path> # Force remove even if dirty
|
||||
|
||||
FORCE=false
|
||||
if [ "$1" = "--force" ]; then
|
||||
FORCE=true
|
||||
shift
|
||||
fi
|
||||
|
||||
TARGET="$1"
|
||||
REPO_PATH=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
||||
|
||||
cd "$REPO_PATH"
|
||||
|
||||
remove_worktree() {
|
||||
local worktree_path="$1"
|
||||
|
||||
if [ ! -d "$worktree_path" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$FORCE" = true ]; then
|
||||
git worktree remove "$worktree_path" --force 2>/dev/null || true
|
||||
else
|
||||
git worktree remove "$worktree_path" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if target is a directory containing multiple worktrees
|
||||
if [ -d "$TARGET" ]; then
|
||||
# Check if it's a worktree itself or a directory of worktrees
|
||||
if git worktree list | grep -q "$TARGET\$"; then
|
||||
# It's a single worktree
|
||||
remove_worktree "$TARGET"
|
||||
else
|
||||
# It's a directory, remove all worktrees inside
|
||||
for worktree in "$TARGET"/*; do
|
||||
if [ -d "$worktree" ]; then
|
||||
remove_worktree "$worktree"
|
||||
fi
|
||||
done
|
||||
|
||||
# Try to remove the directory if empty
|
||||
rmdir "$TARGET" 2>/dev/null || true
|
||||
fi
|
||||
else
|
||||
echo "Error: Path does not exist: $TARGET" >&2
|
||||
exit 1
|
||||
fi
|
||||
74
skills/worktrees/scripts/create-worktree.sh
Executable file
74
skills/worktrees/scripts/create-worktree.sh
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Create a git worktree for issue work or PR review
|
||||
#
|
||||
# Usage:
|
||||
# ./create-worktree.sh issue <issue-number>
|
||||
# ./create-worktree.sh review <pr-number> <branch-name>
|
||||
#
|
||||
# Returns: Absolute path to created worktree (stdout)
|
||||
|
||||
MODE="$1"
|
||||
REPO_PATH=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
||||
REPO_NAME=$(basename "$REPO_PATH")
|
||||
WORKTREES_DIR="${REPO_PATH}/../worktrees"
|
||||
|
||||
# Ensure worktrees directory exists
|
||||
mkdir -p "$WORKTREES_DIR"
|
||||
|
||||
# Fetch latest from origin
|
||||
cd "$REPO_PATH"
|
||||
git fetch origin >/dev/null 2>&1
|
||||
|
||||
case "$MODE" in
|
||||
issue)
|
||||
ISSUE_NUMBER="$2"
|
||||
WORKTREE_NAME="${REPO_NAME}-issue-${ISSUE_NUMBER}"
|
||||
WORKTREE_PATH="${WORKTREES_DIR}/${WORKTREE_NAME}"
|
||||
|
||||
# Get issue title for branch name
|
||||
ISSUE_TITLE=$(tea issues "$ISSUE_NUMBER" 2>/dev/null | grep -i "title" | head -1 | cut -d: -f2- | xargs || echo "untitled")
|
||||
|
||||
# Create safe branch name
|
||||
BRANCH_NAME="issue-${ISSUE_NUMBER}-$(echo "$ISSUE_TITLE" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd '[:alnum:]-' | cut -c1-50)"
|
||||
|
||||
# Remove worktree if it already exists
|
||||
if [ -d "$WORKTREE_PATH" ]; then
|
||||
git worktree remove "$WORKTREE_PATH" --force 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Delete branch if it exists
|
||||
git branch -D "$BRANCH_NAME" 2>/dev/null || true
|
||||
|
||||
# Create worktree with new branch from main
|
||||
git worktree add "$WORKTREE_PATH" -b "$BRANCH_NAME" origin/main >/dev/null 2>&1
|
||||
|
||||
echo "$WORKTREE_PATH"
|
||||
;;
|
||||
|
||||
review)
|
||||
PR_NUMBER="$2"
|
||||
BRANCH_NAME="$3"
|
||||
WORKTREE_NAME="${REPO_NAME}-review-${PR_NUMBER}"
|
||||
WORKTREE_PATH="${WORKTREES_DIR}/${WORKTREE_NAME}"
|
||||
|
||||
# Remove worktree if it already exists
|
||||
if [ -d "$WORKTREE_PATH" ]; then
|
||||
git worktree remove "$WORKTREE_PATH" --force 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Create worktree from existing branch
|
||||
git worktree add "$WORKTREE_PATH" "origin/${BRANCH_NAME}" >/dev/null 2>&1
|
||||
|
||||
echo "$WORKTREE_PATH"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Error: Invalid mode '$MODE'. Use 'issue' or 'review'" >&2
|
||||
echo "Usage:" >&2
|
||||
echo " $0 issue <issue-number>" >&2
|
||||
echo " $0 review <pr-number> <branch-name>" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
13
skills/worktrees/scripts/list-worktrees.sh
Executable file
13
skills/worktrees/scripts/list-worktrees.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# List all active git worktrees
|
||||
#
|
||||
# Usage:
|
||||
# ./list-worktrees.sh
|
||||
|
||||
REPO_PATH=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
||||
cd "$REPO_PATH"
|
||||
|
||||
echo "Active worktrees:"
|
||||
git worktree list
|
||||
Reference in New Issue
Block a user