Skip to content
Development
Hook

Hooks

What dev-toolings-superpowers-symfony runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.

From plugin
dev-toolings-superpowers-symfony
18744 skills7 agents13 commands1 hook
Install
> /plugin marketplace add dev-toolings/superpowers-symfony
> /plugin install superpowers-symfony@superpowers-symfony

Ships with dev-toolings-superpowers-symfony. Installing the plugin gets these hooks.

What fires, and when

SessionStart

Fires once when a session begins, and again after a context compaction. It is where a plugin sets up its environment, or restores state the compaction dropped.

  • Matchesstartup|resume|clear|compact${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh
Read hooks/hooks.json

Where it lives

  • hooks/session-start.shRunsGitHub
    Read the script
    #!/usr/bin/env bash
    
    # ============================================
    # superpowers-symfony Session Start Hook
    # Detects Symfony projects and configures environment
    # ============================================
    
    set -euo pipefail
    
    PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "$0")")}"
    SKILL_DIR="${PLUGIN_ROOT}/skills/using-symfony-superpowers"
    
    # ============================================
    # 1. SYMFONY PROJECT DETECTION
    # ============================================
    
    detect_symfony_apps() {
      local search_root="${1:-.}"
      local apps=()
    
      # Search for composer.json with symfony/framework-bundle
      while IFS= read -r -d '' composer_file; do
        if grep -q '"symfony/framework-bundle"' "$composer_file" 2>/dev/null; then
          local app_dir
          app_dir=$(dirname "$composer_file")
          apps+=("$app_dir")
        fi
      done < <(find "$search_root" \
        -name "composer.json" \
        -not -path "*/vendor/*" \
        -not -path "*/node_modules/*" \
        -not -path "*/.git/*" \
        -print0 2>/dev/null)
    
      # Guard the empty case: under bash 3.2 + `set -u`, expanding an empty
      # array as "${apps[@]}" raises "apps[@]: unbound variable" (only fixed in
      # bash 4.4+). ${#apps[@]} is safe on an empty array, so gate on the count.
      if [[ ${#apps[@]} -gt 0 ]]; then
        printf '%s\n' "${apps[@]}"
      fi
    }
    
    # ============================================
    # 2. SYMFONY VERSION DETECTION
    # ============================================
    
    get_symfony_version() {
      local app_dir="$1"
      local version=""
    
      # Priority 1: composer.lock (most accurate)
      if [[ -f "$app_dir/composer.lock" ]]; then
        version=$(grep -A5 '"name": "symfony/framework-bundle"' "$app_dir/composer.lock" 2>/dev/null |
          grep '"version"' | head -1 |
          sed -E 's/.*"version": "v?([0-9]+\.[0-9]+).*/\1/')
      fi
    
      # Priority 2: composer.json require
      # Anchor on the framework-bundle key so a minified (single-line) composer.json
      # can't bleed another dependency's version into the match.
      if [[ -z "$version" && -f "$app_dir/composer.json" ]]; then
        version=$(grep -oE '"symfony/framework-bundle"[[:space:]]*:[[:space:]]*"[v^~>=! ]*[0-9]+\.[0-9]+' "$app_dir/composer.json" 2>/dev/null |
          head -1 | grep -oE '[0-9]+\.[0-9]+' | head -1)
      fi
    
      echo "${version:-unknown}"
    }
    
    # ============================================
    # 3. API PLATFORM DETECTION
    # ============================================
    
    detect_api_platform() {
      local app_dir="$1"
      local has_api_platform="false"
      local api_version=""
    
      if [[ -f "$app_dir/composer.lock" ]]; then
        if grep -q '"api-platform/core"' "$app_dir/composer.lock" 2>/dev/null; then
          has_api_platform="true"
          api_version=$(grep -A5 '"name": "api-platform/core"' "$app_dir/composer.lock" 2>/dev/null |
            grep '"version"' | head -1 |
            sed -E 's/.*"version": "v?([0-9]+\.[0-9]+).*/\1/')
        fi
      elif [[ -f "$app_dir/composer.json" ]]; then
        if grep -q '"api-platform/core"' "$app_dir/composer.json" 2>/dev/null; then
          has_api_platform="true"
        fi
      fi
    
      echo "${has_api_platform}:${api_version:-none}"
    }
    
    # ============================================
    # 4. DOCKER TYPE DETECTION
    # ============================================
    
    detect_docker_type() {
      local app_dir="$1"
      local docker_type="none"
    
      # Check for DDEV first (highest priority)
      if [[ -d "$app_dir/.ddev" ]]; then
        docker_type="ddev"
      # Check for Symfony Docker (dunglas/symfony-docker with FrankenPHP)
      elif [[ -f "$app_dir/compose.yaml" ]]; then
        if grep -qE "(frankenphp|dunglas/symfony-docker|caddy)" "$app_dir/compose.yaml" 2>/dev/null; then
          docker_type="symfony-docker"
        elif grep -q "services:" "$app_dir/compose.yaml" 2>/dev/null; then
          docker_type="compose-yaml"
        fi
      elif [[ -f "$app_dir/compose.yml" ]]; then
        if grep -qE "(frankenphp|dunglas/symfony-docker|caddy)" "$app_dir/compose.yml" 2>/dev/null; then
          docker_type="symfony-docker"
        else
          docker_type="compose-yml"
        fi
      elif [[ -f "$app_dir/docker-compose.yaml" ]]; then
        docker_type="docker-compose-yaml"
      elif [[ -f "$app_dir/docker-compose.yml" ]]; then
        docker_type="docker-compose-yml"
      fi
    
      # Additional check for Symfony Docker indicators
      if [[ -d "$app_dir/frankenphp" ]] || [[ -f "$app_dir/Caddyfile" ]]; then
        docker_type="symfony-docker"
      fi
    
      echo "$docker_type"
    }
    
    # ============================================
    # 5. DOCKER RUNNING STATUS
    # ============================================
    
    check_docker_running() {
      local app_dir="$1"
      local docker_type="$2"
    
      # For testing
      if [[ "${SUPERPOWERS_TEST_DOCKER_RUNNING:-}" == "true" ]]; then
        echo "true"
        return
      fi
    
      if ! command -v docker &>/dev/null; then
        echo "false"
        return
      fi
    
      # Check if containers are running in project context
      cd "$app_dir" 2>/dev/null || {
        echo "false"
        return
      }
    
      if docker compose ps --filter "status=running" 2>/dev/null | grep -q .; then
        echo "true"
      else
        echo "false"
      fi
    }
    
    # ============================================
    # 6. TEST FRAMEWORK DETECTION
    # ============================================
    
    detect_test_framework() {
      local app_dir="$1"
      local framework="phpunit" # Default Symfony
    
      if [[ -f "$app_dir/composer.lock" ]]; then
        if grep -q '"pestphp/pest"' "$app_dir/composer.lock" 2>/dev/null; then
          framework="pest"
        fi
      elif [[ -f "$app_dir/composer.json" ]]; then
        if grep -q '"pestphp/pest"' "$app_dir/composer.json" 2>/dev/null; then
          framework="pest"
        fi
      fi
    
      echo "$framework"
    }
    
    # ============================================
    # 7. DETERMINE RUNNER COMMANDS
    # ============================================
    
    get_runner_commands() {
      local app_dir="$1"
      local docker_type="$2"
      local docker_running="$3"
    
      local runner_cmd="php"
      local console_cmd="php bin/console"
      local composer_cmd="composer"
      local test_cmd="./vendor/bin/phpunit"
    
      if [[ "$docker_running" == "true" ]]; then
        if [[ "$docker_type" == "ddev" ]]; then
          runner_cmd="ddev exec"
      

Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.

Ships withdev-toolings-superpowers-symfony

Symfony AI development superpowers for Claude Code. 44 expert skills, 7 specialized subagents, and 13 slash commands covering API Platform v4, Doctrine ORM 3, TDD with Pest & PHPUnit, Symfony Messenger, security/voters, and DDD / hexagonal architecture.

Get the whole plugin