write-hook

write-hook

Create Claude Code hooks for static analysis and code quality. Provides pre-built linting, formatting, and type-checking hooks. Use when setting up project quality gates, enforcing code standards, or adding pre-commit style checks.

7Star
2Fork
更新于 1/9/2026
SKILL.md
readonly只读
name
write-hook
description

Create Claude Code hooks for static analysis and code quality. Provides pre-built linting, formatting, and type-checking hooks. Use when setting up project quality gates, enforcing code standards, or adding pre-commit style checks.

Hook Creator

Create hooks that enforce code quality through static analysis.

Core Principles

  1. Exit code 2 blocks - Use to prevent bad code from being written
  2. Fast checks only - Hooks run synchronously; keep under 5 seconds
  3. JSON stdin/stdout - Hooks receive context, can output structured responses
  4. Fail safe - Non-zero (except 2) continues execution with warning
  5. Use Python - Wrap shell commands in Python for cross-platform compatibility

Quick Start

Add a static check hook:

python3 scripts/add_hook.py <hook-name> --type <lint|format|typecheck|custom>

Options:

  • --type, -t: Hook template type (default: custom)
  • --path, -p: Output directory (default: .claude/hooks)
  • --event, -e: Hook event (default: PostToolUse)

Hook Structure

.claude/
├── hooks/
│   ├── eslint_check.py       # Linting hook
│   ├── prettier_check.py     # Formatting hook
│   └── typecheck.py          # Type checking hook
└── settings.json             # Hook configuration

Configuration Format

Important: Hooks must be configured in .claude/settings.json (not settings.local.json). The settings.json file is shared with the team via version control, ensuring consistent hook behavior across all collaborators.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [{
          "type": "command",
          "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/eslint_check.py",
          "timeout": 30
        }]
      }
    ]
  }
}

Static Check Patterns

1. Linting (ESLint, Ruff, etc.)

#!/usr/bin/env python3
import json, subprocess, sys

data = json.load(sys.stdin)
file_path = data.get('tool_input', {}).get('file_path', '')

if not file_path.endswith(('.js', '.ts', '.tsx')):
    sys.exit(0)

result = subprocess.run(
    ['npx', 'eslint', '--format', 'compact', file_path],
    capture_output=True, text=True
)

if result.returncode != 0:
    print(f"ESLint errors:\n{result.stdout}", file=sys.stderr)
    sys.exit(2)  # Block the action

2. Formatting Check

#!/usr/bin/env python3
import json, subprocess, sys

data = json.load(sys.stdin)
file_path = data.get('tool_input', {}).get('file_path', '')

result = subprocess.run(
    ['npx', 'prettier', '--check', file_path],
    capture_output=True, text=True
)

if result.returncode != 0:
    # Auto-fix instead of blocking
    subprocess.run(['npx', 'prettier', '--write', file_path])
    print(f"Auto-formatted: {file_path}")

3. Type Checking

#!/usr/bin/env python3
import json, subprocess, sys

data = json.load(sys.stdin)
file_path = data.get('tool_input', {}).get('file_path', '')

if not file_path.endswith(('.ts', '.tsx')):
    sys.exit(0)

result = subprocess.run(
    ['npx', 'tsc', '--noEmit', '--pretty', 'false'],
    capture_output=True, text=True
)

if result.returncode != 0:
    # Filter errors for this file only
    errors = [l for l in result.stdout.split('\n') if file_path in l]
    if errors:
        print('\n'.join(errors[:5]), file=sys.stderr)
        sys.exit(2)

Event Selection Guide

Event Use Case Blocking
PreToolUse Validate before write Yes
PostToolUse Check after write Yes
UserPromptSubmit Add linting context Yes

Exit Codes

Code Meaning Effect
0 Success Continue, stdout shown in verbose
2 Block Action blocked, stderr fed to Claude
Other Warning Continue, stderr shown in verbose

Verification

After creating a hook, verify it works:

# Test with sample input
echo '{"tool_input":{"file_path":"test.ts"}}' | .claude/hooks/your_hook.py
echo $?  # Should be 0 (pass) or 2 (block)

Check:

  • Exit code 0 for valid files, 2 for violations
  • Errors go to stderr, info to stdout

Best Practices

  1. Filter by extension - Only run checks on relevant files
  2. Cache dependencies - Avoid npm/pip on every check
  3. Limit output - Show first 5-10 errors, not all
  4. Auto-fix when safe - Format instead of block

References

You Might Also Like

Related Skills

fix

fix

243Kdev-testing

Use when you have lint errors, formatting issues, or before committing code to ensure it passes CI.

facebook avatarfacebook
获取
peekaboo

peekaboo

179Kdev-testing

Capture and automate macOS UI with the Peekaboo CLI.

openclaw avataropenclaw
获取
frontend-testing

frontend-testing

128Kdev-testing

Generate Vitest + React Testing Library tests for Dify frontend components, hooks, and utilities. Triggers on testing, spec files, coverage, Vitest, RTL, unit tests, integration tests, or write/review test requests.

langgenius avatarlanggenius
获取
frontend-code-review

frontend-code-review

127Kdev-testing

Trigger when the user requests a review of frontend files (e.g., `.tsx`, `.ts`, `.js`). Support both pending-change reviews and focused file reviews while applying the checklist rules.

langgenius avatarlanggenius
获取
code-reviewer

code-reviewer

92Kdev-testing

Use this skill to review code. It supports both local changes (staged or working tree) and remote Pull Requests (by ID or URL). It focuses on correctness, maintainability, and adherence to project standards.

google-gemini avatargoogle-gemini
获取
session-logs

session-logs

90Kdev-testing

Search and analyze your own session logs (older/parent conversations) using jq.

moltbot avatarmoltbot
获取