Skip to content
Development
Skill

/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.

From plugin
claude-skills
241183 skills42 agents62 commands2 MCP

Claude Code

$ npx -y skills add secondsky/claude-skills --skill claude-hook-writer --agent claude-code

SKILL.md

claude-hook-writer.SKILL.md
name: claude-hook-writer
description: 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.
metadata:
  version: 2.0.0
  author: Claude Skills Maintainers
  last_verified: 2025-12-17
  optimization_date: 2025-12-17
  token_savings: ~55%
  errors_prevented: 5
license: MIT

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:

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

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

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

# ❌ 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/

Read more
@secondsky
Ships withclaude-skills

145 production-ready skills for Claude Code CLI 🔌 Platform / Harness Support These plugins ship as Claude Code marketplace plugins (.claude-plugin/ manifests) and Codex CLI plugins (.codex-plugin/ manifests).

241183 skills42 agents2 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
241
Star history of secondsky/claude-skills on GitHub, a chart by star-history.com

Other skills on claude-skills.

aceternity-ui

aceternity-ui

100+ animated React components (Aceternity UI) for Next.js with Tailwind. Use for hero sections, parallax, 3D effects, or…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about claude-hook-writer.

Which coding agents can use claude-hook-writer?
claude-hook-writer installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.