Claude Code Hooks
Integration with Claude Code's hook system for event capture.
Overview
Claude Code supports hooks - shell commands that execute in response to events. ClaudeBox uses hooks to capture session data when conversations end or reach milestones.
Hook Types
| Hook | Trigger | Purpose |
|---|---|---|
stop | Session ends | Capture complete conversation |
notification | Milestone reached | Capture progress updates |
Installation
The hooks are installed automatically by the deploy script:
cd ~/repos-meetrhea/claudebox
./deploy.sh
This copies hook scripts to ~/.claude/hooks/:
~/.claude/hooks/
├── stop-inbox-hook.sh
└── notification-inbox-hook.sh
Hook Implementation
stop-inbox-hook.sh
Triggered when a Claude Code session ends:
#!/bin/bash
# Read JSON payload from stdin
read -r payload
# Extract fields
session_id=$(echo "$payload" | jq -r '.session_id')
transcript_path=$(echo "$payload" | jq -r '.transcript_path')
cwd=$(echo "$payload" | jq -r '.cwd')
# Generate event file
event_id=$(uuidgen)
timestamp=$(date -Iseconds)
# Write to inbox
cat > ~/.claude/inbox/claudebox/events/event_${event_id}.json <<EOF
{
"event_id": "$event_id",
"event_type": "stop",
"session_id": "$session_id",
"transcript_path": "$transcript_path",
"cwd": "$cwd",
"timestamp": "$timestamp"
}
EOF
# Always exit 0 to not block Claude Code
exit 0
notification-inbox-hook.sh
Triggered at conversation milestones:
#!/bin/bash
read -r payload
# Similar structure to stop hook
# Used for progress tracking during long sessions
Hook Payload
Claude Code sends JSON payloads to hooks via stdin:
{
"session_id": "abc-123-def-456",
"transcript_path": "/home/user/.claude/projects/myproject/session.jsonl",
"cwd": "/home/user/repos/myproject",
"summary": "Working on authentication feature",
"message_count": 42
}
Design Principles
Silent and Non-blocking
Hooks must:
- Never output to stdout/stderr (would appear in Claude Code)
- Always exit 0 (non-zero blocks Claude Code)
- Execute quickly (async processing preferred)
All errors are logged to ~/.claude/inbox/claudebox/logs/hook-errors.log.
Idempotent Processing
The daemon handles duplicate events gracefully. If the same event is processed twice, it's detected and skipped.
Debugging Hooks
Check hook installation
ls -la ~/.claude/hooks/
Test hook manually
echo '{"session_id":"test","transcript_path":"/tmp/test.jsonl","cwd":"/tmp"}' | \
~/.claude/hooks/stop-inbox-hook.sh
Check for errors
cat ~/.claude/inbox/claudebox/logs/hook-errors.log
Verify events are created
ls ~/.claude/inbox/claudebox/events/
Custom Hooks
You can add custom hooks alongside ClaudeBox hooks. Claude Code executes all hooks in ~/.claude/hooks/ that match the pattern:
*-stop-hook.sh- Session end hooks*-notification-hook.sh- Notification hooks
Example custom hook:
#!/bin/bash
# my-custom-stop-hook.sh
# Send notification when session ends
read -r payload
session_id=$(echo "$payload" | jq -r '.session_id')
# Send to your notification service
curl -s -X POST https://my-service.com/notify \
-d "{\"session\": \"$session_id\"}" \
> /dev/null 2>&1
exit 0
Transcript Format
The transcript_path points to a JSONL file with conversation records:
{"type":"system","content":"You are Claude...","timestamp":"2025-01-01T12:00:00Z"}
{"type":"user","content":"Help me debug this","timestamp":"2025-01-01T12:00:01Z"}
{"type":"assistant","content":"I'll help you...","timestamp":"2025-01-01T12:00:02Z"}
{"type":"tool_use","tool":"Read","input":{"path":"/src/main.py"},"timestamp":"2025-01-01T12:00:03Z"}
{"type":"tool_result","tool_id":"123","output":"...","timestamp":"2025-01-01T12:00:04Z"}
{"type":"summary","content":"Fixed authentication bug","timestamp":"2025-01-01T12:30:00Z"}
The daemon parses this format to extract:
- Messages (user, assistant, system)
- Tool calls and results
- Summaries
- File paths mentioned