
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.
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
- Exit code 2 blocks - Use to prevent bad code from being written
- Fast checks only - Hooks run synchronously; keep under 5 seconds
- JSON stdin/stdout - Hooks receive context, can output structured responses
- Fail safe - Non-zero (except 2) continues execution with warning
- 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
- Filter by extension - Only run checks on relevant files
- Cache dependencies - Avoid npm/pip on every check
- Limit output - Show first 5-10 errors, not all
- Auto-fix when safe - Format instead of block
References
- static-checks.md - Complete hook examples
- events.md - Hook events reference
You Might Also Like
Related Skills

fix
Use when you have lint errors, formatting issues, or before committing code to ensure it passes CI.
facebook
frontend-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
frontend-code-review
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
code-reviewer
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
session-logs
Search and analyze your own session logs (older/parent conversations) using jq.
moltbot
