create-hooks
from glittercowboy/taches-cc-resources
A collection of my favorite custom Claude Code resources to make life easier.
npx skills add https://github.com/glittercowboy/taches-cc-resources --skill create-hooksSKILL.md
Hooks provide programmatic control over Claude's behavior without modifying core code, enabling project-specific automation, safety checks, and workflow customization.
<quick_start>
- Create hooks config file:
- Project:
.claude/hooks.json - User:
~/.claude/hooks.json
- Project:
- Choose hook event (when it fires)
- Choose hook type (command or prompt)
- Configure matcher (which tools trigger it)
- Test with
claude --debug
.claude/hooks.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \\\"No description\\\")\"' >> ~/.claude/bash-log.txt"
}
]
}
]
}
}
This hook:
- Fires before (
PreToolUse) everyBashtool use - Executes a
command(not an LLM prompt) - Logs command + description to a file
</quick_start>
<hook_types>
| Event | When it fires | Can block? |
|---|---|---|
| PreToolUse | Before tool execution | Yes |
| PostToolUse | After tool execution | No |
| UserPromptSubmit | User submits a prompt | Yes |
| Stop | Claude attempts to stop | Yes |
| SubagentStop | Subagent attempts to stop | Yes |
| SessionStart | Session begins | No |
| SessionEnd | Session ends | No |
| PreCompact | Before context compaction | Yes |
| Notification | Claude needs input | No |
Blocking hooks can return "decision": "block" to prevent the action. See references/hook-types.md for detailed use cases.
</hook_types>
<hook_anatomy> <hook_type name="command"> Type: Executes a shell command
Use when:
- Simple validation (check file exists)
- Logging (append to file)
- External tools (formatters, linters)
- Desktop notifications
Input: JSON via stdin Output: JSON via stdout (optional)
{
"type": "command",
"command": "/path/to/script.sh",
"timeout": 30000
}
</hook_type>
<hook_type name="prompt"> Type: LLM evaluates a prompt
Use when:
- Complex decision logic
- Natural language validation
- Context-aware checks
- Reasoning required
Input: Prompt with $ARGUMENTS placeholder
Output: JSON with decision and reason
{
"type": "prompt",
"prompt": "Evaluate if this command is safe: $ARGUMENTS\n\nReturn JSON: {\"decision\": \"approve\" or \"block\", \"reason\": \"explanation\"}"
}
</hook_type> </hook_anatomy>
{
"matcher": "Bash", // Exact match
"matcher": "Write|Edit", // Multiple tools (regex OR)
"matcher": "mcp__.*", // All MCP tools
"matcher": "mcp__memory__.*" // Specific MCP server
}
No matcher: Hook fires for all tools
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [...] // No matcher - fires on every user prompt
}
]
}
}
<input_output> Hooks receive JSON via stdin with session info, current directory, and event-specific data. Blocking hooks can return JSON to approve/block actions or modify inputs.
Example output (blocking hooks):
{
"decision": "approve" | "block",
"reason": "Why this decision was made"
}
See references/input-output-schemas.md for complete schemas for each hook type. </input_output>
<environment_variables> Available in hook commands:
| Variable | Value |
|---|---|
$CLAUDE_PROJECT_DIR | Project root directory |
${CLAUDE_PLUGIN_ROOT} | Plugin directory (plugin hooks only) |
$ARGUMENTS | Hook input JSON (prompt hooks only) |
Example:
{
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/validate.sh"
}
</environment_variables>
<common_patterns> Desktop notification when input needed:
{
"hooks": {
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude needs input\" with title \"Claude Code\"'"
}
]
}
]
}
}
**Block destru
...