Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save SebastianKlaiber/39f463f657ec88ca2fec8a7cca2fe7c4 to your computer and use it in GitHub Desktop.
Save SebastianKlaiber/39f463f657ec88ca2fec8a7cca2fe7c4 to your computer and use it in GitHub Desktop.
bmad-claude
#!/usr/bin/env bash
# bmad-claude - BMAD Method + Claude Worktree Integration
# Quickly switch between BMAD personas and development tasks with isolated environments
set -e
# Configuration
WORKTREE_BASE="${WORKTREE_BASE:-../$(basename $(pwd))}"
DEFAULT_BASE_BRANCH="${DEFAULT_BASE_BRANCH:-main}"
BMAD_AI_DIR="ai"
BMAD_STORIES_DIR="$BMAD_AI_DIR/stories"
BMAD_TEMPLATES_DIR="$BMAD_AI_DIR/templates"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'
# BMAD Personas (using functions instead of associative arrays for compatibility)
get_persona_description() {
case "$1" in
"ba") echo "Business Analyst - Market research, competitor analysis, feature brainstorming" ;;
"pm") echo "Product Manager - PRD creation, story breakdown, requirements gathering" ;;
"ux") echo "UX Expert - UI/UX design, wireframes, user journey mapping" ;;
"architect") echo "Technical Architect - System design, technology stack, architecture docs" ;;
"po") echo "Product Owner - Story management, backlog prioritization, acceptance criteria" ;;
"sm") echo "Scrum Master - Sprint planning, story creation, workflow management" ;;
"dev") echo "Developer - Code implementation, testing, story execution" ;;
*) echo "Unknown persona" ;;
esac
}
is_valid_persona() {
case "$1" in
"ba"|"pm"|"ux"|"architect"|"po"|"sm"|"dev") return 0 ;;
*) return 1 ;;
esac
}
# Helper functions
log_info() { echo -e "${BLUE}ℹ ${1}${NC}"; }
log_success() { echo -e "${GREEN}✓ ${1}${NC}"; }
log_warning() { echo -e "${YELLOW}⚠ ${1}${NC}"; }
log_error() { echo -e "${RED}✗ ${1}${NC}"; }
log_persona() { echo -e "${PURPLE}🎭 ${1}${NC}"; }
show_help() {
cat << EOF
BMAD + Claude Worktree - AI-Driven Development with Isolated Environments
BMAD PERSONAS:
ba Business Analyst - Market research, competitor analysis, feature brainstorming
pm Product Manager - PRD creation, story breakdown, requirements gathering
ux UX Expert - UI/UX design, wireframes, user journey mapping
architect Technical Architect - System design, technology stack, architecture docs
po Product Owner - Story management, backlog prioritization, acceptance criteria
sm Scrum Master - Sprint planning, story creation, workflow management
dev Developer - Code implementation, testing, story execution
USAGE:
./bmad-claude <persona> [task-name] [branch] # Start BMAD persona in worktree
./bmad-claude dev <story-name> [branch] # Development workflow
./bmad-claude story <story-id> # Work on specific story
./bmad-claude list # List all worktrees
./bmad-claude personas # Show available personas
./bmad-claude clean [task-name] # Remove worktree
./bmad-claude setup # Initialize BMAD structure
EXAMPLES:
./bmad-claude ba market-research # BA persona for market research
./bmad-claude pm user-auth-feature # PM persona for user auth PRD
./bmad-claude dev user-login # Dev persona for user login story
./bmad-claude story epic1.story3 # Work on specific story
./bmad-claude ux onboarding-flow # UX persona for onboarding
./bmad-claude architect microservices # Architect for system design
BMAD WORKFLOW:
1. ba → Market research & feature brainstorming
2. pm → Create PRD with story breakdown
3. ux → Design user experience & wireframes
4. architect → Technical architecture & stack decisions
5. po → Review stories & acceptance criteria
6. dev → Implement individual stories
ENVIRONMENT VARIABLES:
WORKTREE_BASE Base directory for worktrees
DEFAULT_BASE_BRANCH Default base branch (default: main)
EOF
}
show_personas() {
log_persona "Available BMAD Personas:"
echo
printf " ${CYAN}%-12s${NC} %s\n" "ba" "$(get_persona_description ba)"
printf " ${CYAN}%-12s${NC} %s\n" "pm" "$(get_persona_description pm)"
printf " ${CYAN}%-12s${NC} %s\n" "ux" "$(get_persona_description ux)"
printf " ${CYAN}%-12s${NC} %s\n" "architect" "$(get_persona_description architect)"
printf " ${CYAN}%-12s${NC} %s\n" "po" "$(get_persona_description po)"
printf " ${CYAN}%-12s${NC} %s\n" "sm" "$(get_persona_description sm)"
printf " ${CYAN}%-12s${NC} %s\n" "dev" "$(get_persona_description dev)"
echo
log_info "Use: ./bmad-claude <persona> <task-name> to start"
}
setup_bmad_structure() {
log_info "Setting up BMAD project structure..."
# Create BMAD directories
mkdir -p "$BMAD_AI_DIR"
mkdir -p "$BMAD_STORIES_DIR"
mkdir -p "$BMAD_TEMPLATES_DIR"
# Create story template if it doesn't exist
if [[ ! -f "$BMAD_TEMPLATES_DIR/story-template.md" ]]; then
cat > "$BMAD_TEMPLATES_DIR/story-template.md" << 'EOF'
# Story: {STORY_NAME}
**Status:** Draft | In Progress | Review | Done
**Epic:** {EPIC_NAME}
**Story Points:** {POINTS}
**Assignee:** DEV Agent
## User Story
As a {USER_TYPE}, I want {FUNCTIONALITY} so that {BENEFIT}.
## Acceptance Criteria
- [ ] Criterion 1
- [ ] Criterion 2
- [ ] Criterion 3
## Technical Notes
- Implementation approach
- Dependencies
- Technical considerations
## Definition of Done
- [ ] Code implemented
- [ ] Tests written and passing
- [ ] Code reviewed
- [ ] Documentation updated
- [ ] Story tested against acceptance criteria
## Progress Notes
<!-- DEV agent updates this section during implementation -->
EOF
log_success "Created story template"
fi
# Create .gitignore additions for BMAD
if [[ -f ".gitignore" ]]; then
if ! grep -q "# BMAD Method" .gitignore; then
cat >> .gitignore << EOF
# BMAD Method
ai/stories/*.md
ai/artifacts/
ai/temp/
EOF
log_success "Updated .gitignore for BMAD"
fi
fi
log_success "BMAD structure ready!"
}
get_bmad_prompt() {
local persona="$1"
local task_name="$2"
case $persona in
"ba")
echo "I'm your Business Analyst AI. I'll help you with market research, competitor analysis, and feature brainstorming for '$task_name'. Let's start by understanding your product vision and target market. What's your core product idea?"
;;
"pm")
echo "I'm your Product Manager AI. I'll help you create a comprehensive PRD for '$task_name'. I'll ask clarifying questions to understand requirements, user personas, and create detailed user stories. What's the product or feature you want to plan?"
;;
"ux")
echo "I'm your UX Expert AI. I'll help you design the user experience for '$task_name', including wireframes, user journeys, and interface design. I can help create prompts for V0 or similar UI generators. What's the user experience you want to design?"
;;
"architect")
echo "I'm your Technical Architect AI. I'll help you design the system architecture for '$task_name', including technology stack decisions, system design, and technical specifications. What's the technical challenge you're solving?"
;;
"po")
echo "I'm your Product Owner AI. I'll help you review and prioritize stories for '$task_name', ensure proper acceptance criteria, and manage the product backlog. What stories or features need review?"
;;
"sm")
echo "I'm your Scrum Master AI. I'll help you with sprint planning, story creation, and workflow management for '$task_name'. Let's organize your development process. What's your current sprint goal?"
;;
"dev")
echo "I'm your Developer AI. I'll help you implement '$task_name' following BMAD methodology. I work on one story at a time and will draft the story for your review before implementation. What story should I work on?"
;;
*)
echo "Starting Claude session for '$task_name'. How can I help you today?"
;;
esac
}
create_bmad_worktree() {
local persona="$1"
local task_name="$2"
local branch_name="${3:-$persona-$task_name}"
local base_branch="${4:-$DEFAULT_BASE_BRANCH}"
local worktree_dir="${WORKTREE_BASE}-${persona}-${task_name}"
# Validate persona
if [[ -n "$persona" ]] && ! is_valid_persona "$persona"; then
log_error "Unknown BMAD persona: $persona"
log_info "Available personas:"
show_personas
exit 1
fi
# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
log_error "Not in a Git repository"
exit 1
fi
# Check if worktree already exists
if [[ -d "$worktree_dir" ]]; then
log_warning "Worktree already exists: $worktree_dir"
read -p "Remove and recreate? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
git worktree remove "$worktree_dir" --force
else
log_info "Using existing worktree"
cd "$worktree_dir"
log_success "Switched to: $worktree_dir"
log_persona "BMAD Persona: $(get_persona_description "$persona")"
exec claude
exit 0
fi
fi
# Create new worktree
log_info "Creating BMAD worktree for $persona persona..."
log_persona "$(get_persona_description "$persona")"
# Check if branch exists
if git show-ref --verify --quiet "refs/heads/$branch_name"; then
log_info "Using existing branch: $branch_name"
git worktree add "$worktree_dir" "$branch_name"
else
log_info "Creating new branch: $branch_name (from $base_branch)"
git worktree add -b "$branch_name" "$worktree_dir" "$base_branch"
fi
log_success "Worktree created: $worktree_dir"
# Setup environment in worktree
cd "$worktree_dir"
# Setup BMAD structure if needed
if [[ ! -d "$BMAD_AI_DIR" ]]; then
setup_bmad_structure
fi
# Setup development environment based on project type
setup_development_environment
# Create persona-specific context
local prompt=$(get_bmad_prompt "$persona" "$task_name")
log_success "Ready! Starting Claude with $persona persona..."
log_info "Context: $prompt"
# Start Claude with persona context
exec claude
}
work_on_story() {
local story_id="$1"
local story_file="$BMAD_STORIES_DIR/story-${story_id}.md"
if [[ ! -f "$story_file" ]]; then
log_error "Story not found: $story_file"
log_info "Available stories:"
ls -la "$BMAD_STORIES_DIR"/*.md 2>/dev/null || log_warning "No stories found"
exit 1
fi
local task_name="story-${story_id}"
local worktree_dir="${WORKTREE_BASE}-dev-${task_name}"
create_bmad_worktree "dev" "$task_name" "dev-${story_id}"
}
setup_development_environment() {
local project_type=$(detect_project_type)
case $project_type in
"flutter")
log_info "Setting up Flutter environment..."
if command -v flutter &> /dev/null; then
flutter pub get
else
log_warning "Flutter not found in PATH"
fi
;;
"node")
if [[ -f "package.json" ]]; then
log_info "Installing Node.js dependencies..."
if command -v pnpm &> /dev/null; then
pnpm install
elif command -v yarn &> /dev/null; then
yarn install
else
npm install
fi
fi
;;
"python")
if [[ -f "requirements.txt" ]]; then
log_info "Setting up Python environment..."
if [[ ! -d "venv" ]]; then
python -m venv venv
fi
source venv/bin/activate
pip install -r requirements.txt
fi
;;
*)
log_info "Project auto-setup complete"
;;
esac
}
detect_project_type() {
if [[ -f "pubspec.yaml" ]]; then
echo "flutter"
elif [[ -f "package.json" ]]; then
echo "node"
elif [[ -f "requirements.txt" ]] || [[ -f "pyproject.toml" ]]; then
echo "python"
elif [[ -f "Cargo.toml" ]]; then
echo "rust"
elif [[ -f "go.mod" ]]; then
echo "go"
else
echo "unknown"
fi
}
list_worktrees() {
log_info "Current worktrees:"
git worktree list
echo
log_info "BMAD Stories:"
if [[ -d "$BMAD_STORIES_DIR" ]]; then
ls -la "$BMAD_STORIES_DIR"/*.md 2>/dev/null | while read -r line; do
echo " $line"
done
else
log_warning "No BMAD stories directory found. Run: ./bmad-claude setup"
fi
}
clean_worktree() {
local task_name="$1"
if [[ -z "$task_name" ]]; then
log_warning "Cleaning ALL BMAD worktrees..."
read -p "Are you sure? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Cancelled"
exit 0
fi
git worktree list --porcelain | grep "^worktree" | grep -v "$(pwd)" | while read -r line; do
worktree_path="${line#worktree }"
if [[ "$worktree_path" == *"${WORKTREE_BASE}"* ]]; then
log_info "Removing worktree: $worktree_path"
git worktree remove "$worktree_path" --force
fi
done
else
# Find and remove specific worktree
local found=false
git worktree list --porcelain | grep "^worktree" | while read -r line; do
worktree_path="${line#worktree }"
if [[ "$worktree_path" == *"$task_name"* ]]; then
log_info "Removing worktree: $worktree_path"
git worktree remove "$worktree_path" --force
found=true
break
fi
done
if [[ "$found" == false ]]; then
log_error "Worktree not found: $task_name"
exit 1
fi
fi
}
# Main script logic
case "${1:-}" in
"help"|"-h"|"--help")
show_help
;;
"personas"|"persona")
show_personas
;;
"setup")
setup_bmad_structure
;;
"list"|"ls")
list_worktrees
;;
"clean"|"rm")
clean_worktree "$2"
;;
"story")
if [[ -z "$2" ]]; then
log_error "Story ID required"
log_info "Usage: ./bmad-claude story <story-id>"
exit 1
fi
work_on_story "$2"
;;
"ba"|"pm"|"ux"|"architect"|"po"|"sm"|"dev")
if [[ -z "$2" ]]; then
log_error "Task name required for $1 persona"
log_info "Usage: ./bmad-claude $1 <task-name>"
exit 1
fi
create_bmad_worktree "$1" "$2" "$3" "$4"
;;
"")
log_error "Command required"
show_help
exit 1
;;
*)
log_error "Unknown command: $1"
show_help
exit 1
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment