plugins/claude-code-expert/archive/v7.6.0/skills/hooks-system/SKILL.md
# Claude Code Hooks System Complete reference for the hooks lifecycle system. ## Overview Hooks are user-defined shell commands that execute at specific points in the Claude Code lifecycle. They run synchronously and can modify Claude's behavior by returning structured JSON. ## Hook Types ### All Lifecycle Events | Event | When | Can Block? | |-------|------|-----------| | `SessionStart` | Session begins/resumes | No | | `UserPromptSubmit` | Before processing user prompt | Yes (exit 2) | |
npx skillsauth add markus41/claude plugins/claude-code-expert/archive/v7.6.0/skills/hooks-systemInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Complete reference for the hooks lifecycle system.
Hooks are user-defined shell commands that execute at specific points in the Claude Code lifecycle. They run synchronously and can modify Claude's behavior by returning structured JSON.
| Event | When | Can Block? |
|-------|------|-----------|
| SessionStart | Session begins/resumes | No |
| UserPromptSubmit | Before processing user prompt | Yes (exit 2) |
| PreToolUse | Before tool execution | Yes (exit 2) |
| PostToolUse | After tool succeeds | No |
| PostToolUseFailure | After tool fails | No |
| PermissionRequest | Permission prompt appears | No |
| Notification | User needs attention | No |
| SubagentStart | Sub-agent starts | No |
| SubagentStop | Sub-agent finishes | Yes (continue) |
| TaskCompleted | Task marked complete | No |
| ConfigChange | Config file changed | No |
| TeammateIdle | Agent team teammate going idle | No |
| PreCompact | Before conversation history compacted | No |
| InstructionsLoaded | After CLAUDE.md/rules loaded | No |
| WorktreeCreate | Git worktree created for agent | No |
| WorktreeRemove | Git worktree cleaned up | No |
| SessionEnd | Session terminates | No |
| Stop | Claude about to stop | Yes (continue) |
| Type | Description |
|------|-------------|
| command | Shell script execution |
| http | POST to a URL endpoint |
| prompt | Single-turn LLM evaluation |
| agent | Multi-turn verification with tools |
| Exit Code | Meaning |
|-----------|---------|
| 0 | Proceed (approve). For UserPromptSubmit/SessionStart, stdout added to context |
| 2 | Block action (deny). stderr becomes feedback to Claude |
| Other | Log only (hook failure, tool proceeds normally) |
Fires before a tool is executed. Can approve, deny, or modify the tool call.
Trigger: Before each tool invocation Input (stdin): JSON with tool name and input parameters Output (stdout): JSON with decision
// Input received on stdin
{
"tool_name": "Bash",
"tool_input": {
"command": "rm -rf /tmp/data",
"description": "Delete temporary data"
},
"session_id": "abc123"
}
Response options:
// Approve (proceed normally)
{ "decision": "approve" }
// Deny (block the tool call)
{ "decision": "deny", "reason": "Destructive command blocked" }
// Modify (change the tool input)
{
"decision": "approve",
"tool_input": {
"command": "rm -rf /tmp/data --interactive",
"description": "Delete temporary data (with confirmation)"
}
}
// No output = approve (passthrough)
Fires after a tool completes. Can observe results or modify output.
Trigger: After each tool invocation Input (stdin): JSON with tool name, input, and output
{
"tool_name": "Bash",
"tool_input": {
"command": "npm test"
},
"tool_output": {
"stdout": "All tests passed",
"stderr": "",
"exitCode": 0
},
"session_id": "abc123"
}
Response: Optional JSON to modify what Claude sees.
Fires when Claude wants to notify the user (e.g., task completion).
Trigger: Claude sends a notification Input (stdin): JSON with notification details
{
"message": "Task completed successfully",
"type": "info",
"session_id": "abc123"
}
Use cases: Desktop notifications, Slack messages, sound alerts.
Fires when Claude is about to stop (end of conversation turn).
Trigger: Claude reaches a stopping point Input (stdin): JSON with session context
{
"session_id": "abc123",
"reason": "end_turn",
"message": "I've completed the task."
}
Response: Can force Claude to continue.
// Force continue with additional instructions
{
"decision": "continue",
"message": "Also run the linter before finishing."
}
// Allow stop (default)
{ "decision": "stop" }
Fires when a sub-agent (spawned via Agent tool) is about to stop.
Same schema as Stop but for sub-agents.
Hooks are configured in settings.json (project or user level):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/pre-bash.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/log-tool-use.py"
}
]
}
],
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/notify.sh"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/on-stop.sh"
}
]
}
]
}
}
| Pattern | Matches |
|---------|---------|
| "Bash" | Only Bash tool calls |
| "Read" | Only Read tool calls |
| "Write" | Only Write tool calls |
| "Edit" | Only Edit tool calls |
| "mcp__*" | All MCP tool calls |
| "mcp__filesystem__*" | Specific MCP server tools |
| "*" | All tool calls |
| "" | Default/all (for non-tool hooks) |
#!/bin/bash
# .claude/hooks/security-guard.sh
# Block dangerous bash commands
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
if [ "$TOOL" = "Bash" ]; then
# Block rm -rf on important paths
if echo "$COMMAND" | grep -qE 'rm\s+-rf\s+(/|/home|/etc|/var)'; then
echo '{"decision": "deny", "reason": "Blocked: destructive rm -rf on system path"}'
exit 0
fi
# Block curl piped to bash
if echo "$COMMAND" | grep -qE 'curl.*\|\s*(ba)?sh'; then
echo '{"decision": "deny", "reason": "Blocked: piping curl to shell"}'
exit 0
fi
# Block sudo
if echo "$COMMAND" | grep -qE '^\s*sudo\s'; then
echo '{"decision": "deny", "reason": "Blocked: sudo commands"}'
exit 0
fi
fi
# Approve everything else
echo '{"decision": "approve"}'
#!/bin/bash
# .claude/hooks/log-tool-use.sh
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
echo "$TIMESTAMP | $TOOL" >> .claude/tool-usage.log
#!/bin/bash
# .claude/hooks/notify.sh
INPUT=$(cat)
MESSAGE=$(echo "$INPUT" | jq -r '.message')
# macOS
if command -v osascript &>/dev/null; then
osascript -e "display notification \"$MESSAGE\" with title \"Claude Code\""
fi
# Linux
if command -v notify-send &>/dev/null; then
notify-send "Claude Code" "$MESSAGE"
fi
#!/bin/bash
# .claude/hooks/auto-test.sh
INPUT=$(cat)
# Check if any source files were modified
if git diff --name-only | grep -qE '\.(ts|tsx|js|jsx)$'; then
# Run tests
if ! npm test --silent 2>/dev/null; then
echo '{"decision": "continue", "message": "Tests are failing. Please fix them before stopping."}'
exit 0
fi
fi
echo '{"decision": "stop"}'
#!/bin/bash
# .claude/hooks/lessons-learned-capture.sh
# Capture tool failures to lessons-learned.md
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')
EXIT_CODE=$(echo "$INPUT" | jq -r '.tool_output.exitCode // .tool_output.exit_code // "0"')
ERROR=$(echo "$INPUT" | jq -r '.tool_output.stderr // .error // ""')
if [ "$EXIT_CODE" != "0" ] && [ -n "$ERROR" ]; then
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
TOOL_INPUT=$(echo "$INPUT" | jq -r '.tool_input | tostring' | head -c 200)
cat >> .claude/rules/lessons-learned.md << EOF
### Error: ${TOOL} failure (${TIMESTAMP})
- **Tool:** ${TOOL}
- **Input:** \`${TOOL_INPUT}\`
- **Error:** ${ERROR}
- **Status:** NEEDS_FIX
EOF
fi
development
Enhanced plan-authoring skill with Pre-Writing context gathering, task metadata, non-TDD templates, Red Flags, telemetry, and an automated plan linter. Use when you have a spec or requirements for a multi-step task, before touching code.
tools
Documentation intelligence engine with graph-based API docs, algorithm library, and drift detection
tools
Ultraplan cloud planning — kick off a plan in the cloud from your terminal, review and revise in the browser, then execute remotely or send back to CLI
tools
--- name: mcp description: Configure MCP servers for Claude Code — stdio vs HTTP, authentication, Tools/Resources/Prompts distinction, channels (CI webhook, mobile relay, Discord bridge, fakechat), and cost of always-loaded tools. Use this skill whenever adding an MCP server, debugging connection issues, choosing between MCP Tools vs Prompts vs Resources, installing channel servers, or managing .mcp.json. Triggers on: "MCP server", "mcp config", "add Obsidian MCP", "install context7", "channels"