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.
Install
$ npx -y skills add AlterLab-IEU/AlterLab_GameForge --agent claude-codeShips 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

