# Hooks and Plugins Customize and extend Claude Code behavior with hooks and plugins. ## Hooks System Hooks are shell commands that execute in response to events. ### Hook Types **Pre-tool hooks**: Execute before tool calls **Post-tool hooks**: Execute after tool calls **User prompt submit hooks**: Execute when user submits prompts ### Configuration Hooks are configured in `.claude/hooks.json`: ```json { "hooks": { "pre-tool": { "bash": "echo 'Running: $TOOL_ARGS'", "write": "./scripts/validate-write.sh" }, "post-tool": { "write": "./scripts/format-code.sh", "edit": "prettier --write $FILE_PATH" }, "user-prompt-submit": "./scripts/validate-request.sh" } } ``` ### Environment Variables Available in hook scripts: **All hooks:** - `$TOOL_NAME`: Name of the tool being called - `$TOOL_ARGS`: JSON string of tool arguments **Post-tool only:** - `$TOOL_RESULT`: Tool execution result **User-prompt-submit only:** - `$USER_PROMPT`: User's prompt text ### Hook Examples #### Pre-tool: Security Validation ```bash #!/bin/bash # .claude/scripts/validate-bash.sh # Block dangerous commands if echo "$TOOL_ARGS" | grep -E "rm -rf /|format|mkfs"; then echo "❌ Dangerous command blocked" exit 1 fi echo "✓ Command validated" ``` **Configuration:** ```json { "hooks": { "pre-tool": { "bash": "./.claude/scripts/validate-bash.sh" } } } ``` #### Post-tool: Auto-format ```bash #!/bin/bash # .claude/scripts/format-code.sh # Extract file path from tool args FILE_PATH=$(echo "$TOOL_ARGS" | jq -r '.file_path') # Format based on file type case "$FILE_PATH" in *.js|*.ts|*.jsx|*.tsx) prettier --write "$FILE_PATH" ;; *.py) black "$FILE_PATH" ;; *.go) gofmt -w "$FILE_PATH" ;; esac ``` **Configuration:** ```json { "hooks": { "post-tool": { "write": "./.claude/scripts/format-code.sh", "edit": "./.claude/scripts/format-code.sh" } } } ``` #### User-prompt-submit: Cost Tracking ```bash #!/bin/bash # .claude/scripts/track-usage.sh # Log prompt echo "$(date): $USER_PROMPT" >> .claude/usage.log # Estimate tokens (rough) TOKEN_COUNT=$(echo "$USER_PROMPT" | wc -w) echo "Estimated tokens: $TOKEN_COUNT" ``` **Configuration:** ```json { "hooks": { "user-prompt-submit": "./.claude/scripts/track-usage.sh" } } ``` ### Hook Best Practices **Performance**: Keep hooks fast (<100ms) **Reliability**: Handle errors gracefully **Security**: Validate all inputs **Logging**: Log important actions **Testing**: Test hooks thoroughly ### Hook Errors When a hook fails: - Pre-tool hook failure blocks tool execution - Post-tool hook failure is logged but doesn't block - User can configure strict mode to block on all failures ## Plugins System Plugins are packaged collections of extensions. ### Plugin Structure ``` my-plugin/ ├── plugin.json # Plugin metadata ├── commands/ # Slash commands │ ├── my-command.md │ └── another-command.md ├── skills/ # Agent skills │ └── my-skill/ │ ├── skill.md │ └── skill.json ├── hooks/ # Hook scripts │ ├── hooks.json │ └── scripts/ ├── mcp/ # MCP server configurations │ └── mcp.json └── README.md # Documentation ``` ### plugin.json ```json { "name": "my-plugin", "version": "1.0.0", "description": "Plugin description", "author": "Your Name", "homepage": "https://github.com/user/plugin", "license": "MIT", "commands": ["commands/*.md"], "skills": ["skills/*/"], "hooks": "hooks/hooks.json", "mcpServers": "mcp/mcp.json", "dependencies": { "node": ">=18.0.0" } } ``` ### Installing Plugins #### From GitHub ```bash claude plugin install gh:username/repo claude plugin install gh:username/repo@v1.0.0 ``` #### From npm ```bash claude plugin install npm:package-name claude plugin install npm:@scope/package-name ``` #### From Local Path ```bash claude plugin install ./path/to/plugin claude plugin install ~/plugins/my-plugin ``` #### From URL ```bash claude plugin install https://example.com/plugin.zip ``` ### Managing Plugins #### List Installed Plugins ```bash claude plugin list ``` #### Update Plugin ```bash claude plugin update my-plugin claude plugin update --all ``` #### Uninstall Plugin ```bash claude plugin uninstall my-plugin ``` #### Enable/Disable Plugin ```bash claude plugin disable my-plugin claude plugin enable my-plugin ``` ### Creating Plugins #### Initialize Plugin ```bash mkdir my-plugin cd my-plugin ``` #### Create plugin.json ```json { "name": "my-plugin", "version": "1.0.0", "description": "My awesome plugin", "author": "Your Name", "commands": ["commands/*.md"], "skills": ["skills/*/"] } ``` #### Add Components ```bash # Add slash command mkdir -p commands cat > commands/my-command.md < skills/my-skill/skill.json <