# Claude Code Hook Setup Guide This guide explains how to configure Claude Code hooks to automatically track your development sessions with the Project Tracker API. ## Overview Claude Code hooks are shell commands that execute in response to specific events. We'll configure hooks to send HTTP requests to our tracking API whenever key development events occur. ## Prerequisites 1. **Claude Code Project Tracker** server running on `http://localhost:8000` 2. **curl** or **httpie** available in your shell 3. **jq** for JSON processing (recommended) ## Hook Configuration Location Claude Code hooks are configured in your settings file: - **Linux/macOS**: `~/.config/claude-code/settings.json` - **Windows**: `%APPDATA%\claude-code\settings.json` ## Complete Hook Configuration Add this hooks section to your Claude Code settings: ```json { "hooks": { "SessionStart": [ { "matcher": "startup", "command": "curl -s -X POST http://localhost:8000/api/session/start -H 'Content-Type: application/json' -d '{\"session_type\":\"startup\",\"working_directory\":\"'\"$PWD\"'\",\"git_branch\":\"'$(git branch --show-current 2>/dev/null || echo \"unknown\")'\",\"git_repo\":\"'$(git config --get remote.origin.url 2>/dev/null || echo \"null\")'\",\"environment\":{\"pwd\":\"'\"$PWD\"'\",\"user\":\"'\"$USER\"'\",\"timestamp\":\"'$(date -Iseconds)'\"}}' > /dev/null 2>&1 &" }, { "matcher": "resume", "command": "curl -s -X POST http://localhost:8000/api/session/start -H 'Content-Type: application/json' -d '{\"session_type\":\"resume\",\"working_directory\":\"'\"$PWD\"'\",\"git_branch\":\"'$(git branch --show-current 2>/dev/null || echo \"unknown\")'\",\"git_repo\":\"'$(git config --get remote.origin.url 2>/dev/null || echo \"null\")'\",\"environment\":{\"pwd\":\"'\"$PWD\"'\",\"user\":\"'\"$USER\"'\",\"timestamp\":\"'$(date -Iseconds)'\"}}' > /dev/null 2>&1 &" }, { "matcher": "clear", "command": "curl -s -X POST http://localhost:8000/api/session/start -H 'Content-Type: application/json' -d '{\"session_type\":\"clear\",\"working_directory\":\"'\"$PWD\"'\",\"git_branch\":\"'$(git branch --show-current 2>/dev/null || echo \"unknown\")'\",\"git_repo\":\"'$(git config --get remote.origin.url 2>/dev/null || echo \"null\")'\",\"environment\":{\"pwd\":\"'\"$PWD\"'\",\"user\":\"'\"$USER\"'\",\"timestamp\":\"'$(date -Iseconds)'\"}}' > /dev/null 2>&1 &" } ], "UserPromptSubmit": [ { "command": "echo '{\"session_id\":1,\"timestamp\":\"'$(date -Iseconds)'\",\"user_prompt\":\"'\"$CLAUDE_USER_PROMPT\"'\",\"exchange_type\":\"user_prompt\"}' | curl -s -X POST http://localhost:8000/api/conversation -H 'Content-Type: application/json' -d @- > /dev/null 2>&1 &" } ], "Notification": [ { "command": "curl -s -X POST http://localhost:8000/api/waiting/start -H 'Content-Type: application/json' -d '{\"session_id\":1,\"timestamp\":\"'$(date -Iseconds)'\",\"context_before\":\"Claude is waiting for input\"}' > /dev/null 2>&1 &" } ], "PostToolUse": [ { "matcher": "Edit", "command": "echo '{\"session_id\":1,\"tool_name\":\"Edit\",\"action\":\"file_edit\",\"file_path\":\"'\"$CLAUDE_TOOL_FILE_PATH\"'\",\"timestamp\":\"'$(date -Iseconds)'\",\"metadata\":{\"success\":true},\"success\":true}' | curl -s -X POST http://localhost:8000/api/activity -H 'Content-Type: application/json' -d @- > /dev/null 2>&1 &" }, { "matcher": "Write", "command": "echo '{\"session_id\":1,\"tool_name\":\"Write\",\"action\":\"file_write\",\"file_path\":\"'\"$CLAUDE_TOOL_FILE_PATH\"'\",\"timestamp\":\"'$(date -Iseconds)'\",\"metadata\":{\"success\":true},\"success\":true}' | curl -s -X POST http://localhost:8000/api/activity -H 'Content-Type: application/json' -d @- > /dev/null 2>&1 &" }, { "matcher": "Read", "command": "echo '{\"session_id\":1,\"tool_name\":\"Read\",\"action\":\"file_read\",\"file_path\":\"'\"$CLAUDE_TOOL_FILE_PATH\"'\",\"timestamp\":\"'$(date -Iseconds)'\",\"metadata\":{\"success\":true},\"success\":true}' | curl -s -X POST http://localhost:8000/api/activity -H 'Content-Type: application/json' -d @- > /dev/null 2>&1 &" }, { "matcher": "Bash", "command": "echo '{\"session_id\":1,\"tool_name\":\"Bash\",\"action\":\"command_execution\",\"timestamp\":\"'$(date -Iseconds)'\",\"metadata\":{\"command\":\"'\"$CLAUDE_BASH_COMMAND\"'\",\"success\":true},\"success\":true}' | curl -s -X POST http://localhost:8000/api/activity -H 'Content-Type: application/json' -d @- > /dev/null 2>&1 &" }, { "matcher": "Grep", "command": "echo '{\"session_id\":1,\"tool_name\":\"Grep\",\"action\":\"search\",\"timestamp\":\"'$(date -Iseconds)'\",\"metadata\":{\"pattern\":\"'\"$CLAUDE_GREP_PATTERN\"'\",\"success\":true},\"success\":true}' | curl -s -X POST http://localhost:8000/api/activity -H 'Content-Type: application/json' -d @- > /dev/null 2>&1 &" }, { "matcher": "Glob", "command": "echo '{\"session_id\":1,\"tool_name\":\"Glob\",\"action\":\"file_search\",\"timestamp\":\"'$(date -Iseconds)'\",\"metadata\":{\"pattern\":\"'\"$CLAUDE_GLOB_PATTERN\"'\",\"success\":true},\"success\":true}' | curl -s -X POST http://localhost:8000/api/activity -H 'Content-Type: application/json' -d @- > /dev/null 2>&1 &" }, { "matcher": "Task", "command": "echo '{\"session_id\":1,\"tool_name\":\"Task\",\"action\":\"subagent_call\",\"timestamp\":\"'$(date -Iseconds)'\",\"metadata\":{\"task_type\":\"'\"$CLAUDE_TASK_TYPE\"'\",\"success\":true},\"success\":true}' | curl -s -X POST http://localhost:8000/api/activity -H 'Content-Type: application/json' -d @- > /dev/null 2>&1 &" } ], "Stop": [ { "command": "echo '{\"session_id\":1,\"timestamp\":\"'$(date -Iseconds)'\",\"claude_response\":\"Response completed\",\"exchange_type\":\"claude_response\"}' | curl -s -X POST http://localhost:8000/api/conversation -H 'Content-Type: application/json' -d @- > /dev/null 2>&1 && curl -s -X POST http://localhost:8000/api/waiting/end -H 'Content-Type: application/json' -d '{\"session_id\":1,\"timestamp\":\"'$(date -Iseconds)'\"}' > /dev/null 2>&1 &" } ] } } ``` ## Simplified Hook Configuration For easier setup, you can use our provided configuration file: ```bash # Copy the hook configuration to Claude Code settings cp config/claude-hooks.json ~/.config/claude-code/ ``` ## Hook Details ### SessionStart Hooks Triggered when starting Claude Code or resuming a session: - **startup**: Fresh start of Claude Code - **resume**: Resuming after --resume flag - **clear**: Starting after clearing history **Data Captured:** - Working directory - Git branch and repository - System environment info - Session type ### UserPromptSubmit Hook Triggered when you submit a prompt to Claude: **Data Captured:** - Your input message - Timestamp - Session context ### Notification Hook Triggered when Claude is waiting for input: **Data Captured:** - Wait start time - Context before waiting ### PostToolUse Hooks Triggered after successful tool execution: **Tools Tracked:** - **Edit/Write**: File modifications - **Read**: File examinations - **Bash**: Command executions - **Grep/Glob**: Search operations - **Task**: Subagent usage **Data Captured:** - Tool name and action - Target files - Success/failure status - Tool-specific metadata ### Stop Hook Triggered when Claude finishes responding: **Data Captured:** - Response completion - End of waiting period - Session activity summary ## Testing Hook Configuration 1. **Start the tracker server:** ```bash python main.py ``` 2. **Verify hooks are working:** ```bash # Check server logs for incoming requests tail -f tracker.log # Test a simple operation in Claude Code # You should see API calls in the logs ``` 3. **Manual hook testing:** ```bash # Test session start hook curl -X POST http://localhost:8000/api/session/start \ -H 'Content-Type: application/json' \ -d '{"session_type":"startup","working_directory":"'$(pwd)'"}' ``` ## Environment Variables The hooks can use these Claude Code environment variables: - `$CLAUDE_USER_PROMPT` - User's input message - `$CLAUDE_TOOL_FILE_PATH` - File path for file operations - `$CLAUDE_BASH_COMMAND` - Bash command being executed - `$CLAUDE_GREP_PATTERN` - Search pattern for Grep - `$CLAUDE_GLOB_PATTERN` - File pattern for Glob - `$CLAUDE_TASK_TYPE` - Type of Task/subagent ## Troubleshooting ### Hooks Not Firing 1. **Check Claude Code settings syntax:** ```bash # Validate JSON syntax python -m json.tool ~/.config/claude-code/settings.json ``` 2. **Verify tracker server is running:** ```bash curl http://localhost:8000/api/projects ``` 3. **Check hook command syntax:** ```bash # Test commands manually in shell echo "Testing hook command..." ``` ### Missing Data 1. **Session ID issues**: The static `session_id: 1` in examples needs dynamic generation 2. **JSON escaping**: Special characters in prompts/paths may break JSON 3. **Network issues**: Hooks may fail if server is unreachable ### Performance Impact - Hooks run asynchronously (`&` at end of commands) - Failed hook calls don't interrupt Claude Code operation - Network timeouts are handled gracefully ## Advanced Configuration ### Dynamic Session IDs For production use, implement session ID management: ```bash # Store session ID in temp file CLAUDE_SESSION_FILE="/tmp/claude-session-id" # In SessionStart hook: SESSION_ID=$(curl -s ... | jq -r '.session_id') echo $SESSION_ID > $CLAUDE_SESSION_FILE # In other hooks: SESSION_ID=$(cat $CLAUDE_SESSION_FILE 2>/dev/null || echo "1") ``` ### Conditional Hook Execution Skip tracking for certain directories: ```bash # Only track in specific directories if [[ "$PWD" =~ "/projects/" ]]; then curl -X POST ... fi ``` ### Error Handling Add error logging to hooks: ```bash curl ... 2>> ~/claude-tracker-errors.log || echo "Hook failed: $(date)" >> ~/claude-tracker-errors.log ``` ## Security Considerations - Hooks execute with your shell privileges - API calls are made to localhost only - No sensitive data is transmitted externally - Hook commands are logged in shell history ## Next Steps After setting up hooks: 1. Start using Claude Code normally 2. Check the web dashboard at http://localhost:8000 3. Review captured data and analytics 4. Adjust hook configuration as needed For detailed API documentation, see [API Specification](api-spec.yaml).