Created
July 22, 2025 06:56
-
-
Save SebastianKlaiber/39f463f657ec88ca2fec8a7cca2fe7c4 to your computer and use it in GitHub Desktop.
bmad-claude
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
#!/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