Skip to content
Development
Hook

Hooks

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

From plugin
alterlab-gameforge
4034 skills11 hooks
Install
$ npx -y skills add AlterLab-IEU/AlterLab_GameForge --agent claude-code

Ships with alterlab-gameforge. Installing the plugin gets these hooks.

Where it lives

  • hooks/config-change.shGitHub
    Read the script
    #!/usr/bin/env bash
    # GameForge Config Change Hook
    # Event: ConfigChange
    # Purpose: Detect when skills or configuration are modified during a session.
    #
    # When skills, settings, or project configuration change while a session is active,
    # Claude may be operating with stale skill definitions. This hook detects the change,
    # logs it, and suggests a skill reload so the session picks up the latest content.
    #
    # This is especially important during GameForge development (editing SKILL.md files)
    # and when users modify their .claude/settings.json or project configuration.
    #
    # Input: JSON via stdin with config change details
    # Output: JSON to stdout with systemMessage if skills changed
    # Exit 0: success, Exit 2: blocking error
    
    # Read input from stdin
    INPUT=$(cat)
    
    # Ensure log directory exists
    if [ ! -d "production/session-logs" ]; then
      mkdir -p production/session-logs 2>/dev/null || true
    fi
    
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    
    # Try to extract the config source from input
    CONFIG_SOURCE="unknown"
    if echo "$INPUT" | grep -q '"config_source"'; then
      CONFIG_SOURCE=$(echo "$INPUT" | sed -n 's/.*"config_source"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
    fi
    if [ "$CONFIG_SOURCE" = "unknown" ] && echo "$INPUT" | grep -q '"matcher"'; then
      CONFIG_SOURCE=$(echo "$INPUT" | sed -n 's/.*"matcher"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
    fi
    if [ "$CONFIG_SOURCE" = "unknown" ] && echo "$INPUT" | grep -q '"source"'; then
      CONFIG_SOURCE=$(echo "$INPUT" | sed -n 's/.*"source"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
    fi
    
    # Log the config change event
    echo "[$TIMESTAMP] ConfigChange: source=$CONFIG_SOURCE" \
      >> production/session-logs/sessions.log 2>/dev/null || true
    
    # Determine the appropriate response based on what changed
    case "$CONFIG_SOURCE" in
      skills)
        # Skills were modified -- this is the most impactful change
        cat <<EOF
    {
      "continue": true,
      "systemMessage": "[GameForge] Skill files have been modified during this session. The active skill definitions may be stale. If you are developing or updating GameForge skills, consider reloading the affected skill by invoking it again with /skill-name. If a skill behaves unexpectedly, this config change may be the cause."
    }
    EOF
        ;;
      user_settings)
        # User-level settings changed (e.g., ~/.claude/settings.json)
        cat <<EOF
    {
      "continue": true,
      "systemMessage": "[GameForge] User settings have been modified. If you changed tool permissions, model preferences, or hook configuration, the changes are now active."
    }
    EOF
        ;;
      project_settings)
        # Project-level settings changed (e.g., .claude/settings.json)
        cat <<EOF
    {
      "continue": true,
      "systemMessage": "[GameForge] Project settings have been modified. If you changed tool permissions or hook configuration for this project, the changes are now active."
    }
    EOF
        ;;
      local_settings)
        # Local settings changed (e.g., .claude/settings.local.json)
        cat <<EOF
    {
      "continue": true
    }
    EOF
        ;;
      policy_settings)
        # Managed policy settings changed
        cat <<EOF
    {
      "continue": true,
      "systemMessage": "[GameForge] Organization policy settings have been updated. Review any new restrictions that may affect tool usage."
    }
    EOF
        ;;
      *)
        # Unknown config source -- log but don't alarm the user
        cat <<EOF
    {
      "continue": true
    }
    EOF
        ;;
    esac
    
    exit 0
    
  • hooks/detect-gaps.shGitHub
    Read the script
    #!/bin/sh
    # GameForge Gap Detection Hook
    
    # Find source directories (engine-aware)
    find_source_dirs() {
      DIRS=""
      for d in src scripts Scripts Source Assets/Scripts lib; do
        if [ -d "$d" ]; then
          DIRS="$DIRS $d"
        fi
      done
      echo "$DIRS"
    }
    
    # Find design directories
    find_design_dirs() {
      DIRS=""
      for d in design design/gdd docs/design Documentation; do
        if [ -d "$d" ]; then
          DIRS="$DIRS $d"
        fi
      done
      echo "$DIRS"
    }
    
    # Find test directories
    find_test_dirs() {
      DIRS=""
      for d in tests test Tests; do
        if [ -d "$d" ]; then
          DIRS="$DIRS $d"
        fi
      done
      echo "$DIRS"
    }
    
    SRC_DIRS=$(find_source_dirs)
    DESIGN_DIRS=$(find_design_dirs)
    TEST_DIRS=$(find_test_dirs)
    
    # Fresh project detection -- no source AND no design directories
    if [ -z "$SRC_DIRS" ] && [ -z "$DESIGN_DIRS" ]; then
      echo "Fresh project detected. Run /game-start to begin."
      exit 0
    fi
    
    # Code exists but no design docs
    if [ -n "$SRC_DIRS" ] && [ -z "$DESIGN_DIRS" ]; then
      echo "Code exists but no design docs found. Consider /game-design-review"
    fi
    
    # Design docs exist but no tests
    if [ -n "$DESIGN_DIRS" ] && [ -z "$TEST_DIRS" ]; then
      echo "Design docs exist but no test directory. Consider setting up testing."
    fi
    
    exit 0
    
  • hooks/instructions-validate.shGitHub
    Read the script
    #!/usr/bin/env bash
    # GameForge Instructions Validation Hook
    # Event: InstructionsLoaded
    # Purpose: Validate that required documentation files exist when CLAUDE.md is loaded.
    #
    # When Claude Code loads CLAUDE.md (at session start, after compaction, or when
    # traversing nested directories), this hook checks that the shared documentation
    # files referenced by skills actually exist. Missing docs cause skills to produce
    # incomplete or incorrect output because they reference knowledge that is not there.
    #
    # Input: JSON via stdin with load event details
    # Output: JSON to stdout with systemMessage if docs are missing
    # Exit 0: success, Exit 2: blocking error
    
    # Read input from stdin
    INPUT=$(cat)
    
    # Track missing files
    MISSING=""
    MISSING_COUNT=0
    
    # Check each required doc (inline values, no bash arrays)
    for doc in docs/collaboration-protocol.md docs/game-design-theory.md docs/coordination-rules.md docs/agent-hierarchy.md docs/coding-standards.md docs/workflow-guide.md docs/monetization-ethics.md docs/engine-comparison.md; do
      if [ ! -f "$doc" ]; then
        MISSING="$MISSING $doc"
        MISSING_COUNT=$((MISSING_COUNT + 1))
      fi
    done
    
    # Check if docs directory exists at all
    if [ ! -d "docs" ]; then
      cat <<EOF
    {
      "continue": true,
      "systemMessage": "[GameForge] Warning: docs/ directory not found. This project may not be a GameForge-enabled game project, or the docs directory has not been created yet. Run /game-start to initialize project structure."
    }
    EOF
      exit 0
    fi
    
    # Check if templates directory exists
    TEMPLATE_WARNING=""
    if [ ! -d "templates" ]; then
      TEMPLATE_WARNING=" Templates directory (templates/) is also missing."
    fi
    
    # Report findings
    if [ "$MISSING_COUNT" -gt 0 ]; then
      cat <<EOF
    {
      "continue": true,
      "systemMessage": "[GameForge] Warning: $MISSING_COUNT required documentation file(s) missing:$MISSING.$TEMPLATE_WARNING Skills that reference these docs will produce incomplete output. Run /game-start to scaffold missing files, or create them manually."
    }
    EOF
    else
      # All docs present, no message needed
      cat <<EOF
    {
      "continue": true
    }
    EOF
    fi
    
    exit 0
    
  • hooks/log-agent.shGitHub
    Read the script
    #!/bin/sh
    # GameForge Agent Logging Hook
    # Log subagent invocations for audit trail
    if [ ! -d "production/session-logs" ]; then
      mkdir -p production/session-logs 2>/dev/null
    fi
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] Agent invoked: $1" >> production/session-logs/agent-log.txt 2>/dev/null
    
    exit 0
    
  • hooks/post-compact.shGitHub
    Read the script
    #!/usr/bin/env bash
    # GameForge Post-Compact Hook
    # Event: PostCompact
    # Purpose: Restore essential game dev context after context compaction.
    #
    # When Claude Code compacts context to free up the context window, critical project
    # state can be lost. This hook re-injects the most important context reminders so
    # the session continues without amnesia about the project's engine, phase, and
    # active sprint.
    #
    # Input: JSON via stdin with compaction details
    # Output: JSON to stdout with systemMessage containing context reminders
    # Exit 0: success, Exit 2: blocking error
    
    # Find source directories (engine-aware)
    find_source_dirs() {
      DIRS=""
      for d in src scripts Scripts Source Assets/Scripts lib; do
        if [ -d "$d" ]; then
          DIRS="$DIRS $d"
        fi
      done
      echo "$DIRS"
    }
    
    # Find design directories
    find_design_dirs() {
      DIRS=""
      for d in design design/gdd docs/design Documentation; do
        if [ -d "$d" ]; then
          DIRS="$DIRS $d"
        fi
      done
      echo "$DIRS"
    }
    
    # Read input from stdin (compaction event data)
    INPUT=$(cat)
    
    # Ensure session state directories exist
    mkdir -p production/session-state 2>/dev/null || true
    mkdir -p production/session-logs 2>/dev/null || true
    
    # Collect project context pieces
    ENGINE="unknown"
    PHASE="unknown"
    SPRINT_GOAL=""
    TEAM_SIZE=""
    
    # Detect engine from project files
    if [ -f "project.godot" ]; then
      ENGINE="Godot"
    elif ls *.unity 2>/dev/null | head -1 > /dev/null 2>&1; then
      ENGINE="Unity"
    elif ls *.uproject 2>/dev/null | head -1 > /dev/null 2>&1; then
      ENGINE="Unreal Engine"
    elif [ -f "package.json" ] && grep -q "phaser\|pixi\|playcanvas" package.json 2>/dev/null; then
      ENGINE="Web (JS)"
    elif [ -f "Cargo.toml" ] && grep -q "bevy\|macroquad" Cargo.toml 2>/dev/null; then
      ENGINE="Rust"
    fi
    
    # Detect project phase from directory structure (engine-aware)
    SRC_DIRS=$(find_source_dirs)
    DESIGN_DIRS=$(find_design_dirs)
    HAS_SRC=""
    HAS_DESIGN=""
    if [ -n "$SRC_DIRS" ]; then
      HAS_SRC="yes"
    fi
    if [ -n "$DESIGN_DIRS" ]; then
      HAS_DESIGN="yes"
    fi
    
    if [ -z "$HAS_SRC" ] && [ -z "$HAS_DESIGN" ]; then
      PHASE="empty-project"
    elif [ -n "$HAS_DESIGN" ] && [ -z "$HAS_SRC" ]; then
      PHASE="concept"
    elif [ -n "$HAS_SRC" ] && [ -n "$HAS_DESIGN" ]; then
      PHASE="in-progress"
    elif [ -n "$HAS_SRC" ] && [ -z "$HAS_DESIGN" ]; then
      PHASE="code-only"
    fi
    
    # Read active sprint info if available
    if [ -f "production/session-state/last-sprint.json" ]; then
      SPRINT_GOAL=$(head -5 production/session-state/last-sprint.json 2>/dev/null)
    fi
    
    # Read active session state if available
    ACTIVE_STATE=""
    if [ -f "production/session-state/active.md" ]; then
      ACTIVE_STATE=$(head -10 production/session-state/active.md 2>/dev/null)
    fi
    
    # Log the compaction event
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    echo "[$TIMESTAMP] PostCompact: context restored (engine=$ENGINE, phase=$PHASE)" \
      >> production/session-logs/sessions.log 2>/dev/null || true
    
    # Build the context reminder message
    CONTEXT_MSG="[GameForge Context Restored After Compaction]"
    CONTEXT_MSG="$CONTEXT_MSG Engine: $ENGINE."
    CONTEXT_MSG="$CONTEXT_MSG Project phase: $PHASE."
    
    if [ -n "$SPRINT_GOAL" ] && [ "$SPRINT_GOAL" != "" ]; then
      CONTEXT_MSG="$CONTEXT_MSG Active sprint data available in production/session-state/last-sprint.json."
    fi
    
    if [ -n "$ACTIVE_STATE" ] && [ "$ACTIVE_STATE" != "" ]; then
      CONTEXT_MSG="$CONTEXT_MSG Previous session state available in production/session-state/active.md."
    fi
    
    CONTEXT_MSG="$CONTEXT_MSG Shared docs: @docs/collaboration-protocol.md, @docs/game-design-theory.md, @docs/coordination-rules.md. Refer to CLAUDE.md for full skill routing rules."
    
    # Output JSON response
    cat <<EOF
    {
      "continue": true,
      "systemMessage": "$CONTEXT_MSG"
    }
    EOF
    
    exit 0
    
  • hooks/pre-compact.shGitHub
    Read the script
    #!/bin/sh
    # GameForge Pre-Compact Hook
    # Remind to save state before context compression
    echo "Context compaction incoming. Ensure session state is saved to production/session-state/active.md"
    
    exit 0
    
  • hooks/session-start.shGitHub
  • hooks/session-stop.shGitHub
  • hooks/stop-failure.shGitHub
  • hooks/subagent-track.shGitHub
  • hooks/validate-commit.shGitHub

All 11 scripts are listed above. The source is inlined for 6 of them, starting with whatever hooks.json actually runs. See all of them in the repo.

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 withalterlab-gameforge

🎮 34 production-grade Claude Code skills for indie game development — studio agents, workflow skills, engine specialists, genre packs, and CI validation. From concept to launch.

Get the whole plugin