agentleFS
claude-worldclaude-world/director-mode-lite/skills/hook-template/SKILL.md

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
  1. Very specific:

    All hooks receive JSON on stdin.

    line 63
  2. Very specific:

    Instead of a bash script, use type: "prompt" in settings.json:

    line 193

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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:

GroupEvents
LifecycleSessionStart, SessionEnd, Setup
PromptUserPromptSubmit, UserPromptExpansion
ToolPreToolUse, PostToolUse, PostToolUseFailure, PostToolBatch
PermissionPermissionRequest, PermissionDenied
SubagentSubagentStart, SubagentStop
StopStop, StopFailure
TaskTaskCreated, TaskCompleted
CompactionPreCompact, PostCompact
NotificationNotification, MessageDisplay
MCP elicitationElicitation, ElicitationResult
ModelPreModelSwitch, PostModelSwitch
EnvironmentConfigChange, 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

FieldTypeRequiredDefaultNotes
typeStringYes-command, prompt, http, mcp_tool, or agent
commandStringIf type=command-Shell command, or the executable when args is set
argsArrayNo-Exec form: no shell, each element is one argument
promptStringIf type=prompt/agent-Prompt for the model; $ARGUMENTS receives the input JSON
matcherStringNoallExact names (Edit|Write), *, or a regex; ignored by events without matcher support
timeoutIntegerNo600 (command), 30 (prompt), 60 (agent)Seconds, per hook
ifStringNo-Permission-rule filter such as Bash(git *); tool events only
onFailureStringNocontinueblock makes a hook that cannot run or times out block the action (v2.1.295+)
asyncBooleanNofalseCommand hooks only: run in the background, cannot block
onceBooleanNofalseRemove after the first successful run; honored only in skill frontmatter
statusMessageStringNo-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.permissionDecision of allow, deny, ask, or defer (-p only). Exit code 2 with a stderr message is the shorthand for deny. 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 is reason.
  • Silent success is exit 0 with no output.

Process

  1. Gather Requirements
    • Hook event
    • Purpose
    • Matcher (for tool events: tool name, regex, or *)
  2. Generate Script at .claude/hooks/[name].sh
  3. Update settings.json with hook config
  4. Make Executable: chmod +x
  5. 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 0

PreToolUse (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 0

PostToolUse (Logger)

#!/bin/bash
INPUT=$(cat)
# Process and log... (no stdout needed)
exit 0

Stop (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 0

SessionStart (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 0

Prompt 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.json

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.