mcpField
E
enhance-hooks

enhance-hooks

github.com/agent-shAgent 工作流1.0k82 次安装2 天前更新
代码仓库

关于 enhance-hooks

面向 Agent 开发者的 Claude Code Hook 审查技能,检查 Hook 配置与脚本的安全性、正确性和生命周期适配,并可应用部分修复。

主要功能

  1. 01发现并分类 Hook 文件
  2. 02验证元数据与配置
  3. 03检查脚本中的不安全模式
  4. 04审查退出码、事件类型和匹配器
  5. 05建议或应用部分修复

适用场景

  1. 01审查项目的 Hook 配置
  2. 02检查命令脚本中的不安全操作
  3. 03验证阻止行为与事件是否匹配

安装

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

$npx skills add https://github.com/agent-sh/agentsys --skill enhance-hooks

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

详细介绍

enhance-hooks

分析钩子定义和脚本的安全性、正确性与最佳实践。

解析参数

const args = '$ARGUMENTS'.split(' ').filter(Boolean);
const targetPath = args.find(a => !a.startsWith('--')) || '.';
const fix = args.includes('--fix');

工作流

  1. 发现 - 查找钩子文件(.md、.sh、.json)
  2. 分类 - 确定钩子类型和事件
  3. 解析 - 提取 frontmatter 和脚本内容
  4. 检查 - 根据下方知识运行所有模式检查
  5. 筛选 - 应用确定性筛选
  6. 报告 - 生成 Markdown 输出
  7. 修复 - 如果存在 --fix 标志,则应用自动修复

钩子知识参考

什么是钩子

钩子是在 Claude Code 会话中特定时间点触发的自动化操作。它们通过 bash 命令或基于 LLM 的评估,实现对 Claude 操作的验证、监控和控制。

钩子生命周期(完整参考)

钩子按以下顺序触发:

顺序事件描述是否需要匹配器
1SessionStart会话开始或恢复否
2UserPromptSubmit用户提交提示词否
3PreToolUse工具执行前(可修改或阻止)是
4PermissionRequest权限对话框出现时是
5PostToolUse工具成功执行后是
6SubagentStart启动子 Agent 时否
7SubagentStop子 Agent 结束时否
8StopClaude 完成响应时否
9PreCompact压缩上下文前否
10SessionEnd会话终止时否
11NotificationClaude Code 发送通知时否
钩子类型

命令钩子(type: "command"):

  • 执行 bash 命令,并完全控制 stdin/stdout
  • 适用于所有事件

提示词钩子(type: "prompt"):

  • 使用 LLM 评估进行智能且上下文感知的决策
  • 仅支持 Stop 和 SubagentStop 事件
配置位置
文件位置范围是否提交
用户设置~/.claude/settings.json所有项目否
项目设置.claude/settings.json当前项目是
本地设置.claude/settings.local.json当前项目否
配置结构
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/validate-bash.sh",
            "timeout": 30
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/format-code.sh"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Check if all requested tasks are complete.",
            "timeout": 30
          }
        ]
      }
    ]
  }
}
匹配器语法
模式描述
Write精确匹配工具名称
Edit|Write匹配多个工具(正则 OR)
Notebook.*正则模式匹配
* 或 ""匹配所有工具
(省略)Stop、SubagentStop、UserPromptSubmit 必需
输入架构(通过 stdin 传入的 JSON)

所有钩子都会接收以下 JSON 结构:

{
  "session_id": "abc123",
  "transcript_path": "/path/to/transcript",
  "cwd": "/project/root",
  "permission_mode": "default",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test",
    "description": "Run test suite"
  }
}
退出代码
退出代码行为
0成功 - stdout 显示给用户或添加为上下文
2阻止性错误 - 显示 stderr,并阻止操作
其他非阻止性错误 - 在详细模式下显示 stderr
输出架构

PreToolUse 决策控制:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow|deny|ask",
    "permissionDecisionReason": "Reason for decision",
    "updatedInput": {
      "command": "modified command"
    },
    "additionalContext": "Context for Claude"
  }
}

Stop/SubagentStop 控制:

{
  "decision": "block",
  "reason": "Tasks incomplete: missing test coverage"
}
环境变量
变量描述可用范围
CLAUDE_PROJECT_DIR项目根目录的绝对路径所有钩子
CLAUDE_CODE_REMOTE远程会话时为 "true"所有钩子
CLAUDE_ENV_FILE用于持久化环境变量的路径仅 SessionStart
CLAUDE_FILE_PATHS以空格分隔的文件路径PostToolUse(Write/Edit)
实用钩子示例

安全防火墙(PreToolUse):

#!/usr/bin/env bash
set -euo pipefail

cmd=$(jq -r '.tool_input.command // ""')

# Block dangerous patterns
if echo "$cmd" | grep -qE 'rm -rf|git reset --hard|curl.*\|.*sh'; then
  echo '{"decision": "block", "reason": "Dangerous command blocked"}' >&2
  exit 2
fi

exit 0

自动格式化工具(PostToolUse):

#!/usr/bin/env bash
set -euo pipefail

files=$(jq -r '.tool_input.file_path // ""')

for file in $files; do
  case "$file" in
    *.py) black "$file" 2>/dev/null || true ;;
    *.js|*.ts) prettier --write "$file" 2>/dev/null || true ;;
  esac
done

exit 0

命令记录器(PreToolUse):

#!/usr/bin/env bash
set -euo pipefail
cmd=$(jq -r '.tool_input.command // ""')
printf '%s %s\n' "$(date -Is)" "$cmd" >> .claude/bash-commands.log
exit 0

工作流编排(SubagentStop - prompt 类型):

{
  "hooks": {
    "SubagentStop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Review the subagent's work. Did it complete all tasks?"
          }
        ]
      }
    ]
  }
}

检测模式

1. Frontmatter 验证(确定性高)

必需:

  • 使用 --- 分隔符的 YAML frontmatter
  • frontmatter 中包含 name 字段
  • frontmatter 中包含 description 字段

建议:

  • 为命令钩子设置 timeout(默认值:30s)
  • 指定钩子类型

标记:

  • 缺少 frontmatter 分隔符
  • 缺少 name 或 description
2. 脚本安全性(高确定性)

必需的安全模式:

  • 在脚本开头使用 set -euo pipefail
  • 处理 jq/JSON 解析错误
  • 正确引用变量

需要标记的危险模式:

模式风险确定性
rm -rf未经确认即执行破坏性操作高
git reset --hard存在数据丢失风险高
curl | sh远程代码执行高
eval "$input"任意代码执行高
rm -r递归删除(可能是有意操作)中
git push --force强制推送(可能是有意操作)中
3. 退出代码处理(高确定性)

检查: 脚本是否使用了正确的退出代码

标记:

  • 成功路径缺少 exit 0
  • 阻止操作时使用退出代码 1(应使用 2)
  • 脚本末尾没有退出代码
4. Hook 类型是否适当(高确定性)

检查: Hook 类型是否与事件匹配

标记:

  • 将提示词 Hook 用于 Stop/SubagentStop 以外的事件
  • 缺少类型声明
5. 生命周期事件是否适当(中确定性)
事件适用场景
PreToolUse安全验证、阻止命令、修改输入
PostToolUse格式化、日志记录、通知
Stop完成检查、清理、摘要
SubagentStop工作流编排、结果验证
SessionStart环境设置、初始化

标记:

  • PostToolUse Hook 尝试阻止操作(为时已晚)
  • PreToolUse Hook 执行繁重处理(应保持快速)
  • 在不支持的事件上使用提示词 Hook
6. 超时配置(中确定性)

指南:

  • 默认值:命令 Hook 为 30 秒
  • 网络操作:始终设置明确的超时时间
  • 外部服务调用:根据预期延迟设置超时时间

标记:

  • 网络操作没有超时时间
  • 外部服务调用缺少超时时间
  • 超时时间长得不合理(超过 60 秒且没有说明理由)
7. 输出格式(中确定性)

PreToolUse 输出字段:

  • permissionDecision:allow、deny 或 ask
  • permissionDecisionReason:决策说明
  • updatedInput:修改后的工具输入(可选)
  • additionalContext:提供给 Claude 的上下文(可选)

标记:

  • 无效的 permissionDecision 值
  • deny 决策缺少理由
  • JSON 输出格式错误
8. 匹配器模式(中确定性)

检查: 匹配器语法是否有效

标记:

  • 无效的正则表达式模式
  • 过于宽泛的匹配器(使用 * 且没有说明理由)
  • 在不支持匹配器的事件上使用匹配器(Stop、SubagentStop)
9. 反模式(低确定性)
  • Hook 中包含复杂逻辑(应简单且快速)
  • 缺少文档或注释
  • 硬编码路径(应使用 $CLAUDE_PROJECT_DIR)
  • 网络调用没有错误处理
  • Hook 脚本中包含密钥/凭据

自动修复实现

1. 缺少安全头部
#!/usr/bin/env bash
set -euo pipefail
2. 缺少退出代码

在脚本末尾添加 exit 0

3. 缺少 frontmatter 字段
---
name: hook-name
description: Hook description
timeout: 30
---
4. 错误的阻止操作退出代码

阻止操作出错时,将 exit 1 替换为 exit 2


输出格式

## Hook Analysis: {hook-name}

**File**: {path}
**Type**: {command|prompt|config}
**Event**: {PreToolUse|PostToolUse|Stop|...}

### Summary
- HIGH: {count} issues
- MEDIUM: {count} issues

### Frontmatter Issues ({n})
| Issue | Fix | Certainty |

### Safety Issues ({n})
| Issue | Fix | Certainty |

### Exit Code Issues ({n})
| Issue | Fix | Certainty |

### Lifecycle Issues ({n})
| Issue | Fix | Certainty |

### Output Format Issues ({n})
| Issue | Fix | Certainty |

模式统计

类别模式数可自动修复
Frontmatter32
安全性62
退出代码32
Hook 类型20
生命周期50
超时30
输出30
匹配器30
反模式50
总计336

### 示例:缺少安全头部

<bad_example>

#!/usr/bin/env bash
cmd=$(jq -r '.tool_input.command // ""')

问题原因:缺少 set -euo pipefail,意味着错误可能会被悄悄忽略。 </bad_example>

<good_example>

#!/usr/bin/env bash
set -euo pipefail
cmd=$(jq -r '.tool_input.command // ""')

优点:遇到错误、未设置的变量和管道失败时会快速失败。 </good_example>

示例:用于阻止操作的退出代码错误

<bad_example>

if [[ "$cmd" == *"rm -rf"* ]]; then
  echo "Blocked dangerous command" >&2
  exit 1  # Wrong!
fi

为什么不好:退出代码 1 不会阻止操作。操作仍会继续。 </bad_example>

<good_example>

if [[ "$cmd" == *"rm -rf"* ]]; then
  echo '{"decision": "block", "reason": "Dangerous command"}' >&2
  exit 2  # Correct blocking exit code
fi

为什么好:退出代码 2 会阻止操作。JSON 输出提供上下文。 </good_example>

示例:在错误事件上使用提示词钩子

<bad_example>

{
  "hooks": {
    "PreToolUse": [
      {
        "hooks": [{ "type": "prompt", "prompt": "Is this safe?" }]
      }
    ]
  }
}

为什么不好:提示词钩子仅适用于 Stop 和 SubagentStop 事件。 </bad_example>

<good_example>

{
  "hooks": {
    "PreToolUse": [
      {
        "hooks": [{ "type": "command", "command": "./validate.sh" }]
      }
    ]
  }
}

为什么好:命令钩子适用于所有事件。 </good_example>

示例:危险的命令模式

<bad_example>

if echo "$cmd" | grep -q 'rm'; then
  exit 2
fi

为什么不好:范围过广——会阻止合法的 rm file.tmp 命令。 </bad_example>

<good_example>

if echo "$cmd" | grep -qE 'rm\s+(-rf|-fr)\s+/'; then
  exit 2
fi

为什么好:针对性模式可匹配实际危险的命令。 </good_example>

示例:硬编码路径

<bad_example>

log_file="/home/user/project/.claude/commands.log"

为什么不好:硬编码路径在其他机器上会失效。 </bad_example>

<good_example>

log_file="$CLAUDE_PROJECT_DIR/.claude/commands.log"

为什么好:使用环境变量以确保可移植性。 </good_example>


约束

  • 仅对确定性高的问题应用自动修复
  • 谨慎处理安全模式——漏报比误报更糟
  • 绝不删除内容,只提出改进建议
  • 根据上方嵌入的知识参考进行验证

评论

支持 Markdown