agentsclimarketplace

Hook development

Skill cmtkdot/claude-development/skills/hook-development

Use when creating hooks, configuring hook events, debugging hooks not firing, choosing hook types (command vs prompt), or understanding exit codes. Triggers: create hook, hook not working, PreToolUse, PostToolUse, Stop, settings.json hooksFrom its SKILL.md

Install
npx -y skills add cmtkdot/claude-development --skill hook-development

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

6.5 KB, as published. Nobody here has run it

Hook Development

Before creating hooks, check latest docs: /docs hooks or /docs hooks-guide for current syntax and best practices.

Hooks run scripts automatically at specific points in Claude's workflow. Unlike CLAUDE.md instructions which are advisory, hooks are deterministic.

Quick Setup (Scaffolding)

# Create structure
mkdir -p .claude/hooks

# Create settings.json with a basic hook
cat > .claude/settings.json << 'EOF'
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/lint.sh",
            "timeout": 30
          }
        ]
      }
    ]
  }
}
EOF

For plugins, use hooks/hooks.json at plugin root with ${CLAUDE_PLUGIN_ROOT}.

Hook Events

EventWhenMatcherCan Block
SessionStartSession begins/resumessource¹No
UserPromptSubmitUser submits promptNoYes (exit 2)
PreToolUseBefore tool runsYesYes (exit 2)
PermissionRequestPermission dialog shownYesYes (deny)
PostToolUseAfter tool succeedsYesNo
PostToolUseFailureAfter tool failsYesNo
SubagentStartSubagent spawnsNoNo
SubagentStopSubagent finishesNoYes (exit 2)
StopClaude finishesNoYes (exit 2)
PreCompactBefore compactiontrigger²No
Setup--init or --maintenancetrigger³No
NotificationNotification senttype⁴No
SessionEndSession endsNoNo

¹ startup, resume, clear, compact ² manual, auto ³ init, maintenance ⁴ permission_prompt, idle_prompt, auth_success

Configuration

Hooks in settings files (~/.claude/settings.json, .claude/settings.json):

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npm run lint:fix $FILE",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

Plugin hooks use ${CLAUDE_PLUGIN_ROOT} for portability.

Hook Types

Command Hooks (type: "command")

Run bash commands. Most common type.

{
  "type": "command",
  "command": "bash /path/to/script.sh",
  "timeout": 30
}

Prompt Hooks (type: "prompt")

LLM-evaluated hooks for context-aware decisions. Best for Stop and SubagentStop.

{
  "type": "prompt",
  "prompt": "Evaluate if Claude should stop. Check if all tasks complete. Return {\"ok\": true} to allow, or {\"ok\": false, \"reason\": \"explanation\"} to continue.",
  "timeout": 30
}

Exit Codes

ExitBehavior
0Success - parse JSON stdout if present
2Block action - stderr shown to Claude
OtherNon-blocking error - logged only

Input (JSON via stdin)

Common fields:

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../session.jsonl",
  "cwd": "/path/to/project",
  "permission_mode": "default",
  "hook_event_name": "PreToolUse"
}

Tool hooks add: tool_name, tool_input, tool_use_id PostToolUse adds: tool_response

Output (JSON via stdout)

PreToolUse

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "permissionDecisionReason": "Safe operation",
    "updatedInput": {"field": "modified value"},
    "additionalContext": "Info for Claude"
  },
  "systemMessage": "User-only message"
}

permissionDecision: "allow" | "deny" | "ask"

Stop/SubagentStop (force continue)

{
  "decision": "block",
  "reason": "Not finished - still need to run tests"
}

SessionStart (persist env vars)

Use CLAUDE_ENV_FILE:

if [ -n "$CLAUDE_ENV_FILE" ]; then
  echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
fi

Environment Variables

Always available:

  • CLAUDE_PROJECT_DIR - Project root
  • CLAUDE_CODE_REMOTE - "true" in remote environments

SessionStart/Setup only:

  • CLAUDE_ENV_FILE - Write env vars here to persist

Matchers

For PreToolUse, PostToolUse, PermissionRequest:

PatternMatches
"Write"Write tool only
"Write|Edit"Write or Edit
"mcp__memory__.*"All memory MCP tools
".*" or "*"All tools (avoid)

Case-sensitive regex.

Quick Patterns

Block dangerous commands:

#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
if echo "$CMD" | grep -qE 'rm -rf|git push.*--force'; then
  echo "Blocked: Dangerous command" >&2
  exit 2
fi
exit 0

Auto-approve safe files:

#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [[ "$FILE" == *.md || "$FILE" == *.txt ]]; then
  echo '{"hookSpecificOutput":{"permissionDecision":"allow"}}'
fi
exit 0

Add context on prompt:

#!/bin/bash
echo "Current time: $(date)"
exit 0

Skills/Agents Hooks

Hooks in skill/agent frontmatter (scoped to that component):

---
name: my-skill
hooks:
  PreToolUse:
    - matcher: "Bash"
      hooks:
        - type: command
          command: "./validate.sh"
  Stop:
    - hooks:
        - type: prompt
          prompt: "Check if all tasks complete"
---

Add once: true to run only once per session.

Debugging

  1. Check /hooks to see registered hooks
  2. Use claude --debug for execution details
  3. Test commands manually first
  4. Verify scripts are executable

Best Practices

  • Use ${CLAUDE_PROJECT_DIR} for paths
  • Quote all variables ("$VAR")
  • Keep PreToolUse < 100ms
  • Exit 0 for success, 2 to block
  • Validate JSON input exists before parsing

Supporting Files

For deeper content, see:

Related Components

  • Skills: writing-skills, ecosystem-analysis
  • Used by agents: hook-creator, workflow-auditor

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.