BMAD-METHOD/bmad-core/tasks/auto-language-init.md

12 KiB

Auto Language Initialization

Automatic language detection and configuration that runs once per session to set up environment variables for all subsequent BMAD tasks.

LLM: This task runs automatically on first BMAD command to detect project language and configure all subsequent tasks

Auto-Initialization System

1. Session-Based Auto-Detection (50-100 tokens)

# Auto-initialize language environment if not already done
auto_init_language_environment() {
  local CACHE_FILE="tmp/bmad-session.json"
  
  # Check if already initialized this session
  if [ -f "$CACHE_FILE" ]; then
    SESSION_AGE=$(jq -r '.initialized_at // "1970-01-01"' "$CACHE_FILE")
    if [ "$(date -d "$SESSION_AGE" +%s)" -gt "$(date -d '2 hours ago' +%s)" ]; then
      # Load cached environment variables
      source <(jq -r '.environment | to_entries[] | "export " + .key + "=\"" + .value + "\""' "$CACHE_FILE")
      echo "🔄 Using cached language environment: $BMAD_PRIMARY_LANGUAGE"
      return 0
    fi
  fi
  
  echo "🔍 Auto-detecting project language..."
  
  # Rapid language detection
  PROJECT_DIR="${1:-.}"
  PRIMARY_LANGUAGE="unknown"
  BUILD_COMMAND="echo 'No build system detected'"
  TEST_COMMAND="echo 'No test system detected'"
  SIMULATION_PATTERNS="TODO|FIXME|HACK"
  ERROR_PATTERNS="error:|Error:"
  COMPONENT_PATTERNS="[A-Z][a-zA-Z]*Service|[A-Z][a-zA-Z]*Controller|[A-Z][a-zA-Z]*Repository"
  FILE_EXTENSIONS="*.*"
  
  # Multi-tier detection strategy for new/existing projects
  
  # Tier 1: Config files (most reliable)
  if [ -f "$PROJECT_DIR/package.json" ]; then
    if grep -q '"typescript":\|"@types/\|"ts-' "$PROJECT_DIR/package.json" || [ -f "$PROJECT_DIR/tsconfig.json" ]; then
      PRIMARY_LANGUAGE="typescript"
      BUILD_COMMAND="npm run build 2>/dev/null || tsc --noEmit"
      TEST_COMMAND="npm test"
      SIMULATION_PATTERNS="Math\.random|jest\.fn|sinon\.|TODO|FIXME"
      ERROR_PATTERNS="TS[0-9]{4}|error TS"
      FILE_EXTENSIONS="*.ts|*.tsx"
    else
      PRIMARY_LANGUAGE="javascript"
      BUILD_COMMAND="npm run build 2>/dev/null || echo 'No build step'"
      TEST_COMMAND="npm test"
      SIMULATION_PATTERNS="Math\.random|jest\.fn|sinon\.|TODO|FIXME"
      ERROR_PATTERNS="Error:|SyntaxError:"
      FILE_EXTENSIONS="*.js|*.jsx"
    fi
  elif ls "$PROJECT_DIR"/*.csproj >/dev/null 2>&1 || [ -f "$PROJECT_DIR"/*.sln ]; then
    PRIMARY_LANGUAGE="csharp"
    BUILD_COMMAND="dotnet build --verbosity quiet"
    TEST_COMMAND="dotnet test --verbosity quiet"
    SIMULATION_PATTERNS="Random\.NextDouble|Task\.FromResult|NotImplementedException|Mock\.|Fake\.|Stub\."
    ERROR_PATTERNS="CS[0-9]{4}"
    FILE_EXTENSIONS="*.cs"
  elif [ -f "$PROJECT_DIR/pom.xml" ] || [ -f "$PROJECT_DIR/build.gradle" ]; then
    PRIMARY_LANGUAGE="java"
    BUILD_COMMAND="mvn compile -q 2>/dev/null || gradle build -q"
    TEST_COMMAND="mvn test -q 2>/dev/null || gradle test -q"
    SIMULATION_PATTERNS="Math\.random|Mockito\.|@Mock|TODO|FIXME"
    ERROR_PATTERNS="error:"
    FILE_EXTENSIONS="*.java"
  elif [ -f "$PROJECT_DIR/Cargo.toml" ]; then
    PRIMARY_LANGUAGE="rust"
    BUILD_COMMAND="cargo build --quiet"
    TEST_COMMAND="cargo test --quiet"
    SIMULATION_PATTERNS="todo!|unimplemented!|panic!|TODO|FIXME"
    ERROR_PATTERNS="error\[E[0-9]{4}\]"
    FILE_EXTENSIONS="*.rs"
  elif [ -f "$PROJECT_DIR/go.mod" ]; then
    PRIMARY_LANGUAGE="go"
    BUILD_COMMAND="go build ./..."
    TEST_COMMAND="go test ./..."
    SIMULATION_PATTERNS="rand\.|mock\.|TODO|FIXME"
    ERROR_PATTERNS="cannot find package|undefined:"
    FILE_EXTENSIONS="*.go"
  elif [ -f "$PROJECT_DIR/requirements.txt" ] || [ -f "$PROJECT_DIR/pyproject.toml" ] || [ -f "$PROJECT_DIR/setup.py" ]; then
    PRIMARY_LANGUAGE="python"
    BUILD_COMMAND="python -m py_compile *.py 2>/dev/null || echo 'Syntax check complete'"
    TEST_COMMAND="python -m pytest"
    SIMULATION_PATTERNS="random\.|mock\.|Mock\.|TODO|FIXME"
    ERROR_PATTERNS="SyntaxError:|IndentationError:|NameError:"
    FILE_EXTENSIONS="*.py"
  elif [ -f "$PROJECT_DIR/Gemfile" ]; then
    PRIMARY_LANGUAGE="ruby"
    BUILD_COMMAND="ruby -c *.rb 2>/dev/null || echo 'Ruby syntax check'"
    TEST_COMMAND="bundle exec rspec"
    SIMULATION_PATTERNS="rand|mock|double|TODO|FIXME"
    ERROR_PATTERNS="SyntaxError:|NameError:"
    FILE_EXTENSIONS="*.rb"
  elif [ -f "$PROJECT_DIR/composer.json" ]; then
    PRIMARY_LANGUAGE="php"
    BUILD_COMMAND="php -l *.php 2>/dev/null || echo 'PHP syntax check'"
    TEST_COMMAND="vendor/bin/phpunit"
    SIMULATION_PATTERNS="rand|mock|TODO|FIXME"
    ERROR_PATTERNS="Parse error:|Fatal error:"
    FILE_EXTENSIONS="*.php"
    
  # Tier 2: File extension analysis (for new projects)
  elif find "$PROJECT_DIR" -maxdepth 3 -name "*.ts" -o -name "*.tsx" | head -1 | grep -q .; then
    PRIMARY_LANGUAGE="typescript"
    BUILD_COMMAND="tsc --noEmit 2>/dev/null || echo 'TypeScript check (install: npm i -g typescript)'"
    TEST_COMMAND="npm test 2>/dev/null || echo 'Install test framework'"
    SIMULATION_PATTERNS="Math\.random|jest\.fn|TODO|FIXME"
    ERROR_PATTERNS="TS[0-9]{4}|error TS"
    FILE_EXTENSIONS="*.ts|*.tsx"
    echo "💡 New TypeScript project detected - consider: npm init && npm install typescript"
  elif find "$PROJECT_DIR" -maxdepth 3 -name "*.cs" | head -1 | grep -q .; then
    PRIMARY_LANGUAGE="csharp"
    BUILD_COMMAND="dotnet build --verbosity quiet 2>/dev/null || echo 'C# files found (install: dotnet CLI)'"
    TEST_COMMAND="dotnet test --verbosity quiet"
    SIMULATION_PATTERNS="Random\.NextDouble|Task\.FromResult|NotImplementedException"
    ERROR_PATTERNS="CS[0-9]{4}"
    FILE_EXTENSIONS="*.cs"
    echo "💡 New C# project detected - consider: dotnet new console/webapi/classlib"
  elif find "$PROJECT_DIR" -maxdepth 3 -name "*.java" | head -1 | grep -q .; then
    PRIMARY_LANGUAGE="java"
    BUILD_COMMAND="javac *.java 2>/dev/null || echo 'Java files found (setup: mvn/gradle)'"
    TEST_COMMAND="mvn test 2>/dev/null || echo 'Setup Maven/Gradle'"
    SIMULATION_PATTERNS="Math\.random|TODO|FIXME"
    ERROR_PATTERNS="error:"
    FILE_EXTENSIONS="*.java"
    echo "💡 New Java project detected - consider: mvn archetype:generate"
  elif find "$PROJECT_DIR" -maxdepth 3 -name "*.rs" | head -1 | grep -q .; then
    PRIMARY_LANGUAGE="rust"
    BUILD_COMMAND="rustc --version >/dev/null 2>&1 && echo 'Rust files found' || echo 'Install Rust toolchain'"
    TEST_COMMAND="cargo test 2>/dev/null || echo 'Run: cargo init'"
    SIMULATION_PATTERNS="todo!|unimplemented!|TODO"
    ERROR_PATTERNS="error\[E[0-9]{4}\]"
    FILE_EXTENSIONS="*.rs"
    echo "💡 New Rust project detected - consider: cargo init"
  elif find "$PROJECT_DIR" -maxdepth 3 -name "*.go" | head -1 | grep -q .; then
    PRIMARY_LANGUAGE="go"
    BUILD_COMMAND="go version >/dev/null 2>&1 && echo 'Go files found' || echo 'Install Go'"
    TEST_COMMAND="go test ./... 2>/dev/null || echo 'Run: go mod init'"
    SIMULATION_PATTERNS="TODO|FIXME"
    ERROR_PATTERNS="undefined:|cannot find"
    FILE_EXTENSIONS="*.go"
    echo "💡 New Go project detected - consider: go mod init"
  elif find "$PROJECT_DIR" -maxdepth 3 -name "*.py" | head -1 | grep -q .; then
    PRIMARY_LANGUAGE="python"
    BUILD_COMMAND="python -m py_compile *.py 2>/dev/null || echo 'Python files found'"
    TEST_COMMAND="python -m pytest 2>/dev/null || echo 'Install: pip install pytest'"
    SIMULATION_PATTERNS="random\.|TODO|FIXME"
    ERROR_PATTERNS="SyntaxError:|NameError:"
    FILE_EXTENSIONS="*.py"
    echo "💡 New Python project detected - consider: pip install -r requirements.txt"
  elif find "$PROJECT_DIR" -maxdepth 3 -name "*.js" -o -name "*.jsx" | head -1 | grep -q .; then
    PRIMARY_LANGUAGE="javascript"
    BUILD_COMMAND="node --version >/dev/null 2>&1 && echo 'JavaScript files found' || echo 'Install Node.js'"
    TEST_COMMAND="npm test 2>/dev/null || echo 'Run: npm init'"
    SIMULATION_PATTERNS="Math\.random|TODO|FIXME"
    ERROR_PATTERNS="Error:|SyntaxError:"
    FILE_EXTENSIONS="*.js|*.jsx"
    echo "💡 New JavaScript project detected - consider: npm init"
    
  # Tier 3: Directory/filename hints (empty projects)
  elif [ -d "$PROJECT_DIR/src/main/java" ] || [ -d "$PROJECT_DIR/app/src/main/java" ]; then
    PRIMARY_LANGUAGE="java"
    BUILD_COMMAND="echo 'Java project structure detected - setup Maven/Gradle'"
    TEST_COMMAND="echo 'Setup Maven: mvn archetype:generate'"
    SIMULATION_PATTERNS="TODO|FIXME"
    ERROR_PATTERNS="error:"
    FILE_EXTENSIONS="*.java"
    echo "💡 Java project structure detected - run: mvn archetype:generate"
  elif [ -d "$PROJECT_DIR/src" ] && [ ! -f "$PROJECT_DIR/package.json" ] && [ ! -f "$PROJECT_DIR/*.csproj" ]; then
    PRIMARY_LANGUAGE="generic"
    BUILD_COMMAND="echo 'Generic project with src/ folder detected'"
    TEST_COMMAND="echo 'Setup appropriate build system'"
    SIMULATION_PATTERNS="TODO|FIXME|HACK"
    ERROR_PATTERNS="error:|Error:"
    FILE_EXTENSIONS="*.*"
    echo "💡 Generic project structure - specify language manually if needed"
  fi
  
  # Cache environment for session
  mkdir -p tmp
  cat > "$CACHE_FILE" << EOF
{
  "initialized_at": "$(date -Iseconds)",
  "environment": {
    "BMAD_PRIMARY_LANGUAGE": "$PRIMARY_LANGUAGE",
    "BMAD_BUILD_COMMAND": "$BUILD_COMMAND",
    "BMAD_TEST_COMMAND": "$TEST_COMMAND",
    "BMAD_SIMULATION_PATTERNS": "$SIMULATION_PATTERNS",
    "BMAD_ERROR_PATTERNS": "$ERROR_PATTERNS",
    "BMAD_COMPONENT_PATTERNS": "$COMPONENT_PATTERNS",
    "BMAD_FILE_EXTENSIONS": "$FILE_EXTENSIONS"
  }
}
EOF
  
  # Export environment variables for current session
  export BMAD_PRIMARY_LANGUAGE="$PRIMARY_LANGUAGE"
  export BMAD_BUILD_COMMAND="$BUILD_COMMAND"  
  export BMAD_TEST_COMMAND="$TEST_COMMAND"
  export BMAD_SIMULATION_PATTERNS="$SIMULATION_PATTERNS"
  export BMAD_ERROR_PATTERNS="$ERROR_PATTERNS"
  export BMAD_COMPONENT_PATTERNS="$COMPONENT_PATTERNS"
  export BMAD_FILE_EXTENSIONS="$FILE_EXTENSIONS"
  
  echo "✅ Language environment initialized: $PRIMARY_LANGUAGE"
}

# Call auto-initialization (runs automatically when this task is loaded)
auto_init_language_environment

Integration Method

2. Automatic Task Wrapper

Instead of individual tasks calling language detection, each optimized task starts with:

#!/bin/bash
# Auto-initialize language environment if needed
if [ -z "$BMAD_PRIMARY_LANGUAGE" ]; then
  Read tool: bmad-core/tasks/auto-language-init.md
fi

# Now use language-specific variables directly
echo "🔍 Smart Build Context Analysis ($BMAD_PRIMARY_LANGUAGE)"
BUILD_OUTPUT=$($BMAD_BUILD_COMMAND 2>&1)
# ... rest of task logic

3. Agent-Level Auto-Initialization

Add to both dev and qa agent startup:

session_initialization:
  - auto_init_language_environment    # Runs once per agent session
  
enhanced_commands:
  - "*smart-build-context"            # Uses pre-initialized environment
  - "*smart-reality-audit"            # Uses pre-initialized environment
  - "*smart-story-mapping"            # Uses pre-initialized environment

Execution Flow

How It Works in Practice:

# User runs: *smart-reality-audit story.md

1. Agent starts executing smart-reality-audit task
2. Task checks: "Is BMAD_PRIMARY_LANGUAGE set?"
3. If not: Runs auto-language-init.md (50-100 tokens, once per session)
4. If yes: Skips initialization (0 tokens)
5. Task uses $BMAD_BUILD_COMMAND, $BMAD_SIMULATION_PATTERNS directly
6. All subsequent tasks in session use cached environment (0 additional tokens)

Token Usage:

  • First task in session: 50-100 tokens for initialization
  • All subsequent tasks: 0 additional tokens (uses cached environment)
  • Session reuse: Environment cached for 2 hours

Benefits of This Approach

Fully Automatic - No manual commands needed
Session Efficient - Initialize once, use everywhere
Zero Integration Overhead - Tasks just check environment variables
Language Agnostic - Works with any supported language
Minimal Token Cost - 50-100 tokens per session vs per task

This makes language adaptation completely transparent to the user while maintaining all optimization benefits!