Skip to content

Instantly share code, notes, and snippets.

@busla
Last active December 15, 2025 11:50
Show Gist options
  • Select an option

  • Save busla/06228d9d6dd8e17a2f7600a1f0d167c9 to your computer and use it in GitHub Desktop.

Select an option

Save busla/06228d9d6dd8e17a2f7600a1f0d167c9 to your computer and use it in GitHub Desktop.
SDAD - Spec-Driven Agentic Development Setup
#!/bin/bash
# SDAD Install - Minimal hooks infrastructure setup
# Usage: curl -sL https://gist.github.com/busla/06228d9d6dd8e17a2f7600a1f0d167c9/raw | bash
set -e
TARGET_DIR="${1:-.}"
TARGET_DIR=$(cd "$TARGET_DIR" 2>/dev/null && pwd || echo "$TARGET_DIR")
mkdir -p "$TARGET_DIR"
TARGET_DIR=$(cd "$TARGET_DIR" && pwd)
echo "πŸš€ SDAD: Installing hooks infrastructure..."
echo ""
echo "πŸ“ Target: $TARGET_DIR"
# Create directories
mkdir -p "$TARGET_DIR/.claude"
mkdir -p "$TARGET_DIR/.specify/scripts/bash"
# Backup existing settings if present
if [ -f "$TARGET_DIR/.claude/settings.json" ]; then
cp "$TARGET_DIR/.claude/settings.json" "$TARGET_DIR/.claude/settings.json.backup"
echo " Backed up existing settings.json"
fi
# Write settings.json with hooks
cat > "$TARGET_DIR/.claude/settings.json" << 'SETTINGS_EOF'
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "bash .specify/scripts/bash/post-tool-use.sh"
}
]
}
],
"PreToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "bash .specify/scripts/bash/pre-tool-use.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "bash .specify/scripts/bash/on-stop.sh"
}
]
}
]
}
}
SETTINGS_EOF
echo " βœ“ .claude/settings.json"
# Write post-tool-use.sh
cat > "$TARGET_DIR/.specify/scripts/bash/post-tool-use.sh" << 'POSTTOOL_EOF'
#!/bin/bash
# SDAD Post-Tool-Use Hook
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Read tool input from stdin
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty')
# Only process .specify/* files
if [[ "$FILE" != *.specify/* ]]; then
exit 0
fi
# Sync to memory if script exists
if [ -f "$SCRIPT_DIR/sync-to-memory.sh" ]; then
"$SCRIPT_DIR/sync-to-memory.sh" 2>/dev/null || true
fi
# Get filename and provide agent spawning guidance
BASENAME=$(basename "$FILE")
case "$BASENAME" in
spec.md)
echo ""
echo "πŸ“‹ SDAD: Specification written!"
echo "πŸ€– Spawn these agents NOW in a SINGLE message:"
echo " Task(\"Requirements Researcher\", \"Analyze spec for completeness.\", \"researcher\")"
echo " Task(\"Domain Analyst\", \"Validate requirements against domain patterns.\", \"analyst\")"
echo ""
;;
plan.md)
echo ""
echo "πŸ—οΈ SDAD: Plan written!"
echo "πŸ€– Spawn these agents NOW in a SINGLE message:"
echo " Task(\"System Architect\", \"Design architecture per constitution.\", \"system-architect\")"
echo " Task(\"API Designer\", \"Define OpenAPI contracts.\", \"api-docs\")"
echo " Task(\"Data Modeler\", \"Design entity schemas.\", \"code-analyzer\")"
echo ""
;;
tasks.md)
echo ""
echo "βœ… SDAD: Tasks written!"
echo "πŸ€– Spawn these agents NOW in a SINGLE message:"
echo " Task(\"Implementation Coordinator\", \"Orchestrate tasks from tasks.md\", \"coordinator\")"
echo " Task(\"Backend Developer\", \"Implement backend tasks\", \"backend-dev\")"
echo " Task(\"Test Engineer\", \"Write tests BEFORE implementation (TDD)\", \"tester\")"
echo " Task(\"Code Reviewer\", \"Validate against constitution\", \"reviewer\")"
echo ""
;;
constitution.md)
echo "πŸ“œ SDAD: Constitution updated"
;;
esac
POSTTOOL_EOF
# Write pre-tool-use.sh
cat > "$TARGET_DIR/.specify/scripts/bash/pre-tool-use.sh" << 'PRETOOL_EOF'
#!/bin/bash
# SDAD Pre-Tool-Use Hook
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
# Read tool input from stdin
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty')
# Only validate src/* files
if [[ "$FILE" != */src/* ]]; then
exit 0
fi
# Run constitution validation if script exists
if [ -f "$SCRIPT_DIR/validate-constitution.sh" ]; then
"$SCRIPT_DIR/validate-constitution.sh" 2>/dev/null || true
fi
PRETOOL_EOF
# Write on-stop.sh
cat > "$TARGET_DIR/.specify/scripts/bash/on-stop.sh" << 'ONSTOP_EOF'
#!/bin/bash
# SDAD Stop Hook
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
if [ ! -d "$PROJECT_ROOT/.specify/specs" ]; then
exit 0
fi
echo "πŸ›‘ SDAD: Session ending - syncing state..."
if [ -f "$SCRIPT_DIR/sync-to-memory.sh" ]; then
"$SCRIPT_DIR/sync-to-memory.sh" 2>/dev/null || true
fi
ONSTOP_EOF
# Write sync-to-memory.sh
cat > "$TARGET_DIR/.specify/scripts/bash/sync-to-memory.sh" << 'SYNC_EOF'
#!/bin/bash
# SDAD Memory Sync
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
# Sync constitution
if [ -f "$PROJECT_ROOT/.specify/memory/constitution.md" ]; then
npx claude-flow@alpha memory store \
--key "project/constitution" \
--namespace "foundation" \
--file "$PROJECT_ROOT/.specify/memory/constitution.md" 2>/dev/null || true
fi
# Sync feature specs
if [ -d "$PROJECT_ROOT/.specify/specs" ]; then
for feature_dir in "$PROJECT_ROOT/.specify/specs"/*/; do
if [ -d "$feature_dir" ]; then
feature_name=$(basename "$feature_dir")
for doc in spec.md plan.md tasks.md; do
if [ -f "$feature_dir/$doc" ]; then
ns="specifications"
[[ "$doc" == "plan.md" ]] && ns="architecture"
[[ "$doc" == "tasks.md" ]] && ns="tasks"
npx claude-flow@alpha memory store \
--key "features/$feature_name/${doc%.md}" \
--namespace "$ns" \
--file "$feature_dir/$doc" 2>/dev/null || true
fi
done
fi
done
fi
SYNC_EOF
# Write validate-constitution.sh
cat > "$TARGET_DIR/.specify/scripts/bash/validate-constitution.sh" << 'VALIDATE_EOF'
#!/bin/bash
# SDAD Constitution Validator
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
CONSTITUTION="$PROJECT_ROOT/.specify/memory/constitution.md"
if [ ! -f "$CONSTITUTION" ]; then
exit 0
fi
if grep -q "Test-First" "$CONSTITUTION"; then
if [ -d "$PROJECT_ROOT/src" ] && [ ! -d "$PROJECT_ROOT/tests" ] && [ ! -d "$PROJECT_ROOT/__tests__" ]; then
echo "⚠️ SDAD: Constitution requires Test-First Development"
echo " No tests directory found. Create tests before implementation!"
fi
fi
if grep -q "Type Safety" "$CONSTITUTION"; then
if [ -f "$PROJECT_ROOT/tsconfig.json" ]; then
if ! grep -q '"strict": true' "$PROJECT_ROOT/tsconfig.json"; then
echo "⚠️ SDAD: Constitution requires strict typing"
fi
fi
fi
exit 0
VALIDATE_EOF
# Make scripts executable
chmod +x "$TARGET_DIR/.specify/scripts/bash/"*.sh
echo " βœ“ .specify/scripts/bash/*.sh"
echo ""
echo "βœ… SDAD hooks installed!"
echo ""
echo "πŸ“‹ Hooks will fire when spec-kit writes to .specify/* files"
echo " Use /speckit.specify, /speckit.plan, /speckit.tasks commands to start"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment