mcpField
H
hook-development

hook-development

github.com/josiahsiegelAgent 工作流59110 次安装19 周前更新
代码仓库

关于 hook-development

介绍 Claude Code 插件中事件驱动 Hook 的开发,说明事件类型、配置格式、提示词与命令 Hook、输入输出、安全及调试方法。

主要功能

  1. 01Hook 事件及用途
  2. 02插件与设置配置格式
  3. 03提示词和命令 Hook
  4. 04Hook 输入与输出结构
  5. 05安全与调试指南

适用场景

  1. 01验证或限制工具操作
  2. 02文件变更后运行测试
  3. 03在会话开始时加载项目上下文
  4. 04检查 Hook 配置和输出

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill hook-development

安装后在 Claude Code 中输入/hook-development确认已加载。

详细介绍

Claude Code 插件的 Hook 开发

概述

Hook 是事件驱动的自动化机制,会在 Claude Code 事件发生时执行。使用 Hook 可验证操作、强制执行策略、加载上下文并集成外部工具。

两种 Hook 类型:

  • 基于提示词(推荐):由大模型驱动,可根据上下文作出决策
  • 基于命令:使用 Shell 命令进行快速、确定性检查

Hook 事件参考

事件触发时机常见用途
PreToolUse工具执行前验证、批准/拒绝、修改输入
PostToolUse工具执行后测试、Lint、记录日志、提供反馈
Stop主 Agent 停止时验证任务是否完成
SubagentStop子 Agent 停止时验证子 Agent 的工作
UserPromptSubmit用户发送提示词时添加上下文、验证、预处理
SessionStart会话开始时加载上下文、设置环境
SessionEnd会话结束时清理、记录日志
PreCompact上下文压缩前保留关键信息
Notification显示通知时自定义提醒响应

配置格式

插件 hooks.json(位于 hooks/hooks.json)

使用带有 hooks 字段的包装格式:

{
  "description": "What these hooks do (optional)",
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh",
            "timeout": 10
          }
        ]
      }
    ]
  }
}
用户设置格式(位于 .claude/settings.json)

直接格式,不使用包装结构:

{
  "PreToolUse": [
    {
      "matcher": "Write|Edit",
      "hooks": [{ "type": "command", "command": "script.sh" }]
    }
  ]
}

**关键区别:**插件 hooks.json 会将事件包裹在 {"hooks": {...}} 中。设置格式则将事件放在顶层。

基于提示词的 Hook(推荐)

使用大模型推理,根据上下文作出决策:

{
  "type": "prompt",
  "prompt": "Evaluate if this tool use is appropriate. Check for: system paths, credentials, path traversal. Return 'approve' or 'deny'.",
  "timeout": 30
}

**支持的事件:**PreToolUse、PostToolUse、Stop、SubagentStop、UserPromptSubmit

**优势:**能结合上下文、灵活、能更好地处理边缘情况、更易维护。

命令 Hook

执行 Shell 命令进行确定性检查:

{
  "type": "command",
  "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh",
  "timeout": 60
}

始终使用 ${CLAUDE_PLUGIN_ROOT},以确保路径可移植。

退出码
代码含义
0成功(stdout 显示在记录中)
2阻止性错误(stderr 会反馈给 Claude)
其他非阻止性错误

匹配器

控制哪些工具会触发 Hook:

"matcher": "Write"              // Exact match
"matcher": "Write|Edit|Bash"    // Multiple tools
"matcher": "mcp__.*__delete.*"  // Regex (all MCP delete tools)
"matcher": "*"                  // All tools (use sparingly)

匹配器区分大小写。

Hook 输入/输出

输入(所有 Hook 均通过 stdin 接收)
{
  "session_id": "abc123",
  "transcript_path": "/path/to/transcript.txt",
  "cwd": "/current/working/dir",
  "hook_event_name": "PreToolUse",
  "tool_name": "Write",
  "tool_input": { "file_path": "/path/to/file" }
}

特定事件字段:tool_name、tool_input、tool_result、user_prompt、reason

在提示词中访问:$TOOL_INPUT、$TOOL_RESULT、$USER_PROMPT

输出

标准格式(所有 Hook):

{
  "continue": true,
  "suppressOutput": false,
  "systemMessage": "Message for Claude"
}

PreToolUse 决策:

{
  "hookSpecificOutput": {
    "permissionDecision": "allow|deny|ask",
    "updatedInput": { "field": "modified_value" }
  }
}

Stop/SubagentStop 决策:

{
  "decision": "approve|block",
  "reason": "Explanation"
}

环境变量

变量适用范围用途
$CLAUDE_PLUGIN_ROOT所有 Hook插件目录(用于可移植路径)
$CLAUDE_PROJECT_DIR所有 Hook项目根目录路径
$CLAUDE_ENV_FILE仅限 SessionStart为会话持久化环境变量

SessionStart 可以持久化变量:

echo "export PROJECT_TYPE=nodejs" >> "$CLAUDE_ENV_FILE"

常见模式

验证文件写入(PreToolUse)
{
  "PreToolUse": [{
    "matcher": "Write|Edit",
    "hooks": [{
      "type": "prompt",
      "prompt": "Check if this file write is safe. Deny writes to: .env, credentials, system paths, or files with path traversal (..). Return 'approve' or 'deny' with reason."
    }]
  }]
}
修改后自动测试(PostToolUse)
{
  "PostToolUse": [{
    "matcher": "Write|Edit",
    "hooks": [{
      "type": "command",
      "command": "npm test -- --bail",
      "timeout": 60
    }]
  }]
}
验证任务完成情况(Stop)
{
  "Stop": [{
    "matcher": "*",
    "hooks": [{
      "type": "prompt",
      "prompt": "Verify: tests run, build succeeded, all questions answered. Return 'approve' to stop or 'block' with reason to continue."
    }]
  }]
}
加载项目上下文(SessionStart)
{
  "SessionStart": [{
    "matcher": "*",
    "hooks": [{
      "type": "command",
      "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/load-context.sh",
      "timeout": 10
    }]
  }]
}

安全最佳实践

在命令 Hook 脚本中:
#!/bin/bash
set -euo pipefail

input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path')

# Always validate inputs
if [[ ! "$file_path" =~ ^[a-zA-Z0-9_./-]+$ ]]; then
  echo '{"decision": "deny", "reason": "Invalid path"}' >&2
  exit 2
fi

# Block path traversal
if [[ "$file_path" == *".."* ]]; then
  echo '{"decision": "deny", "reason": "Path traversal detected"}' >&2
  exit 2
fi

# Block sensitive files
if [[ "$file_path" == *".env"* ]]; then
  echo '{"decision": "deny", "reason": "Sensitive file"}' >&2
  exit 2
fi

# Always quote variables
echo "$file_path"

生命周期和限制

**Hook 会在会话开始时加载。**修改 Hook 配置后,必须重启 Claude Code 才能生效。

  • 编辑 hooks/hooks.json 不会影响当前会话
  • 新增 Hook 脚本后,必须重启才能识别
  • 所有匹配的 Hook 都会并行运行(而非顺序运行)
  • Hook 无法看到彼此的输出,因此应独立设计

**测试更改:**退出 Claude Code,然后使用 claude 或 claude --debug 重启。

调试

# Enable debug mode to see hook execution
claude --debug

# Test hook scripts directly
echo '{"tool_name": "Write", "tool_input": {"file_path": "/test"}}' | \
  bash ${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh

# Validate hook JSON output
output=$(./hook-script.sh < test-input.json)
echo "$output" | jq .

# View loaded hooks in session
# Use /hooks command

验证清单

  • hooks.json 使用正确的格式(插件封装或直接使用设置)
  • 所有脚本路径均使用 ${CLAUDE_PLUGIN_ROOT}(不使用硬编码路径)
  • 脚本可执行且能处理错误(set -euo pipefail)
  • 脚本会验证所有输入,并为所有变量加引号
  • 匹配器设置具体(除非必要,否则避免使用 *)
  • 超时时间设置合理(默认值:命令 60s,提示词 30s)
  • 钩子输出为有效 JSON
  • 已使用 claude --debug 进行测试

评论

支持 Markdown