Skip to content
Agent Orchestration
Hook

Hooks

What metaswarm runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.

From plugin
metaswarm
42114 skills19 agents16 commands2 hooks
Install
$ npx -y skills add dsifry/metaswarm --agent claude-code

Ships with metaswarm. 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

PreCompact

  • ${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
    # hooks/session-start.sh
    # SessionStart + PreCompact hook for metaswarm plugin
    # Outputs JSON with hookSpecificOutput.additionalContext
    
    set -euo pipefail
    
    # --- Phase 0: Self-locate plugin root ---
    # Works with Codex ($PLUGIN_ROOT), Claude Code ($CLAUDE_PLUGIN_ROOT),
    # Gemini CLI ($extensionPath), or direct invocation (derive from script location)
    SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    CODEX_PLUGIN_ROOT="${PLUGIN_ROOT:-}"
    PLUGIN_ROOT="${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-${extensionPath:-$(cd "$SCRIPT_DIR/.." && pwd)}}}"
    METASWARM_PLATFORM="${METASWARM_PLATFORM:-}"
    if [ -z "$METASWARM_PLATFORM" ]; then
      if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
        METASWARM_PLATFORM="claude"
      elif [ -n "${extensionPath:-}" ]; then
        METASWARM_PLATFORM="gemini"
      elif [ -n "$CODEX_PLUGIN_ROOT" ] || [ -n "${CODEX_HOME:-}" ]; then
        METASWARM_PLATFORM="codex"
      else
        METASWARM_PLATFORM="claude"
      fi
    fi
    
    # --- Phase 1: BEADS dedup check ---
    # If standalone BEADS plugin is installed, skip knowledge priming (let BEADS handle it)
    beads_standalone=false
    beads_plugin_caches=("${HOME}/.claude/plugins/cache" "${CODEX_HOME:-${HOME}/.codex}/plugins/cache")
    for beads_plugin_cache in "${beads_plugin_caches[@]}"; do
      if [ -d "$beads_plugin_cache" ]; then
        # Look for a BEADS plugin with name "beads" in plugin.json
        while IFS= read -r -d '' pjson; do
          pname=""
          if command -v jq >/dev/null 2>&1; then
            pname=$(jq -r '.name // empty' "$pjson" 2>/dev/null || true)
          elif command -v node >/dev/null 2>&1; then
            pname=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync(process.argv[1],'utf-8')).name||'')}catch{console.log('')}" "$pjson" 2>/dev/null || true)
          fi
          # Neither jq nor node available — skip dedup check (safe default: allow both to prime)
          if [ "$pname" = "beads" ]; then
            beads_standalone=true
            break
          fi
        done < <(find "$beads_plugin_cache" \( -path "*/.claude-plugin/plugin.json" -o -path "*/.codex-plugin/plugin.json" \) -print0 2>/dev/null || true)
      fi
      [ "$beads_standalone" = true ] && break
    done
    
    # --- Phase 2: New project detection ---
    new_project=false
    if [ ! -f ".metaswarm/project-profile.json" ]; then
      new_project=true
    fi
    
    # --- Phase 3: Legacy install detection ---
    legacy_install=false
    if [ -f ".claude/plugins/metaswarm/.claude-plugin/plugin.json" ]; then
      legacy_install=true
    fi
    
    # --- Phase 3.5: Self-heal mandatory files ---
    # If project profile exists but mandatory files are missing, run the setup script.
    # This catches cases where the agent skipped file creation during setup.
    if [ "$new_project" = false ] && [ "$legacy_install" = false ]; then
      setup_script="${PLUGIN_ROOT}/lib/setup-mandatory-files.sh"
      needs_heal=false
    
      case "$METASWARM_PLATFORM" in
        codex) instruction_file="AGENTS.md" ;;
        gemini) instruction_file="GEMINI.md" ;;
        *) instruction_file="CLAUDE.md" ;;
      esac
    
      if ! grep -q "metaswarm" "$instruction_file" 2>/dev/null; then
        needs_heal=true
      fi
      if [ ! -f ".coverage-thresholds.json" ]; then
        needs_heal=true
      fi
      if { [ "$METASWARM_PLATFORM" = "claude" ] || [ "$METASWARM_PLATFORM" = "all" ]; } \
        && { [ ! -f ".claude/commands/start-task.md" ] || ! grep -q "metaswarm" ".claude/commands/start-task.md" 2>/dev/null; }; then
        needs_heal=true
      fi
    
      if [ "$needs_heal" = true ] && [ -f "$setup_script" ]; then
        # Read coverage command from project profile
        cov_cmd=""
        cov_threshold="100"
        if command -v node >/dev/null 2>&1 && [ -f ".metaswarm/project-profile.json" ]; then
          cov_info=$(node -e "
            try {
              const p = JSON.parse(require('fs').readFileSync('.metaswarm/project-profile.json','utf-8'));
              const t = p.choices?.coverage_threshold || p.coverage?.threshold || p.thresholds?.coverage || 100;
              const c = p.commands?.coverage || 'pytest --cov --cov-fail-under=' + t;
              console.log(t + '|' + c);
            } catch { console.log('100|pytest --cov --cov-fail-under=100'); }
          " 2>/dev/null || echo "100|pytest --cov --cov-fail-under=100")
          cov_threshold="${cov_info%%|*}"
          cov_cmd="${cov_info##*|}"
        fi
        [ -z "$cov_cmd" ] && cov_cmd="pytest --cov --cov-fail-under=${cov_threshold}"
    
        # Run the setup script silently
        bash "$setup_script" "$(pwd)" "$cov_threshold" "$cov_cmd" --platform "$METASWARM_PLATFORM" >/dev/null 2>&1 || true
      fi
    fi
    
    # --- Phase 4: Build context message ---
    context_parts=()
    
    setup_cmd='$setup'
    start_cmd='$start'
    migrate_cmd='$migrate'
    case "$METASWARM_PLATFORM" in
      claude)
        setup_cmd='/setup'
        start_cmd='/start-task'
        migrate_cmd='/migrate'
        ;;
      gemini)
        setup_cmd='/metaswarm:setup'
        start_cmd='/metaswarm:start-task'
        migrate_cmd='/metaswarm:migrate'
        ;;
    esac
    
    if [ "$new_project" = true ]; then
      context_parts+=("Metaswarm is installed but this project hasn't been set up yet. Run \`${setup_cmd}\` to configure it, or \`${start_cmd}\` to begin working.")
    fi
    
    if [ "$legacy_install" = true ]; then
      context_parts+=("This project has metaswarm installed via the old npm method. The marketplace plugin is now active and provides all the same skills and commands. Run \`${migrate_cmd}\` to clean up the redundant copies — this is a safe, reversible operation that only removes duplicate framework files (your project files are never touched).")
    fi
    
    # Knowledge priming (only if project is set up and BEADS isn't separately priming)
    if [ "$new_project" = false ] && [ "$beads_standalone" = false ]; then
      if command -v bd >/dev/null 2>&1; then
        bd_output=$(bd prime 2>/dev/null || true)
        if [ -n "$bd_output" ]; then
          context_parts+=("$bd_output")
        fi
      fi
    fi
    
    # --- Build and output JSON ---
    # Use node for JSON escaping (works on macOS Bash 3.2 where bash parameter
    # expansion with $'\n' is unreliable). Node is available on most systems and
    # is already a soft dependency for the BEADS dedup check above.
    if [ ${#context_parts[@]} 

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 withmetaswarm

A self-improving multi-agent orchestration framework for Claude Code, Gemini CLI, and Codex CLI.

Get the whole plugin