Comprehensive developer toolkit providing reusable skills for Java/Spring Boot, TypeScript/NestJS/React/Next.js, Python, PHP, AWS CloudFormation, AI/RAG, DevOps, and more.
90
90%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Risky
Do not use without reviewing
#!/bin/bash
# Claude Code Interactive Developer Kit Installer Script
# Usage: install-claude.sh "<plugin_json_files>"
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Get plugin files from argument
PLUGIN_JSON_FILES="$1"
DEVKIT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# Confirm installation
read -p "Are you installing for Claude Code? (y/N): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
echo -e "${RED}✗ Installation cancelled.${NC}"
exit 1
fi
echo ""
echo -e "${GREEN}Step 1: Target Project${NC}"
read -p "Enter the project path (absolute or relative, or press Enter for current directory): " project_path
if [[ -z "$project_path" ]]; then
project_path="."
fi
if [[ ! -d "$project_path" ]]; then
echo -n " ⚠ $project_path does not exist. Create it? (y/N): "
read create_dir
if [[ "$create_dir" != "y" && "$create_dir" != "Y" ]]; then
echo -e "${RED}✗ Installation cancelled.${NC}"
exit 1
fi
mkdir -p "$project_path"
fi
TARGET_PROJECT="$(cd "$project_path" && pwd)"
TARGET_DIR="$TARGET_PROJECT/.claude"
mkdir -p "$TARGET_DIR/agents"
mkdir -p "$TARGET_DIR/commands"
mkdir -p "$TARGET_DIR/skills"
mkdir -p "$TARGET_DIR/rules"
mkdir -p "$TARGET_DIR/hooks"
echo " → Target: $TARGET_PROJECT"
echo ""
# List available plugins
echo -e "${GREEN}Step 2: Available Plugins${NC}"
echo ""
declare -a PLUGIN_NAMES
declare -a PLUGIN_PATHS
declare -a PLUGIN_DIRS
declare -a PLUGIN_BASE_DIRS
plugin_num=0
for plugin_json in $PLUGIN_JSON_FILES; do
if [[ -f "$plugin_json" ]]; then
plugin_num=$((plugin_num + 1))
plugin_name=$(jq -r '.name' "$plugin_json" 2>/dev/null || echo "unknown")
plugin_desc=$(jq -r '.description' "$plugin_json" 2>/dev/null || echo "")
num_agents=$(jq -r '.agents | length' "$plugin_json" 2>/dev/null || echo "0")
num_commands=$(jq -r '.commands | length' "$plugin_json" 2>/dev/null || echo "0")
num_skills=$(jq -r '.skills | length' "$plugin_json" 2>/dev/null || echo "0")
num_rules=$(jq -r '.rules | length' "$plugin_json" 2>/dev/null || echo "0")
PLUGIN_NAMES[$plugin_num]="$plugin_name"
PLUGIN_PATHS[$plugin_num]="$plugin_json"
PLUGIN_DIRS[$plugin_num]=$(dirname "$plugin_json")
PLUGIN_BASE_DIRS[$plugin_num]=$(dirname "$(dirname "$plugin_json")")
printf " %2d) ${GREEN}%s${NC}\n" "$plugin_num" "$plugin_name"
echo " $plugin_desc"
echo " Components: $num_agents agents, $num_commands commands, $num_skills skills, $num_rules rules"
echo ""
fi
done
if [[ $plugin_num -eq 0 ]]; then
echo -e "${RED}✗ No plugins found.${NC}"
exit 1
fi
read -p "Select plugins to install (comma-separated numbers, or 'all'): " selected_plugins
echo ""
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BLUE}ℹ Starting Installation...${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
installed_count=0
skipped_count=0
# Register legacy single-file PreToolUse Bash hook in .claude/settings.json
_register_legacy_hook_in_settings() {
local target_dir="$1"
local hook_name="$2"
local settings_file="$target_dir/settings.json"
local hook_command="python3 \"\$CLAUDE_PROJECT_DIR/.claude/hooks/$hook_name\""
if [[ ! -f "$settings_file" ]]; then
cat > "$settings_file" << EOF
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$hook_command"
}
]
}
]
}
}
EOF
echo " ✓ Created .claude/settings.json with legacy hook: $hook_name"
return
fi
python3 - << PYEOF
import json, sys
settings_file = "$settings_file"
hook_command = "$hook_command"
with open(settings_file) as f:
settings = json.load(f)
settings.setdefault("hooks", {})
settings["hooks"].setdefault("PreToolUse", [])
bash_entry = None
for entry in settings["hooks"]["PreToolUse"]:
if entry.get("matcher") == "Bash":
bash_entry = entry
break
if bash_entry is None:
bash_entry = {"matcher": "Bash", "hooks": []}
settings["hooks"]["PreToolUse"].append(bash_entry)
bash_entry.setdefault("hooks", [])
for h in bash_entry["hooks"]:
if h.get("command") == hook_command:
print(" ○ Legacy hook already registered in settings.json")
sys.exit(0)
bash_entry["hooks"].append({"type": "command", "command": hook_command})
with open(settings_file, "w") as f:
json.dump(settings, f, indent=2)
f.write("\n")
print(" ✓ Registered legacy hook in .claude/settings.json: $hook_name")
PYEOF
}
_copy_hook_file() {
local source_file="$1"
local target_dir="$2"
local hook_name
local target_file
hook_name=$(basename "$source_file")
target_file="$target_dir/hooks/$hook_name"
if [[ -f "$target_file" ]]; then
echo -n " ⚠ $hook_name already exists. [O]verwrite, [S]kip? "
read -n 1 conflict_action
echo ""
case $conflict_action in
O|o)
cp "$source_file" "$target_file"
chmod +x "$target_file"
echo " ✓ Overwritten: $hook_name"
installed_count=$((installed_count + 1))
return 0
;;
*)
echo " ○ Skipped: $hook_name"
skipped_count=$((skipped_count + 1))
return 1
;;
esac
fi
cp "$source_file" "$target_file"
chmod +x "$target_file"
echo " ✓ Hook file: $hook_name"
installed_count=$((installed_count + 1))
return 0
}
_register_hooks_config_in_settings() {
local target_dir="$1"
local hooks_config_file="$2"
local settings_file="$target_dir/settings.json"
python3 - << PYEOF
import json
from pathlib import Path
settings_file = Path("$settings_file")
hooks_file = Path("$hooks_config_file")
if settings_file.exists():
with settings_file.open() as f:
settings = json.load(f)
else:
settings = {}
with hooks_file.open() as f:
hook_config = json.load(f)
settings.setdefault("hooks", {})
for event_name, matcher_entries in hook_config.get("hooks", {}).items():
target_entries = settings["hooks"].setdefault(event_name, [])
for matcher_entry in matcher_entries:
normalized_entry = json.loads(json.dumps(matcher_entry))
for hook in normalized_entry.get("hooks", []):
command = hook.get("command")
if isinstance(command, str):
hook["command"] = command.replace(
"${CLAUDE_PLUGIN_ROOT}",
"$CLAUDE_PROJECT_DIR/.claude"
)
if normalized_entry not in target_entries:
target_entries.append(normalized_entry)
with settings_file.open("w") as f:
json.dump(settings, f, indent=2)
f.write("\n")
PYEOF
echo " ✓ Registered hooks config in .claude/settings.json: $(basename "$hooks_config_file")"
}
# Install selected plugins
for ((i=1; i<=plugin_num; i++)); do
should_install=0
if [[ "$selected_plugins" == "all" ]]; then
should_install=1
else
# Check if current plugin number is in selected list
for num in $(echo "$selected_plugins" | tr ',' ' '); do
if [[ "$num" == "$i" ]]; then
should_install=1
break
fi
done
fi
if [[ "$should_install" == "1" ]]; then
plugin_json="${PLUGIN_PATHS[$i]}"
base_dir="${PLUGIN_BASE_DIRS[$i]}"
plugin_name="${PLUGIN_NAMES[$i]}"
echo ""
echo -e "${CYAN}Installing from: $plugin_name${NC}"
# Install agents
agents=$(jq -r '.agents[]? // empty' "$plugin_json" 2>/dev/null)
if [[ -n "$agents" ]]; then
for agent in $agents; do
agent_path="$base_dir/$agent"
if [[ -f "$agent_path" ]]; then
agent_name=$(basename "$agent")
target_file="$TARGET_DIR/agents/$agent_name"
if [[ -f "$target_file" ]]; then
echo -n " ⚠ $agent_name already exists. [O]verwrite, [S]kip, [R]ename? "
read -n 1 conflict_action
echo ""
case $conflict_action in
O|o)
cp "$agent_path" "$target_file"
echo " ✓ Overwritten: $agent_name"
installed_count=$((installed_count + 1))
;;
R|r)
read -p " Enter new name: " new_name
cp "$agent_path" "$TARGET_DIR/agents/$new_name.md"
echo " ✓ Installed as: $new_name.md"
installed_count=$((installed_count + 1))
;;
*)
echo " ○ Skipped: $agent_name"
skipped_count=$((skipped_count + 1))
;;
esac
else
cp "$agent_path" "$target_file"
echo " ✓ Agent: $agent_name"
installed_count=$((installed_count + 1))
fi
fi
done
fi
# Install commands
commands=$(jq -r '.commands[]? // empty' "$plugin_json" 2>/dev/null)
if [[ -n "$commands" ]]; then
for cmd in $commands; do
cmd_path="$base_dir/$cmd"
if [[ -f "$cmd_path" ]]; then
cmd_name=$(basename "$cmd")
cmd_subdir=$(dirname "$cmd")
cmd_subdir_rel=""
if [[ "$cmd_subdir" != "." ]]; then
cmd_subdir_rel=$(echo "$cmd_subdir" | sed 's|^\./commands||' | sed 's|^\./commands/||')
if [[ -n "$cmd_subdir_rel" ]]; then
mkdir -p "$TARGET_DIR/commands/$cmd_subdir_rel"
target_file="$TARGET_DIR/commands/$cmd_subdir_rel/$cmd_name"
else
target_file="$TARGET_DIR/commands/$cmd_name"
fi
else
target_file="$TARGET_DIR/commands/$cmd_name"
fi
if [[ -f "$target_file" ]]; then
echo -n " ⚠ $cmd_name already exists. [O]verwrite, [S]kip, [R]ename? "
read -n 1 conflict_action
echo ""
case $conflict_action in
O|o)
cp "$cmd_path" "$target_file"
echo " ✓ Overwritten: $cmd_name"
installed_count=$((installed_count + 1))
;;
R|r)
read -p " Enter new name: " new_name
if [[ -n "$cmd_subdir_rel" ]]; then
cp "$cmd_path" "$TARGET_DIR/commands/$cmd_subdir_rel/$new_name.md"
else
cp "$cmd_path" "$TARGET_DIR/commands/$new_name.md"
fi
echo " ✓ Installed as: $new_name.md"
installed_count=$((installed_count + 1))
;;
*)
echo " ○ Skipped: $cmd_name"
skipped_count=$((skipped_count + 1))
;;
esac
else
cp "$cmd_path" "$target_file"
echo " ✓ Command: $cmd_name"
installed_count=$((installed_count + 1))
fi
fi
done
fi
# Install skills
skills=$(jq -r '.skills[]? // empty' "$plugin_json" 2>/dev/null)
if [[ -n "$skills" ]]; then
for skill_pattern in $skills; do
for skill_dir in $base_dir/$skill_pattern; do
if [[ -d "$skill_dir" ]]; then
skill_name=$(basename "$skill_dir")
target_skill_dir="$TARGET_DIR/skills/$skill_name"
if [[ -d "$target_skill_dir" ]]; then
echo -n " ⚠ $skill_name already exists. [O]verwrite, [S]kip, [R]ename? "
read -n 1 conflict_action
echo ""
case $conflict_action in
O|o)
rm -rf "$target_skill_dir"
cp -r "$skill_dir" "$target_skill_dir"
echo " ✓ Overwritten: $skill_name"
installed_count=$((installed_count + 1))
;;
R|r)
read -p " Enter new name: " new_name
cp -r "$skill_dir" "$TARGET_DIR/skills/$new_name"
echo " ✓ Installed as: $new_name"
installed_count=$((installed_count + 1))
;;
*)
echo " ○ Skipped: $skill_name"
skipped_count=$((skipped_count + 1))
;;
esac
else
cp -r "$skill_dir" "$target_skill_dir"
echo " ✓ Skill: $skill_name"
installed_count=$((installed_count + 1))
fi
fi
done
done
fi
# Install rules
rules=$(jq -r '.rules[]? // empty' "$plugin_json" 2>/dev/null)
if [[ -n "$rules" ]]; then
rules_target_dir="$TARGET_DIR/rules/$plugin_name"
mkdir -p "$rules_target_dir"
for rule in $rules; do
rule_path="$base_dir/$rule"
if [[ -f "$rule_path" ]]; then
rule_name=$(basename "$rule")
target_file="$rules_target_dir/$rule_name"
if [[ -f "$target_file" ]]; then
echo -n " ⚠ Rule $rule_name already exists. [O]verwrite, [S]kip? "
read -n 1 conflict_action
echo ""
case $conflict_action in
O|o)
cp "$rule_path" "$target_file"
echo " ✓ Overwritten: $rule_name"
installed_count=$((installed_count + 1))
;;
*)
echo " ○ Skipped: $rule_name"
skipped_count=$((skipped_count + 1))
;;
esac
else
cp "$rule_path" "$target_file"
echo " ✓ Rule: $plugin_name/$rule_name"
installed_count=$((installed_count + 1))
fi
fi
done
fi
# Install hooks
hooks=$(jq -r '
if .hooks == null then empty
elif (.hooks | type) == "array" then .hooks[]
elif (.hooks | type) == "string" then .hooks
else empty
end
' "$plugin_json" 2>/dev/null)
if [[ -n "$hooks" ]]; then
for hook in $hooks; do
hook_path="$base_dir/$hook"
if [[ -f "$hook_path" ]]; then
hook_name=$(basename "$hook_path")
if [[ "$hook_name" == "hooks.json" ]]; then
hook_dir=$(dirname "$hook_path")
for hook_impl in "$hook_dir"/*; do
if [[ -f "$hook_impl" && "$(basename "$hook_impl")" != "hooks.json" ]]; then
_copy_hook_file "$hook_impl" "$TARGET_DIR"
fi
done
_register_hooks_config_in_settings "$TARGET_DIR" "$hook_path"
else
if _copy_hook_file "$hook_path" "$TARGET_DIR"; then
_register_legacy_hook_in_settings "$TARGET_DIR" "$hook_name"
fi
fi
fi
done
fi
fi
done
echo ""
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${GREEN}✓ Installation Complete!${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
echo " Target directory: $TARGET_DIR/"
echo " Files installed: $installed_count"
echo " Files skipped: $skipped_count"
echo ""
echo -e "${YELLOW}Next Steps:${NC}"
echo " 1. Navigate to your project: cd $TARGET_PROJECT"
echo " 2. Start Claude Code in the project directory"
echo " 3. Your skills, agents, and commands are now available!"
echo ""
echo -e "${YELLOW}Usage:${NC}"
echo " - Skills are automatically discovered by Claude"
echo " - Rules are loaded from .claude/rules/ to enforce coding standards"
echo " - Hooks run automatically on tool events (configured in .claude/settings.json)"
echo " - Use @agent-name to invoke agents"
echo " - Use /command-name to run commands"
echo ""docs
plugins
developer-kit-ai
developer-kit-aws
agents
docs
skills
aws
aws-cli-beast
aws-cost-optimization
aws-drawio-architecture-diagrams
aws-sam-bootstrap
aws-cloudformation
aws-cloudformation-auto-scaling
aws-cloudformation-bedrock
aws-cloudformation-cloudfront
aws-cloudformation-cloudwatch
aws-cloudformation-dynamodb
aws-cloudformation-ec2
aws-cloudformation-ecs
aws-cloudformation-elasticache
references
aws-cloudformation-iam
references
aws-cloudformation-lambda
aws-cloudformation-rds
aws-cloudformation-s3
aws-cloudformation-security
aws-cloudformation-task-ecs-deploy-gh
aws-cloudformation-vpc
references
developer-kit-core
agents
commands
skills
developer-kit-devops
developer-kit-java
agents
commands
docs
skills
aws-lambda-java-integration
aws-rds-spring-boot-integration
aws-sdk-java-v2-bedrock
aws-sdk-java-v2-core
aws-sdk-java-v2-dynamodb
aws-sdk-java-v2-kms
aws-sdk-java-v2-lambda
aws-sdk-java-v2-messaging
aws-sdk-java-v2-rds
aws-sdk-java-v2-s3
aws-sdk-java-v2-secrets-manager
clean-architecture
graalvm-native-image
langchain4j-ai-services-patterns
references
langchain4j-mcp-server-patterns
references
langchain4j-rag-implementation-patterns
references
langchain4j-spring-boot-integration
langchain4j-testing-strategies
langchain4j-tool-function-calling-patterns
langchain4j-vector-stores-configuration
references
qdrant
references
spring-ai-mcp-server-patterns
spring-boot-actuator
spring-boot-cache
spring-boot-crud-patterns
spring-boot-dependency-injection
spring-boot-event-driven-patterns
spring-boot-openapi-documentation
spring-boot-project-creator
spring-boot-resilience4j
spring-boot-rest-api-standards
spring-boot-saga-pattern
spring-boot-security-jwt
assets
references
scripts
spring-boot-test-patterns
spring-data-jpa
references
spring-data-neo4j
references
unit-test-application-events
unit-test-bean-validation
unit-test-boundary-conditions
unit-test-caching
unit-test-config-properties
references
unit-test-controller-layer
unit-test-exception-handler
references
unit-test-json-serialization
unit-test-mapper-converter
references
unit-test-parameterized
unit-test-scheduled-async
references
unit-test-service-layer
references
unit-test-utility-methods
unit-test-wiremock-rest-api
references
developer-kit-php
developer-kit-project-management
developer-kit-python
developer-kit-specs
commands
docs
hooks
test-templates
tests
skills
developer-kit-tools
developer-kit-typescript
agents
docs
hooks
rules
skills
aws-cdk
aws-lambda-typescript-integration
better-auth
clean-architecture
drizzle-orm-patterns
dynamodb-toolbox-patterns
references
nestjs
nestjs-best-practices
nestjs-code-review
nestjs-drizzle-crud-generator
nextjs-app-router
nextjs-authentication
nextjs-code-review
nextjs-data-fetching
nextjs-deployment
nextjs-performance
nx-monorepo
react-code-review
react-patterns
shadcn-ui
tailwind-css-patterns
tailwind-design-system
references
turborepo-monorepo
typescript-docs
typescript-security-review
zod-validation-utilities
references
github-spec-kit