Agent Skill
2/7/2026

hook-development

This skill should be used when the user asks to "create a hook", "add PreToolUse hook", "validate tool use", "hook events", "hooks.json", "prompt-based hook", or mentions hook events (PreToolUse, PostToolUse, Stop).

N
nthplusio
0GitHub Stars
2Views
npx skills add nthplusio/functional-claude

SKILL.md

Namehook-development
DescriptionThis skill should be used when the user asks to "create a hook", "add PreToolUse hook", "validate tool use", "hook events", "hooks.json", "prompt-based hook", or mentions hook events (PreToolUse, PostToolUse, Stop).

name: hook-development description: Guide for creating event-driven hooks that validate, log, or modify Claude's behavior. Use when the user asks to "create a hook", "add PreToolUse hook", "validate tool use", "hook events", "hooks.json", or mentions hook events (PreToolUse, PostToolUse, Stop). version: 0.5.0

Hook Development

Guide for creating event-driven hooks in hooks/hooks.json.

hooks.json Format

{
  "description": "What these hooks do",
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PLUGIN_ROOT}/hooks/validate.js",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

Hook Types

Command hooks execute a script (see format above). Prompt-based hooks let Claude evaluate conditions — useful for semantic checks hard to script:

{
  "type": "prompt",
  "prompt": "Check if this file modification follows coding standards. If it violates any standards, explain why and set permissionDecision to 'deny'."
}

Hook Events

EventWhen It Fires
SessionStartSession begins or resumes
UserPromptSubmitUser submits a prompt
PreToolUseBefore tool execution
PostToolUseAfter tool succeeds
StopClaude finishes responding
SubagentStartWhen spawning a subagent
SubagentStopWhen subagent finishes
PreCompactBefore context compaction
SessionEndSession terminates
NotificationClaude sends notifications
SetupWith --init or --maintenance flags

Environment Variables

VariableScopeDescription
${CLAUDE_PLUGIN_ROOT}Plugin hooksAbsolute path to plugin
"$CLAUDE_PROJECT_DIR"Project hooksProject root (quoted)

Critical: Plugin hooks use ${CLAUDE_PLUGIN_ROOT} with braces. Project hooks use "$CLAUDE_PROJECT_DIR" with quotes.

Exit Codes

CodeMeaning
0Success — allow action
2Block — deny action, show stderr
OtherNon-blocking error

Common Matchers

  • Write|Edit — File modifications
  • Bash — Shell commands
  • * or "" — All tools
  • mcp__.* — All MCP tools

Temporarily Active Hooks

Hooks can be enabled/disabled via .local.md config:

const config = parseLocalMd(pluginRoot);
if (!config.hooks?.validation_enabled) {
  process.exit(0); // Skip hook
}

See /claude-plugin-dev:plugin-settings for configuration patterns.

JSON Output (PreToolUse)

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "permissionDecisionReason": "Explanation"
  }
}

Permission values: allow, deny, ask

Hook Script Template

#!/usr/bin/env node
const fs = require('fs');

let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', chunk => input += chunk);
process.stdin.on('end', () => {
  try {
    const data = JSON.parse(input || '{}');
    const content = data.tool_input?.content || '';

    if (shouldBlock(content)) {
      console.error('Reason for blocking');
      process.exit(2);
    }

    console.log(JSON.stringify({ permissionDecision: "allow" }));
    process.exit(0);
  } catch (err) {
    process.exit(0);
  }
});
Skills Info
Original Name:hook-developmentAuthor:nthplusio