claude-code-tracker/docs/hook-setup.md
Ryan Malloy 44ed9936b7 Initial commit: Claude Code Project Tracker
Add comprehensive development intelligence system that tracks:
- Development sessions with automatic start/stop
- Full conversation history with semantic search
- Tool usage and file operation analytics
- Think time and engagement analysis
- Git activity correlation
- Learning pattern recognition
- Productivity insights and metrics

Features:
- FastAPI backend with SQLite database
- Modern web dashboard with interactive charts
- Claude Code hook integration for automatic tracking
- Comprehensive test suite with 100+ tests
- Complete API documentation (OpenAPI/Swagger)
- Privacy-first design with local data storage

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-11 02:59:21 -06:00

10 KiB

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:

{
  "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:

# 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:

    python main.py
    
  2. Verify hooks are working:

    # 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:

    # 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:

    # Validate JSON syntax
    python -m json.tool ~/.config/claude-code/settings.json
    
  2. Verify tracker server is running:

    curl http://localhost:8000/api/projects
    
  3. Check hook command syntax:

    # 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:

# 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:

# Only track in specific directories
if [[ "$PWD" =~ "/projects/" ]]; then
  curl -X POST ...
fi

Error Handling

Add error logging to hooks:

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.