Hooks
Audience: Customer — this page explains what data Rulecatch captures from your Claude Code sessions.
Rulecatch uses Claude Code hooks to capture AI development events. Hooks run as shell commands outside the AI's context window, adding zero token overhead.
All 14 Hook Events
Rulecatch registers all 14 Claude Code hook types during setup. Each hook fires at a specific point in the AI workflow:
Session Lifecycle
| Hook | Event Type | When It Fires | What It Captures |
|---|---|---|---|
SessionStart |
session_start |
Claude Code session begins | Model, git context, account info, working directory |
SessionEnd |
session_end |
Session concludes | Token deltas, cost estimate, model breakdown, git diff stats |
Tool Lifecycle
| Hook | Event Type | When It Fires | What It Captures |
|---|---|---|---|
PreToolUse |
pre_tool_use |
Before a tool runs | Tool name (used internally for pre-processing) |
PostToolUse |
tool_call |
After a successful tool call | Tool name, file path, I/O size, language, lines changed, git context |
PostToolUseFailure |
tool_call |
After a failed tool call | Tool name, error message, file path (toolSuccess=false) |
PermissionRequest |
permission_request |
Tool requests elevated permissions | Tool name requesting permission |
User Interaction
| Hook | Event Type | When It Fires | What It Captures |
|---|---|---|---|
UserPromptSubmit |
user_prompt |
User sends a message | Prompt length (never prompt content) |
Stop |
session_end |
User exits Claude Code | Final token counts, cost, git diff stats |
Turn & Conversation
| Hook | Event Type | When It Fires | What It Captures |
|---|---|---|---|
Notification |
notification |
System notification occurs | Notification type and message |
PreCompact |
compaction_start |
Conversation context is compressed | Trigger type (auto or manual) |
Subagents & Teams
| Hook | Event Type | When It Fires | What It Captures |
|---|---|---|---|
SubagentStart |
subagent_start |
A subagent is spawned | Agent type |
SubagentStop |
subagent_stop |
A subagent finishes | Agent type |
TeammateIdle |
teammate_idle |
A teammate goes idle | Teammate name |
TaskCompleted |
task_completed |
A task finishes | Task subject |
Data Captured Per Event
session_start
| Field | Source | Description |
|---|---|---|
type |
Set to session_start |
Event type |
sessionId |
Claude Code | Unique session identifier |
model |
Claude Code | AI model being used |
cwd |
System | Working directory (encrypted if privacy enabled) |
gitRepo |
Git | Repository name |
gitBranch |
Git | Current branch |
gitCommit |
Git | Current commit hash |
gitUsername |
Git | Configured git username (encrypted) |
gitEmail |
Git | Configured git email (encrypted) |
timestamp |
System | ISO timestamp |
tool_call (PostToolUse / PostToolUseFailure)
| Field | Source | Description |
|---|---|---|
type |
Set to tool_call |
Event type |
sessionId |
Claude Code | Session identifier |
toolName |
Claude Code (stdin) | Tool name (Read, Write, Edit, Bash, etc.) |
toolSuccess |
Hook logic | true for PostToolUse, false for PostToolUseFailure |
filePath |
Parsed from tool input | File being operated on (encrypted) |
language |
Derived from file extension | Programming language |
toolInputSize |
Calculated | Input data size in bytes |
toolOutputSize |
Calculated | Output data size in bytes |
linesAdded |
Git diff | Lines added (incremental) |
linesRemoved |
Git diff | Lines removed (incremental) |
fileOperation |
Parsed | Type of operation (read/write/edit/etc.) |
model |
Cached from session start | Model name for cost estimation |
activeTimeMs |
Calculated | Time since last event |
timestamp |
System | ISO timestamp |
session_end (Stop / SessionEnd)
| Field | Source | Description |
|---|---|---|
type |
Set to session_end |
Event type |
sessionId |
Claude Code | Session identifier |
inputTokens |
Stats cache delta | Total input tokens for session |
outputTokens |
Stats cache delta | Total output tokens for session |
thinkingTokens |
Stats cache delta | Total thinking tokens |
cacheReadTokens |
Stats cache delta | Cache read tokens |
cacheWriteTokens |
Stats cache delta | Cache write tokens |
estimatedCost |
Calculated | Estimated session cost |
model |
Cached from session start | Primary model used |
modelsBreakdown |
Stats cache | Per-model token/cost breakdown |
linesAdded |
Git diff | Final lines added count |
linesRemoved |
Git diff | Final lines removed count |
timestamp |
System | ISO timestamp |
user_prompt (UserPromptSubmit)
| Field | Source | Description |
|---|---|---|
type |
Set to user_prompt |
Event type |
sessionId |
Claude Code | Session identifier |
promptLength |
Calculated | Character count of user's prompt |
timestamp |
System | ISO timestamp |
Note: Prompt content is never captured — only the length.
turn_complete
| Field | Source | Description |
|---|---|---|
type |
Set to turn_complete |
Event type |
sessionId |
Claude Code | Session identifier |
timestamp |
System | ISO timestamp |
subagent_start / subagent_stop
| Field | Source | Description |
|---|---|---|
type |
subagent_start or subagent_stop |
Event type |
sessionId |
Claude Code | Session identifier |
agentType |
Claude Code | Type of subagent (e.g., "Explore", "Plan") |
timestamp |
System | ISO timestamp |
permission_request
| Field | Source | Description |
|---|---|---|
type |
Set to permission_request |
Event type |
sessionId |
Claude Code | Session identifier |
toolName |
Claude Code | Tool requesting permission |
timestamp |
System | ISO timestamp |
Other event types
notification, teammate_idle, task_completed, and compaction_start follow a similar minimal structure with type, sessionId, timestamp, and type-specific metadata fields.
How Hooks Work
1. Hook Registration
During init, all 14 hooks are registered in ~/.claude/settings.json:
{
"hooks": {
"SessionStart": [{ "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 30 }] }],
"SessionEnd": [{ "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 30 }] }],
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 10, "async": true }] }],
"PreToolUse": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 10, "async": true }] }],
"PostToolUse": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 10, "async": true }] }],
"PostToolUseFailure": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 10, "async": true }] }],
"PermissionRequest": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 10, "async": true }] }],
"Notification": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 10, "async": true }] }],
"SubagentStart": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 10, "async": true }] }],
"SubagentStop": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 10, "async": true }] }],
"Stop": [{ "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 10, "async": true }] }],
"TeammateIdle": [{ "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 10, "async": true }] }],
"TaskCompleted": [{ "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 10, "async": true }] }],
"PreCompact": [{ "hooks": [{ "type": "command", "command": "~/.claude/hooks/rulecatch-track.sh", "timeout": 10, "async": true }] }]
}
}
2. Hook Execution
When Claude Code fires a hook:
- The hook script receives event data via stdin (JSON) and environment variables
- The script extracts relevant fields
- PII fields are encrypted locally (if encryption is configured)
- Creates a JSON buffer file
- Appends to
events.logfor the live monitor - Exits immediately (< 1ms)
3. Buffer File
Each event is written as a separate JSON file:
~/.claude/rulecatch/buffer/<timestamp>-<type>-<random>.json
Example: 1707234567890-tool_call-a3f2b1.json
4. Flush Trigger
After writing the buffer file, the hook checks if the buffer has reached the batch size threshold. If so, it triggers the flush script asynchronously (in the background, without blocking Claude Code).
Model Detection
The model is captured at session_start and cached to a temporary file:
/tmp/rulecatch-model-<SESSION_ID>
This cached model is used in subsequent events when the model isn't directly available from hook context.
Git Diff Stats
Lines added/removed are captured from git diff:
git diff --stat HEAD
This is run incrementally on each tool call, providing real-time code change metrics without waiting for session end.
File Locations
| File | Purpose |
|---|---|
~/.claude/hooks/rulecatch-track.sh |
Main hook script |
~/.claude/hooks/rulecatch-flush.js |
Flush/send script |
~/.claude/rulecatch/buffer/*.json |
Buffered events |
~/.claude/rulecatch/events.log |
Event log (for live monitor) |
~/.claude/rulecatch/flush.log |
Flush activity log |
/tmp/rulecatch-hook.log |
Hook debug log |
/tmp/rulecatch-model-* |
Cached model per session |
Zero Token Guarantee
Hooks add zero tokens because:
- Shell execution — Hooks run as shell commands, completely outside the AI model's context
- No prompt modification — Nothing is added to AI prompts
- No response modification — AI responses pass through unmodified
- Async buffer writes — File I/O doesn't block the AI
- Background flushes — Network calls happen in background processes
Debugging
Check Hook Log
npx @rulecatch/ai-pooler logs --source=hook
Check if Hooks Are Registered
npx @rulecatch/ai-pooler status
# Look for "Hooks config: + All 14/14 registered"
Manual Hook Test
echo '{"tool_name":"Read","tool_input":"/test.ts"}' | bash ~/.claude/hooks/rulecatch-track.sh tool_call
See Also
- AI-Pooler Overview — Full architecture
- Installation — Hook installation process
- Event Schema — Full event field reference