Skip to main content
ClaudeWave
Skill169 repo starsupdated 29d ago

claude-hook-writer

Expert guidance for writing secure, reliable, and performant Claude Code hooks - validates design decisions, enforces best practices, and prevents common pitfalls. Use when creating, reviewing, or debugging Claude Code hooks.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/secondsky/claude-skills /tmp/claude-hook-writer && cp -r /tmp/claude-hook-writer/plugins/claude-hook-writer/skills/claude-hook-writer ~/.claude/skills/claude-hook-writer
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Claude Hook Writer

**Status**: Production Ready
**Version**: 2.0.0 (Optimized with progressive disclosure)
**Last Updated**: 2025-12-17

---

## Overview

Expert guidance for writing secure, reliable, and performant Claude Code hooks. This skill validates design decisions, enforces best practices, and prevents common pitfalls.

---

## When to Use This Skill

- Designing a new Claude Code hook
- Reviewing existing hook code
- Debugging hook failures
- Optimizing slow hooks
- Securing hooks that handle sensitive data
- Publishing hooks as PRPM packages

---

## Core Principles

### 1. Security is Non-Negotiable

Hooks execute automatically with user permissions and can read, modify, or delete any file the user can access.

**ALWAYS validate and sanitize all input.** Hooks receive JSON via stdin—never trust it blindly.

**For complete security patterns**: Load `references/security-requirements.md` when implementing validation or securing hooks.

### 2. Reliability Over Features

A hook that works 99% of the time is a broken hook. Edge cases (Unicode filenames, spaces in paths, missing tools) will happen.

**Test with edge cases before deploying.**

**For reliability patterns**: Load `references/reliability-performance.md` when handling errors or edge cases.

### 3. Performance Matters

Hooks block operations. A 5-second hook means Claude waits 5 seconds before continuing.

**Keep hooks fast. Run heavy operations in background.**

**For performance optimization**: Load `references/reliability-performance.md` when optimizing hook speed.

### 4. Fail Gracefully

Missing dependencies, malformed input, and disk errors will occur.

**Handle errors explicitly. Log failures. Return meaningful exit codes.**

---

## Hook Design Checklist

Before writing code, answer these questions:

### What Event Does This Hook Target?

- `PreToolUse` - Before tool execution (modify input, validate, block)
- `PostToolUse` - After tool completes (format, log, cleanup)
- `UserPromptSubmit` - Before user input processes (validate, enhance)
- `SessionStart` - When Claude Code starts (setup, env check)
- `SessionEnd` - When Claude Code exits (cleanup, persist state)
- `Notification` - During alerts (desktop notifications, logging)
- `Stop` / `SubagentStop` - When responses finish (cleanup, summary)
- `PreCompact` - Before context compaction (save important context)

**Common mistake:** Using PostToolUse for validation (too late—tool already ran). Use PreToolUse to block operations.

### Which Tools Should Trigger This Hook?

Be specific. `matcher: "*"` runs on every tool call.

**Good matchers:**
- `"Write"` - Only file writes
- `"Edit|Write"` - File modifications
- `"Bash"` - Shell commands
- `"mcp__github__*"` - All GitHub MCP tools

**Bad matchers:**
- `"*"` - Everything (use only for logging/metrics)

### What Input Does This Hook Need?

Different tools provide different input. Check what's available:

```bash
# PreToolUse / PostToolUse
{
  "input": {
    "file_path": "/path/to/file.ts",     // Read, Write, Edit
    "command": "npm test",                // Bash
    "old_string": "...",                  // Edit
    "new_string": "..."                   // Edit
  }
}
```

**Validate fields exist before using them:**

```bash
FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty')
if [[ -z "$FILE" ]]; then
  echo "No file path provided" >&2
  exit 1
fi
```

### Should This Be a Command Hook or Prompt Hook?

**Command hooks** (`type: "command"`):
- Fast (milliseconds)
- Deterministic
- Good for: formatting, logging, file checks

**Prompt hooks** (`type: "prompt"`):
- Slow (2-10 seconds)
- Context-aware (uses LLM)
- Good for: complex validation, security analysis, intent detection

**Rule of thumb:** Use command hooks unless you need LLM reasoning.

### What Exit Code Communicates Success/Failure?

- `exit 0` - Success (continue operation)
- `exit 2` - Block operation (show error to Claude)
- `exit 1` or other - Non-blocking error (log but continue)

**For PreToolUse hooks:**
- Exit 2 blocks the tool from running
- Exit 0 allows it (optionally with modified input)

**For PostToolUse hooks:**
- Exit codes don't block (tool already ran)
- Use exit 0 for success, 1 for logging errors

---

## Top 5 Pitfalls (Must Know)

### Pitfall #1: Not Quoting Variables

**Error**: Hooks break on filenames with spaces or special characters

**Why**: Unquoted variables split on whitespace

**Example**:
```bash
# ❌ WRONG - breaks on "my file.txt"
cat $FILE
prettier --write $FILE
rm $FILE

# ✅ RIGHT - handles spaces and special chars
cat "$FILE"
prettier --write "$FILE"
rm "$FILE"
```

**Why this matters**: Files with spaces (`"my file.txt"`), Unicode (`"文件.txt"`), or special chars (`"file (1).txt"`) are common.

**For quoting best practices**: Load `references/security-requirements.md` for comprehensive input handling patterns.

---

### Pitfall #2: Trusting Input Without Validation

**Error**: Hook executes on malicious or malformed input

**Why**: Not validating JSON fields before using them

**Example**:
```bash
# ❌ DANGEROUS - no validation
FILE=$(jq -r '.input.file_path')
rm "$FILE"  # Could delete ../../../etc/passwd

# ✅ SAFE - validate first
FILE=$(jq -r '.input.file_path // empty')
[[ -n "$FILE" ]] || exit 1
[[ "$FILE" == "$CLAUDE_PROJECT_DIR"* ]] || exit 2
[[ "$FILE" != *".."* ]] || exit 2
rm "$FILE"
```

**Why this matters**: Prevents path traversal attacks, protects files outside project, prevents malformed input crashes.

**For complete security patterns**: Load `references/security-requirements.md`.

---

### Pitfall #3: Blocking Operations Too Long

**Error**: Hook takes 30+ seconds, blocking Claude

**Why**: Running expensive operations (tests, builds) synchronously in hook

**Example**:
```bash
# ❌ BLOCKS Claude for 30 seconds
npm test
npm run build

# ✅ RUN IN BACKGROUND - returns immediately
(npm test > /tmp/test-results.log 2>&1 &)
(npm run build > /tmp/build.log 2>&1 &)
exit 0
```

**Why this matters**: Slow h
access-control-rbacSkill

Role-based access control (RBAC) with permissions and policies. Use for admin dashboards, enterprise access, multi-tenant apps, fine-grained authorization, or encountering permission hierarchies, role inheritance, policy conflicts.

aceternity-uiSkill

100+ animated React components (Aceternity UI) for Next.js with Tailwind. Use for hero sections, parallax, 3D effects, or encountering animation, shadcn CLI integration errors.

ai-elements-chatbotSkill

shadcn/ui AI chat components for conversational interfaces. Use for streaming chat, tool/function displays, reasoning visualization, or encountering Next.js App Router setup, Tailwind v4 integration, AI SDK v5 migration errors.

ai-sdk-coreSkill

Vercel AI SDK v5 for backend AI (text generation, structured output, tools, agents). Multi-provider. Use for server-side AI or encountering AI_APICallError, AI_NoObjectGeneratedError, streaming failures.

ai-sdk-uiSkill

Vercel AI SDK v5 React hooks (useChat, useCompletion, useObject) for AI chat interfaces. Use for React/Next.js AI apps or encountering parse stream errors, no response, streaming issues.

api-authenticationSkill

Secure API authentication with JWT, OAuth 2.0, API keys. Use for authentication systems, third-party integrations, service-to-service communication, or encountering token management, security headers, auth flow errors.

api-changelog-versioningSkill

Creates comprehensive API changelogs documenting breaking changes, deprecations, and migration strategies for API consumers. Use when managing API versions, communicating breaking changes, or creating upgrade guides.

api-contract-testingSkill

Verifies API contracts between services using consumer-driven contracts, schema validation, and tools like Pact. Use when testing microservices communication, preventing breaking changes, or validating OpenAPI specifications.