hook-template
Skill80 starsChanged 8 months agoMITView on GitHub
Generate hook script from template. Use when adding a new hook, wiring a PreToolUse/PostToolUse/Stop/Notification hook, or scaffolding hook config for settings.json.
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 63
All hooks receive JSON on stdin.
- Very specific: line 193
Instead of a bash script, use type: "prompt" in settings.json:
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Hook Template Generator
Generate a hook script and configuration based on requirements.
Usage: /hook-template [hook-event] [purpose]
Hook Events
Claude Code defines 33 hook events. The common ones, grouped:
| Group | Events |
| Lifecycle | SessionStart, SessionEnd, Setup |
| Prompt | UserPromptSubmit, UserPromptExpansion |
| Tool | PreToolUse, PostToolUse, PostToolUseFailure, PostToolBatch |
| Permission | PermissionRequest, PermissionDenied |
| Subagent | SubagentStart, SubagentStop |
| Stop | Stop, StopFailure |
| Task | TaskCreated, TaskCompleted |
| Compaction | PreCompact, PostCompact |
| Notification | Notification, MessageDisplay |
| MCP elicitation | Elicitation, ElicitationResult |
| Model | PreModelSwitch, PostModelSwitch |
| Environment | ConfigChange, CwdChanged, DirectoryAdded, FileChanged, InstructionsLoaded, WorktreeCreate, WorktreeRemove, TeammateIdle |
That is all 33 events. See the official Claude Code hooks docs for the full list and each event's payload. The templates below cover the practical 90%.
Hook Config Fields
| Field | Type | Required | Default | Notes |
type | String | Yes | - | command, prompt, http, mcp_tool, or agent |
command | String | If type=command | - | Shell command, or the executable when args is set |
args | Array | No | - | Exec form: no shell, each element is one argument |
prompt | String | If type=prompt/agent | - | Prompt for the model; $ARGUMENTS receives the input JSON |
matcher | String | No | all | Exact names (Edit|Write), *, or a regex; ignored by events without matcher support |
timeout | Integer | No | 600 (command), 30 (prompt), 60 (agent) | Seconds, per hook |
if | String | No | - | Permission-rule filter such as Bash(git *); tool events only |
onFailure | String | No | continue | block makes a hook that cannot run or times out block the action (v2.1.295+) |
async | Boolean | No | false | Command hooks only: run in the background, cannot block |
once | Boolean | No | false | Remove after the first successful run; honored only in skill frontmatter |
statusMessage | String | No | - | Message shown while the hook runs |
type: command (default) and type: prompt (LLM-evaluated) cover most needs.
The http, mcp_tool, and agent entry types also exist for calling an
endpoint, invoking an MCP tool, or dispatching a subagent.
Hook Input (stdin JSON)
All hooks receive JSON on stdin. The event name is in hook_event_name:
{
"session_id": "abc123",
"transcript_path": "/path/to/transcript.jsonl",
"cwd": "/current/working/dir",
"permission_mode": "default",
"hook_event_name": "PreToolUse",
"tool_name": "Write",
"tool_input": { "file_path": "/path/to/file" }
}Decision output cheatsheet
- PreToolUse: return
hookSpecificOutput.permissionDecisionofallow,deny,ask, ordefer(-ponly). Exit code 2 with a stderr message is the shorthand fordeny. The legacy top-level{"decision": "approve" | "block"}is still accepted. - PostToolUse: Bash output arrives as
tool_response(stdout,stderr,interrupted,isImage). - Prompt / agent hooks: the model answers
{"ok": true}or{"ok": false, "reason": "..."}. - Stop / SubagentStop: to continue the loop, return
{"decision": "block", "reason": "<next prompt>"}— the key isreason. - Silent success is exit
0with no output.
Process
- Gather Requirements
- Hook event
- Purpose
- Matcher (for tool events: tool name, regex, or
*)
- Generate Script at
.claude/hooks/[name].sh - Update settings.json with hook config
- Make Executable:
chmod +x - Validate with
/hooks-check
Templates
PreToolUse (Blocker, exit-code shorthand)
#!/bin/bash
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# Block edits to specific files
if [[ "$FILE" == *"package-lock.json"* ]]; then
echo "BLOCKED: Do not edit lockfiles directly" >&2
exit 2 # exit 2 = deny for PreToolUse
fi
exit 0 # Allow (no output needed)PreToolUse (Deny via JSON permissionDecision)
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [[ "$FILE" == *"package-lock.json"* ]]; then
jq -n '{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Do not edit lockfiles directly"
}
}'
exit 0
fi
# permissionDecision may be "allow", "deny", or "ask"
exit 0PreToolUse (Context Adding)
#!/bin/bash
cat > /dev/null # Consume stdin
INFO="This file requires careful review"
jq -n --arg ctx "$INFO" '{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": $ctx
}
}'
exit 0PostToolUse (Logger)
#!/bin/bash
INPUT=$(cat)
# Process and log... (no stdout needed)
exit 0Stop (Auto-Loop)
#!/bin/bash
CHECKPOINT=".auto-loop/checkpoint.json"
if [[ ! -f "$CHECKPOINT" ]]; then
exit 0 # Allow stop
fi
# Block stop to continue loop — key is "reason", used as the next prompt
jq -n --arg reason "Continuing iteration" \
'{"decision": "block", "reason": $reason}'
exit 0SessionStart (Context Load)
#!/bin/bash
cat > /dev/null
# Plain stdout from SessionStart is added to Claude's context
echo "Project context: run the test suite before committing."
exit 0Prompt Hook (LLM-based)
Instead of a bash script, use type: "prompt" in settings.json:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Review the work done: $ARGUMENTS. Respond {\"ok\": true} if complete, or {\"ok\": false, \"reason\": \"what remains\"}.",
"timeout": 30
}
]
}
]
}
}Settings.json Format
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/validate.sh",
"timeout": 60
}
]
}
],
"SessionStart": [
{
"matcher": "startup|resume|clear|compact|fork",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/load-context.sh"
}
]
}
]
}
}Example
/hook-template PreToolUse "block edits to package-lock.json"
Creates:
- .claude/hooks/protect-lockfile.sh
- Updates .claude/settings.jsonIn this repository36 other files it gives its agents.
- .github/copilot-instructions.mdCopilot instructions
- changelog-observerSkill
- agent-checkSkill
- agentsSkill
- agent-templateSkill
- auto-loopSkill
- changelogSkill
- check-environmentSkill
- claude-md-checkSkill
- claude-md-templateSkill
- code-reviewerSkill
- debuggerSkill
- director-modeSkill
- doc-writerSkill
- evolving-loopSkill
- evolving-statusSkill
- focus-problemSkill
- getting-startedSkill
- handoff-claudeSkill
- handoff-codexSkill
- handoff-geminiSkill
- handoff-grokSkill
- hooks-checkSkill
- interop-routerSkill
- mcp-checkSkill
- planSkill
- project-health-checkSkill
- project-initSkill
- session-relaySkill
- skill-checkSkill
- skillsSkill
- skill-templateSkill
- smart-commitSkill
- test-firstSkill
- test-runnerSkill
- workflowSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

