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.
> /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.
- Matches
startup|resume|clear|compact${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh
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.
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.
Repo: dev-toolings/superpowers-symfony

