Skip to content
Back to skills

2492 Hook Lifecycle 07cd37ab

ASecurity

Claude Code hooks execute at specific lifecycle events during conversations and tool usage.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
toolspythongobashdebugginggitapisecurityperformance

Works with

  • claude code
  • api

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 2492-hook-lifecycle_07cd37ab --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 2492 Hook Lifecycle 07cd37ab?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 2492 Hook Lifecycle 07cd37ab
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-2492-hook-lifecycle-07cd37ab/badge)](https://www.skillsdirectory.com/skills/tools-only-2492-hook-lifecycle-07cd37ab)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Hook Lifecycle

Claude Code hooks execute at specific lifecycle events during conversations and tool usage.

## Hook Events

| Event | When It Fires | Common Use Cases |
|-------|--------------|------------------|
| **PreToolUse** | Before a tool executes | Validation, blocking dangerous operations |
| **PostToolUse** | After a tool executes | Formatting, quality checks, notifications |
| **UserPromptSubmit** | User submits a prompt | Context injection, logging |
| **Stop** | Conversation ends | Cleanup, final backups |
| **PermissionRequest** | Claude requests permission | Custom approval workflows |

### Additional Events

| Event | Description |
|-------|-------------|
| **Start** | Conversation begins |
| **ToolUseApproved** | User approves tool execution |
| **ToolUseDenied** | User denies tool execution |
| **ToolUsePartialFailure** | Some parallel tools failed |
| **AgentSpawn** | Subagent spawned |
| **AgentFinish** | Subagent completed |
| **Notification** | Claude sends notification |

## Event Flow

```
User submits prompt
  ↓
[UserPromptSubmit hooks]
  ↓
Claude generates response with tool calls
  ↓
[PreToolUse hooks] ← Can block here (exit 2)
  ↓
Tool executes (if not blocked)
  ↓
[PostToolUse hooks] ← Can warn here (exit 1)
  ↓
Response shown to user
```

## I/O Schema

### Input (stdin)

Hooks receive JSON via stdin:

```json
{
  "event": "PreToolUse",
  "tool_name": "Edit",
  "tool_input": {
    "file_path": "/path/to/file.md",
    "old_string": "original text",
    "new_string": "updated text"
  },
  "conversation_id": "abc123",
  "timestamp": "2026-02-12T10:30:00Z"
}
```

### Output (stdout)

Hooks output JSON to stdout:

```json
{
  "decision": "block",
  "reason": "File contains API keys",
  "message": "Additional context for user"
}
```

**Decision values:**
- `"allow"` — Continue normal operation
- `"block"` — Prevent tool execution (PreToolUse only)
- `"warn"` — Show warning but continue

**Exit codes must match decision:**
- Exit 0 → allow
- Exit 1 → warn
- Exit 2 → block

## PreToolUse Hooks

### Purpose
Validate tool inputs before execution. Can block dangerous operations.

### Input Schema

```json
{
  "event": "PreToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/.env",
    "content": "API_KEY=secret123"
  }
}
```

### Blocking Example

```python
import json
import sys

input_data = json.loads(sys.stdin.read())

if input_data["tool_input"]["file_path"].endswith(".env"):
    output = {
        "decision": "block",
        "reason": "Cannot edit .env files"
    }
    print(json.dumps(output))
    sys.exit(2)  # MUST exit 2 to block

sys.exit(0)
```

## PostToolUse Hooks

### Purpose
Process results after tool execution. Can warn but not block.

### Input Schema

```json
{
  "event": "PostToolUse",
  "tool_name": "Edit",
  "tool_input": {
    "file_path": "/path/to/note.md"
  },
  "tool_output": {
    "success": true
  }
}
```

### Warning Example

```python
import json
import sys

input_data = json.loads(sys.stdin.read())

# Check file after edit
with open(input_data["tool_input"]["file_path"]) as f:
    content = f.read()

if "TODO" in content:
    output = {
        "decision": "allow",
        "message": "⚠️ File contains TODO items"
    }
    print(json.dumps(output))
    sys.exit(1)  # Exit 1 for warning

sys.exit(0)
```

## UserPromptSubmit Hooks

### Purpose
Process user prompts before Claude responds. Can inject context.

### Input Schema

```json
{
  "event": "UserPromptSubmit",
  "prompt": "Create a new project note",
  "conversation_id": "abc123"
}
```

### Context Injection Example

```python
import json
import sys

input_data = json.loads(sys.stdin.read())

if "project" in input_data["prompt"].lower():
    output = {
        "decision": "allow",
        "context": "Use Project - prefix for project notes"
    }
    print(json.dumps(output))

sys.exit(0)
```

## Stop Hooks

### Purpose
Cleanup or final operations when conversation ends.

### Input Schema

```json
{
  "event": "Stop",
  "conversation_id": "abc123",
  "timestamp": "2026-02-12T11:00:00Z"
}
```

### Cleanup Example

```python
import json
import sys
import subprocess

# Final backup on conversation end
subprocess.run(["git", "add", "-A"])
subprocess.run(["git", "commit", "-m", "Session complete"])

sys.exit(0)
```

## Exit Code Behaviour

| Exit Code | Decision | PreToolUse | PostToolUse | Other Events |
|-----------|----------|------------|-------------|--------------|
| **0** | Allow | Tool executes | Continue | Continue |
| **1** | Warn | ⚠️ Not valid | Show warning | Show message |
| **2** | Block | Tool blocked | ⚠️ Not valid | ⚠️ Not valid |

**Critical rules:**
- PreToolUse: Use exit 2 to block
- PostToolUse: Use exit 1 to warn (cannot block)
- All events: Exit 0 for success

## Error Handling

If a hook crashes or outputs invalid JSON:
- Claude Code logs the error
- The tool continues as if hook returned exit 0
- User sees a notification about hook failure

**Best practice:** Always wrap hook logic in try/except and exit 0 on errors you want to ignore.

```python
try:
    # Hook logic here
    pass
except Exception as e:
    # Log error but don't block
    sys.stderr.write(f"Hook error: {e}
")
    sys.exit(0)
```

## Debugging Hooks

### Test hook with sample input

```bash
echo '{
  "event": "PreToolUse",
  "tool_name": "Write",
  "tool_input": {"file_path": "test.md", "content": "test"}
}' | python3 hooks/security/file-protection.py

echo "Exit code: 0"
```

### Check hook output

```bash
output=$(echo '{}' | python3 hooks/quality/frontmatter-validator.py)
echo "$output" | jq .
```

### Enable hook logging

Set environment variable:

```bash
export CLAUDE_HOOK_DEBUG=1
```

Hooks can check this and write to stderr for debugging.

## Performance Considerations

- Hooks run synchronously and block tool execution
- Keep hook execution time under 100ms for good UX
- For expensive operations (backups, analysis), use PostToolUse
- Consider caching (e.g., vault file list) to avoid repeated disk scans

## Further Reading

- [Hook Patterns](./hook-patterns.md) — Common implementation patterns
- [Configuration Reference](./configuration.md) — settings.json syntax
- [README](./README.md) — Hook overview and examples

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.