brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
hook-authoringCreates and configures Claude Code hooks for lifecycle automation. Covers all 17 hook events, 4 hook types (command, prompt, agent, http), matchers, input/output formats, and exit codes. Follows official Anthropic best practices. USE WHEN: user mentions "hook", "hooks", "auto-format", "pre tool use", "post tool use", "session start", "notification hook", "…
Independent GitHub snapshot · Automated classification · Original documentation governs
name: hook-authoring description: | Creates and configures Claude Code hooks for lifecycle automation. Covers all 17 hook events, 4 hook types (command, prompt, agent, http), matchers, input/output formats, and exit codes. Follows official Anthropic best practices.
USE WHEN: user mentions "hook", "hooks", "auto-format", "pre tool use", "post tool use", "session start", "notification hook", "block command", "validate tool", "lifecycle event", "PostToolUse", "PreToolUse"
skill-authoring;
creating agents - use agent-authoring; webhook endpoints - different concept
allowed-tools: Read, Grep, Glob, Write, EditHooks are deterministic shell commands (or LLM prompts) that execute at specific lifecycle points. They provide guaranteed behavior — not relying on the LLM to choose to run them.
| Location | Scope | Shareable |
|---|---|---|
~/.claude/settings.json | All projects | No |
.claude/settings.json | Single project | Yes (commit) |
.claude/settings.local.json | Single project | No (gitignored) |
| Agent/skill frontmatter | While component active | Yes |
Plugin hooks/hooks.json | When plugin enabled | Yes |
| Type | How it works | Use when |
|---|---|---|
command | Runs shell command, reads stdin JSON, uses exit codes | Deterministic validation, formatting, logging |
prompt | Single-turn LLM call, returns {ok, reason} | Judgment-based decisions without tool access |
agent | Multi-turn subagent with tool access | Verification requiring file reads or commands |
http | POSTs event data to URL endpoint | External service integration, audit logging |
See quick-ref/events-reference.md for full input/output schemas.
| Event | Matcher input | Can block? | Common use |
|---|---|---|---|
SessionStart | startup/resume/clear/compact | No | Re-inject context after compaction |
UserPromptSubmit | (none) | Yes | Validate/transform user input |
PreToolUse | Tool name | Yes | Block commands, validate operations |
PermissionRequest | Tool name | Yes | Auto-allow/deny permissions |
PostToolUse | Tool name | No* | Auto-format files, logging |
PostToolUseFailure | Tool name | No | Error handling |
Notification | Notification type | No | Desktop alerts |
SubagentStart | Agent type | No | Setup before agent runs |
SubagentStop | Agent type | No | Cleanup after agent |
Stop | (none) | Yes | Verify completeness |
ConfigChange | Config source | Yes | Audit, block unauthorized changes |
PreCompact | manual/auto | No | Save context before compaction |
SessionEnd | Exit reason | No | Cleanup |
*PostToolUse Stop hooks can return {"decision": "block"} to keep Claude working.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write",
"timeout": 30
}
]
}
]
}
}
Every hook receives JSON on stdin with common fields + event-specific data:
{
"session_id": "abc123",
"cwd": "/path/to/project",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": { "command": "npm test" }
}
| Exit code | Effect |
|---|---|
0 | Allow — action proceeds. Stdout added to context (SessionStart, UserPromptSubmit) |
2 | Block — action cancelled. Stderr sent to Claude as feedback |
| Other | Allow — stderr logged (visible in verbose mode Ctrl+O) |
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Use rg instead of grep"
}
}
PreToolUse decisions: "allow", "deny", "ask".
{
"PostToolUse": [{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }]
}]
}
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
for pattern in ".env" "package-lock.json" ".git/"; do
if [[ "$FILE" == *"$pattern"* ]]; then
echo "Blocked: matches protected pattern '$pattern'" >&2
exit 2
fi
done
exit 0
{
"SessionStart": [{
"matcher": "compact",
"hooks": [{ "type": "command", "command": "echo 'Reminder: use Bun, not npm. Run tests before commits.'" }]
}]
}
{
"Notification": [{
"matcher": "",
"hooks": [{ "type": "command", "command": "osascript -e 'display notification \"Claude needs attention\" with title \"Claude Code\"'" }]
}]
}
Always check stop_hook_active to avoid loops:
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0 # Let Claude stop
fi
# ... your logic
| Anti-Pattern | Fix |
|---|---|
Shell profile echo breaks JSON | Wrap in if [[ $- == *i* ]] |
| Stop hook without loop guard | Check stop_hook_active field |
| Using PostToolUse to undo actions | Too late — use PreToolUse to block instead |
| Relying on PermissionRequest in headless mode | Doesn't fire in -p mode. Use PreToolUse |
chmod +x)jq for JSON parsing (or Python/Node)stop_hook_active$CLAUDE_PROJECT_DIR