#!/bin/bash # # BMAD Epic Execute - Design Phase Module # # Provides pre-implementation design phase functionality to catch # architectural issues early before coding begins. # # Usage: Sourced by epic-execute.sh # # ============================================================================= # Design Phase Variables # ============================================================================= # Stores the last design output for passing to dev phase LAST_DESIGN="" # ============================================================================= # Design Phase Functions # ============================================================================= # Execute pre-implementation design phase # Generates an implementation plan before coding begins # Arguments: # $1 - story_file path execute_design_phase() { local story_file="$1" local story_id=$(basename "$story_file" .md) # Reset last design LAST_DESIGN="" log ">>> DESIGN PHASE: $story_id" # Story is inlined (small, bounded, and the planner needs it in full) local story_contents=$(cat "$story_file") # Locate the architecture file but pass it by PATH, not embedded contents. # architecture.md is the main unbounded size risk in this prompt. local arch_file="" for search_path in "$PROJECT_ROOT/docs/architecture.md" "$PROJECT_ROOT/docs/architecture/architecture.md" "$PROJECT_ROOT/architecture.md"; do if [ -f "$search_path" ]; then arch_file="$search_path" break fi done # Load previous decisions for context, bounded to the last 20KB # (matches the dev phase; the decision log grows across the epic). local decision_context="" if type get_decision_log_context >/dev/null 2>&1; then decision_context=$(get_decision_log_context) local dec_size dec_size=$(get_byte_size "$decision_context") if [ "$dec_size" -gt 20000 ]; then decision_context=$(printf '%s' "$decision_context" | tail -c 20000) [ "$VERBOSE" = true ] && log_warn "Design: decision log truncated to last 20KB" fi fi local design_prompt="You are a senior developer planning the implementation of a story. ## Your Task Create an implementation plan for: $story_id Do NOT write any code yet. Output only your design plan. ### CRITICAL RULES - Plan thoroughly BEFORE any implementation - Consider existing patterns in the codebase - Map each acceptance criterion to specific files/functions - Identify potential risks and dependencies ## Story to Plan **Story Path:** $story_file **Story ID:** $story_id $story_contents ## Architecture Reference **Read the architecture document at:** ${arch_file:-"(none found)"} ## Previous Decisions in This Epic $decision_context ## Exploration First, explore the codebase to understand existing patterns and conventions before planning. Use the repository's own structure and language to guide you (e.g. inspect the relevant source directories, find files similar to what this story touches, and follow existing patterns rather than introducing new ones). ## Required Output Output your implementation plan in this exact format: \`\`\` DESIGN START story_id: $story_id files_to_modify: - path: action: create|modify purpose: patterns_to_use: - : dependencies: - : acceptance_criteria_mapping: - AC1: - AC2: risks: - estimated_test_files: - : implementation_order: 1. 2. ... DESIGN END \`\`\` Be specific and concrete. This plan will guide the implementation phase. ## Completion Signal After outputting the design block, output exactly: DESIGN COMPLETE: $story_id" # Log prompt size in verbose mode (consistent with other phases) log_prompt_size "$design_prompt" "design-phase" if [ "$DRY_RUN" = true ]; then echo "[DRY RUN] Would execute design phase for $story_id" return 0 fi # Pipe to file to avoid memory bloat run_claude_to_file "$design_prompt" local result result=$(read_phase_tail) # Extract design block LAST_DESIGN=$(echo "$result" | sed -n '/DESIGN START/,/DESIGN END/p') if [ -n "$LAST_DESIGN" ]; then # Persist the plan to a per-story file so the dev phase can read it # even after a resume (when the in-memory LAST_DESIGN is empty). persist_design "$story_id" "$LAST_DESIGN" # Save to decision log if type append_to_decision_log >/dev/null 2>&1; then append_to_decision_log "DESIGN" "$story_id" "$LAST_DESIGN" fi log_success "Design phase complete: $story_id" return 0 else log_error "Design phase did not produce valid output" return 1 fi } # Persist a design plan to a per-story file under DESIGN_DIR. # Arguments: # $1 - story_id # $2 - design content persist_design() { local story_id="$1" local content="$2" if [ -z "${DESIGN_DIR:-}" ]; then return 0 fi mkdir -p "$DESIGN_DIR" 2>/dev/null || true local design_file="$DESIGN_DIR/${story_id}-design.md" if printf '%s\n' "$content" > "$design_file" 2>/dev/null; then [ "$VERBOSE" = true ] && log "Design plan saved: $design_file" else log_warn "Failed to persist design plan: $design_file" fi } # Get the last design for inclusion in dev phase prompt # Returns the design output or empty string if not available get_last_design() { echo "$LAST_DESIGN" } # Build the design context block for dev phase prompt # Returns formatted design context for inclusion in prompts build_design_context_for_dev() { local story_id="$1" # Prefer the in-memory plan; fall back to the persisted file so a resumed # run (where LAST_DESIGN is empty) still gets the design context. local design="$LAST_DESIGN" if [ -z "$design" ] && [ -n "${DESIGN_DIR:-}" ]; then local design_file="$DESIGN_DIR/${story_id}-design.md" if [ -f "$design_file" ]; then design=$(cat "$design_file") fi fi if [ -z "$design" ]; then echo "" return fi cat << EOF ## Pre-Implementation Design The following design was created in the planning phase. Follow this plan: $design ### Implementation Guidelines Based on Design 1. Follow the implementation_order specified 2. Create/modify files as listed in files_to_modify 3. Use the patterns specified in patterns_to_use 4. Ensure each acceptance_criteria_mapping is implemented 5. Be aware of the identified risks EOF }