Superpowers Hook 机制深度解析

Superpowers Hook 机制深度解析

本文从源码层面剖析 Superpowers 项目如何利用 Hook 机制,在 AI Agent 会话启动时自动注入"超能力"引导上下文,使得 14 个预定义技能(Skills)在对话中被自动发现和调用。

目录

  • 一句话总结
  • [为什么需要 Hook](#为什么需要 Hook)
  • [Hook 的整体架构](#Hook 的整体架构)
  • 四个核心文件详解
  • 多平台适配策略
  • [Hook 注入的内容:引导上下文](#Hook 注入的内容:引导上下文)
  • [从 Hook 到 Skill 的完整链路](#从 Hook 到 Skill 的完整链路)
  • [Claude Code Hook 完整机制](#Claude Code Hook 完整机制)
  • 关键设计决策

一句话总结

Superpowers 只用了一个 Hook 事件 (SessionStart),做了一件事 :在 AI Agent 会话开始时,将 using-superpowers 技能的完整内容注入会话上下文,从而驱动 Agent 在整个会话生命周期中自动发现和调用所有技能。


为什么需要 Hook

AI Agent(Claude Code、Cursor、Codex 等)启动会话时,默认不知道 Superpowers 技能的存在。技能文件(SKILL.md)只是磁盘上的静态文件------除非有某种机制在会话开始时"告诉" Agent 这些技能存在,否则它们永远不会被触发。

Hook 就是这个机制。它解决了一个根本问题:如何在 Agent 的第一次回复之前,将技能发现和调用的规则注入到会话上下文中。

没有 Hook 的情况:

复制代码
用户: "帮我做一个 React Todo 应用"
Agent: (直接开始写代码,跳过设计、规划等流程)

有 Hook 的情况:

复制代码
[SessionStart Hook 触发,注入 using-superpowers 引导上下文]
用户: "帮我做一个 React Todo 应用"
Agent: (识别到 brainstorming 技能适用,先进行头脑风暴设计)

Hook 的整体架构

复制代码
hooks/
├── hooks.json           # Claude Code 平台的 Hook 配置
├── hooks-cursor.json    # Cursor 平台的 Hook 配置
├── run-hook.cmd         # 跨平台 polyglot 包装脚本(同时兼容 Windows CMD 和 Unix bash)
└── session-start        # 实际的 Hook 逻辑脚本(无扩展名,避免 Windows 平台问题)

再加上一个非文件系统的 Hook 实现:

复制代码
.opencode/plugins/superpowers.js   # OpenCode 平台的 JavaScript 插件式 Hook

数据流如下:

复制代码
平台启动会话
    │
    ├─ Claude Code ──→ hooks.json ──→ run-hook.cmd ──→ session-start ──→ JSON 输出
    │                                                                     (hookSpecificOutput.additionalContext)
    │
    ├─ Cursor ───────→ hooks-cursor.json ──→ run-hook.cmd ──→ session-start ──→ JSON 输出
    │                                                                          (additional_context)
    │
    ├─ Copilot CLI ──→ hooks.json ──→ run-hook.cmd ──→ session-start ──→ JSON 输出
    │                                                                     (additionalContext)
    │
    └─ OpenCode ────→ superpowers.js ──→ experimental.chat.messages.transform ──→ 消息注入

四个核心文件详解

1. hooks.json --- Claude Code 平台配置

json 复制代码
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup|clear|compact",
        "hooks": [
          {
            "type": "command",
            "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start",
            "async": false
          }
        ]
      }
    ]
  }
}

关键点:

  • 事件类型 SessionStart:这是 Claude Code 定义的生命周期事件,在会话开始时触发。
  • matcher: "startup|clear|compact" :匹配三种场景------新会话启动、清空会话、压缩上下文。注意没有 resume,因为恢复会话时上下文已经存在,不需要重复注入。
  • async: false:同步执行。这保证了 Hook 在 Agent 第一次回复之前完成,否则引导上下文可能来不及注入。
  • ${CLAUDE_PLUGIN_ROOT}:Claude Code 提供的环境变量,指向插件根目录。路径用双引号包裹,兼容 Windows 路径中的空格。

2. hooks-cursor.json --- Cursor 平台配置

json 复制代码
{
  "version": 1,
  "hooks": {
    "sessionStart": [
      {
        "command": "./hooks/run-hook.cmd session-start"
      }
    ]
  }
}

关键差异:

  • Cursor 使用 camelCase(sessionStart),Claude Code 使用 PascalCase(SessionStart)。
  • Cursor 不需要 matcher、type、async 字段。
  • 使用相对路径 ./hooks/... 而非环境变量。

通过 .cursor-plugin/plugin.json 中的 "hooks": "./hooks/hooks-cursor.json" 声明注册。

3. run-hook.cmd --- 跨平台 polyglot 包装器

这是项目中最巧妙的工程设计之一。一个文件,同时是有效的 Windows CMD 脚本和 Unix bash 脚本:

cmd 复制代码
: << 'CMDBLOCK'
@echo off
REM Windows 部分:找到 bash 并执行目标脚本
if exist "C:\Program Files\Git\bin\bash.exe" (
    "C:\Program Files\Git\bin\bash.exe" "%HOOK_DIR%%~1" ...
    exit /b %ERRORLEVEL%
)
REM ... 更多 bash 查找路径 ...
exit /b 0
CMDBLOCK

# Unix 部分:直接执行目标脚本
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SCRIPT_NAME="$1"
shift
exec bash "${SCRIPT_DIR}/${SCRIPT_NAME}" "$@"

工作原理:

  • 在 Windows CMD 中 :: 被视为标签(如 :label),<< 'CMDBLOCK' 被忽略。CMD 执行 @echo off 及后续批处理命令,在 exit /b 处停止,永远不会执行 CMDBLOCK 之后的 Unix 代码。
  • 在 Unix bash 中 :: 是空操作(no-op),<< 'CMDBLOCK' 开始一个 heredoc,所有 Windows 代码被 heredoc 吞掉。bash 从 CMDBLOCK 之后开始执行 Unix 代码。

设计目的是充当一个通用的 Hook 路由器:接收脚本名作为参数(如 session-start),在任何平台上找到合适的 bash 来执行它。

4. session-start --- Hook 核心逻辑

这是整个 Hook 机制的核心,执行三件事:

第一步:检测旧版技能目录并生成警告

bash 复制代码
legacy_skills_dir="${HOME}/.config/superpowers/skills"
if [ -d "$legacy_skills_dir" ]; then
    warning_message="⚠️ WARNING: ..."
fi

如果用户还在使用 v2.x 时代的旧技能目录,生成迁移警告。

第二步:读取 using-superpowers 技能的完整内容

bash 复制代码
using_superpowers_content=$(cat "${PLUGIN_ROOT}/skills/using-superpowers/SKILL.md" 2>&1 || echo "Error reading")

将整个 SKILL.md 文件内容读入内存,然后通过纯 bash 字符串替换进行 JSON 转义(避免依赖 sed/awk 等外部工具,确保 Windows Git Bash 兼容性):

bash 复制代码
escape_for_json() {
    local s="$1"
    s="${s//\\/\\\\}"     # 转义反斜杠
    s="${s//\"/\\\"}"     # 转义双引号
    s="${s//$'\n'/\\n}"   # 转义换行
    s="${s//$'\r'/\\r}"   # 转义回车
    s="${s//$'\t'/\\t}"   # 转义制表符
    printf '%s' "$s"
}

这个函数经历了重要的性能优化:早期版本使用逐字符循环(${input:$i:1}),在 bash 中是 O(n²) 复杂度,在 Windows Git Bash 上需要 60+ 秒。改用 bash 参数替换后,每个模式是单次 C 级别操作,性能提升 7 倍以上。

第三步:根据平台输出不同格式的 JSON

bash 复制代码
if [ -n "${CURSOR_PLUGIN_ROOT:-}" ]; then
    # Cursor:snake_case 格式
    printf '{ "additional_context": "%s" }' "$session_context"
elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -z "${COPILOT_CLI:-}" ]; then
    # Claude Code:嵌套格式
    printf '{ "hookSpecificOutput": { "hookEventName": "SessionStart", "additionalContext": "%s" } }' "$session_context"
else
    # Copilot CLI 或其他平台:SDK 标准格式
    printf '{ "additionalContext": "%s" }' "$session_context"
fi

三种不同的 JSON 格式,因为每个平台读取 Hook 输出的方式不同:

平台 JSON 字段 检测方式
Cursor additional_context (snake_case) CURSOR_PLUGIN_ROOT 环境变量存在
Claude Code hookSpecificOutput.additionalContext (嵌套) CLAUDE_PLUGIN_ROOT 存在且 COPILOT_CLI 不存在
Copilot CLI additionalContext (顶层) 默认分支

一个关键细节:Claude Code 同时读取 additional_context 和 hookSpecificOutput,但不去重,所以必须只输出一种格式,否则引导上下文会被注入两次。

5. OpenCode 的 JavaScript 实现

OpenCode 不使用文件系统 Hook,而是通过 JavaScript 插件 API:

javascript 复制代码
export const SuperpowersPlugin = async ({ client, directory }) => {
  return {
    // Hook 1:注册技能目录
    config: async (config) => {
      config.skills.paths.push(superpowersSkillsDir);
    },

    // Hook 2:在每次 Agent 步骤时,将引导内容注入第一条用户消息
    'experimental.chat.messages.transform': async (_input, output) => {
      const bootstrap = getBootstrapContent();
      const firstUser = output.messages.find(m => m.info.role === 'user');
      // 防重复注入
      if (firstUser.parts.some(p => p.text.includes('EXTREMELY_IMPORTANT'))) return;
      firstUser.parts.unshift({ type: 'text', text: bootstrap });
    }
  };
};

关键设计:

  • 使用用户消息而非系统消息注入:系统消息在 OpenCode 中每轮都会重复,造成 token 膨胀;而且多系统消息会导致 Qwen 等模型崩溃。
  • 模块级缓存 :getBootstrapContent() 只在第一次调用时读取磁盘和解析 frontmatter,后续调用直接返回缓存结果。因为 experimental.chat.messages.transform 在每个 Agent 步骤都会触发(OpenCode 的 prompt.ts 每步都从数据库重载消息),频繁的磁盘 I/O 会显著影响性能。

多平台适配策略

Superpowers 通过三层架构实现"一套 Hook 逻辑,多平台运行":

复制代码
┌─────────────────────────────────────────────────────┐
│ 第 1 层:平台清单(Plugin Manifest)                   │
│                                                      │
│  .cursor-plugin/plugin.json → hooks-cursor.json      │
│  .claude-plugin/plugin.json → (自动发现 hooks.json)    │
│  .opencode/plugins/superpowers.js → JS API           │
│  .codex-plugin/plugin.json → (无 Hook,靠技能发现)     │
└──────────────────────┬──────────────────────────────┘
                       │
┌──────────────────────▼──────────────────────────────┐
│ 第 2 层:Hook 配置(声明式 JSON)                      │
│                                                      │
│  hooks.json (Claude Code + Copilot CLI 共用)         │
│  hooks-cursor.json (Cursor 专用格式)                  │
└──────────────────────┬──────────────────────────────┘
                       │
┌──────────────────────▼──────────────────────────────┐
│ 第 3 层:Hook 实现(运行时脚本)                        │
│                                                      │
│  run-hook.cmd → session-start (所有 shell 平台共用)    │
│  superpowers.js (OpenCode 专用)                      │
└─────────────────────────────────────────────────────┘

Windows 兼容性

Windows 支持是 Superpowers Hook 历史上最大的工程挑战。主要问题和解决方案:

问题 解决方案
CMD 不能执行 .sh 文件 run-hook.cmd polyglot 包装器
Claude Code 自动给 .sh 文件加 bash 前缀 使用无扩展名的 session-start 文件
${VAR} 在 CMD 中不工作 在 polyglot 中使用 %VAR%
bash 不在 Windows PATH 中 按优先级搜索多个已知路径
JSON 转义的 O(n²) 性能问题 使用 bash 参数替换代替逐字符循环
bash 5.3+ heredoc 挂起 bug 使用 printf 代替 cat <<EOF
POSIX 不兼容(dash/sh) 使用 $0 代替 ${BASH_SOURCE[0]}

Hook 注入的内容:引导上下文

Hook 注入的实际内容是一段用 <EXTREMELY_IMPORTANT> 标签包裹的文本:

复制代码
<EXTREMELY_IMPORTANT>
You have superpowers.

**Below is the full content of your 'superpowers:using-superpowers' skill:**

[using-superpowers SKILL.md 的完整内容]

</EXTREMELY_IMPORTANT>

这段引导上下文包含了 using-superpowers 技能的核心指令:

  1. 强制技能检查规则:对每条用户消息,Agent 必须在回复前检查是否有适用的技能。即使只有 1% 的可能性,也必须调用技能。

  2. 反合理化表:预定义了 Agent 常见的跳过技能的借口及其反驳:

    Agent 的想法 正确做法
    "这只是个简单问题" 问题也是任务,检查技能
    "我需要先了解更多上下文" 技能检查在澄清问题之前
    "让我先探索代码库" 技能告诉你如何探索
    "我知道这是什么意思" 知道概念 ≠ 使用技能
  3. 技能优先级:流程技能(brainstorming、debugging)先于实现技能执行。

  4. 平台适配指引 :Claude Code 使用 Skill 工具,Copilot CLI 使用 skill 工具,Gemini CLI 使用 activate_skill 工具。

  5. 子代理停止门控 :<SUBAGENT-STOP> 标签告诉被派遣的子代理跳过此技能,避免子代理重复执行引导流程。


从 Hook 到 Skill 的完整链路

以一个实际场景为例------用户在 Cursor 中输入"帮我做一个 React Todo 应用":

复制代码
1. 用户打开 Cursor 会话
   │
2. Cursor 读取 .cursor-plugin/plugin.json
   │  → 发现 "hooks": "./hooks/hooks-cursor.json"
   │
3. Cursor 解析 hooks-cursor.json
   │  → 发现 sessionStart 事件,命令为 ./hooks/run-hook.cmd session-start
   │
4. Cursor 执行 run-hook.cmd session-start
   │  → Unix 环境下,exec bash ./hooks/session-start
   │
5. session-start 脚本执行
   │  ├─ 检查旧版目录(无警告)
   │  ├─ 读取 skills/using-superpowers/SKILL.md
   │  ├─ JSON 转义内容
   │  ├─ 检测 CURSOR_PLUGIN_ROOT 环境变量
   │  └─ 输出 {"additional_context": "<EXTREMELY_IMPORTANT>..."}
   │
6. Cursor 将 additional_context 注入会话上下文
   │
7. 用户发送消息:"帮我做一个 React Todo 应用"
   │
8. Agent 处理消息前,先检查引导上下文中的规则
   │  → "创建功能/组件/添加功能性"匹配 brainstorming 技能描述
   │  → 即使只有 1% 可能性也必须调用
   │
9. Agent 调用 Skill 工具加载 brainstorming 技能
   │
10. brainstorming 技能接管流程
    ├─ 探索项目上下文
    ├─ 逐个提问澄清需求
    ├─ 提出 2-3 种方案
    ├─ 展示设计并获得用户批准
    ├─ 编写设计文档
    └─ 过渡到 writing-plans 技能 → 再过渡到 subagent-driven-development

关键观察:Hook 只触发一次,但其注入的引导上下文在整个会话中持续生效。每次 Agent 处理新消息时,都会参考这段上下文来决定是否需要调用技能。


Claude Code Hook 完整机制

Superpowers 只使用了 SessionStart 一个 Hook 事件。但 Claude Code 本身提供了远比这丰富的 Hook 体系。理解完整的 Hook 机制,有助于理解 Superpowers 的设计取舍,也为自定义扩展提供参考。

Hook 事件全景

Claude Code 的 Hook 按触发频率分为三类:

会话级别(每个会话触发一次)

事件 触发时机 能否阻断
SessionStart 会话开始或恢复时 否
SessionEnd 会话终止时 否
Setup 使用 --init-only、--init 或 --maintenance 启动时 否

轮次级别(每轮对话触发一次)

事件 触发时机 能否阻断
UserPromptSubmit 用户提交 prompt 后、Agent 处理前 是,可拒绝 prompt
UserPromptExpansion 用户输入的命令展开为 prompt 时 是,可阻止展开
Stop Agent 完成回复时 是,可阻止停止让对话继续
StopFailure 因 API 错误中断时 否

工具级别(每次工具调用触发)

事件 触发时机 能否阻断
PreToolUse 工具调用执行前 是,可拦截工具调用
PostToolUse 工具调用成功后 否(已执行)
PostToolUseFailure 工具调用失败后 否(已失败)
PostToolBatch 一批并行工具调用全部完成后 是,可中止循环
PermissionRequest 权限对话框出现时 是,可自动允许/拒绝
PermissionDenied 工具调用被权限拒绝后 否,但可返回 retry: true

子代理级别

事件 触发时机 能否阻断
SubagentStart 子代理被创建时 否
SubagentStop 子代理完成时 是,可阻止子代理结束
TaskCreated 通过 TaskCreate 创建任务时 是,可回滚创建
TaskCompleted 任务被标记完成时 是,可阻止标记
TeammateIdle Agent Team 中的队友即将空闲 是,可阻止空闲

环境与配置级别

事件 触发时机 能否阻断
ConfigChange 配置文件变更时 是(policy_settings 除外)
CwdChanged 工作目录变更时(如执行 cd) 否
FileChanged 被监视的文件变更时 否
InstructionsLoaded CLAUDE.md 或规则文件被加载时 否
WorktreeCreate 工作树被创建时 是(任何非零退出码中止创建)
WorktreeRemove 工作树被移除时 否
PreCompact 上下文压缩前 是,可阻止压缩
PostCompact 上下文压缩后 否
Notification Claude Code 发送通知时 否
Elicitation MCP 服务器请求用户输入时 是,可拒绝
ElicitationResult 用户响应 MCP elicitation 后 是,可阻止响应

五种 Hook 处理器类型

Claude Code 支持五种不同类型的 Hook 处理器:

复制代码
┌────────────────────────────────────────────────────────────────┐
│                    Hook 事件触发                                │
│           (SessionStart / PreToolUse / PostToolUse / ...)       │
└────────────────────────┬───────────────────────────────────────┘
                         │
          ┌──────────────┼──────────────┬──────────────┬──────────────┐
          ▼              ▼              ▼              ▼              ▼
   ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐
   │ command  │   │   http   │   │ mcp_tool │   │  prompt  │   │  agent   │
   │ Shell命令│   │ HTTP请求 │   │ MCP工具  │   │ LLM提示  │   │ 子代理   │
   └──────────┘   └──────────┘   └──────────┘   └──────────┘   └──────────┘
    stdin 接收      POST 请求     调用已连接的     发送 prompt     创建子代理
    JSON 输入       JSON body     MCP 服务器工具   给 Claude 模型   可用 Read/
    stdout 输出     响应 body                     返回 yes/no      Grep/Glob
    exit code       HTTP 状态码                    JSON 决策       返回决策

1. Command Hook(Shell 命令) --- Superpowers 使用的类型

通过 stdin 接收 JSON 输入,通过 stdout/exit code 返回结果。最常用、最灵活。

json 复制代码
{
  "type": "command",
  "command": "my-script.sh",
  "async": false
}

2. HTTP Hook(HTTP 端点)

将事件 JSON 作为 POST 请求发送到指定 URL。适合连接外部服务或团队共享的校验逻辑。

json 复制代码
{
  "type": "http",
  "url": "http://localhost:8080/hooks/pre-tool-use",
  "headers": { "Authorization": "Bearer $MY_TOKEN" },
  "allowedEnvVars": ["MY_TOKEN"]
}

3. MCP Tool Hook(MCP 工具)

调用已连接的 MCP 服务器上的工具。适合复用 MCP 生态能力。

json 复制代码
{
  "type": "mcp_tool",
  "server": "my_server",
  "tool": "security_scan",
  "input": { "file_path": "${tool_input.file_path}" }
}

4. Prompt Hook(LLM 提示)

将事件上下文发送给 Claude 模型做单轮评估,返回 yes/no 决策。适合需要"判断"而非"规则"的场景。

json 复制代码
{
  "type": "prompt",
  "prompt": "Does this command look safe? $ARGUMENTS"
}

5. Agent Hook(子代理)

创建一个有工具(Read/Grep/Glob)的子代理来验证条件。比 Prompt Hook 更强大但更慢。实验性功能。

json 复制代码
{
  "type": "agent",
  "prompt": "Verify that all test files follow the naming convention"
}

Hook 的输入输出协议

所有 Hook 共享统一的输入输出协议:

输入(stdin / POST body)

json 复制代码
{
  "session_id": "abc123",
  "transcript_path": "/home/user/.claude/projects/.../transcript.jsonl",
  "cwd": "/home/user/my-project",
  "permission_mode": "default",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": { "command": "npm test" }
}

输出控制 --- 三种方式

方式 用法 适用场景
Exit Code exit 0 允许,exit 2 阻断 简单的允许/拒绝
顶层 JSON {"decision": "block", "reason": "..."} 阻断并提供原因
hookSpecificOutput {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny"}} 精细控制(允许/拒绝/询问用户/修改输入)

向 Agent 注入上下文

通过 additionalContext 字段,Hook 可以向 Claude 的上下文窗口注入信息(最多 10,000 字符):

json 复制代码
{
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "当前分支是 feature/auth,部署目标是 staging 环境"
  }
}

Superpowers 的 session-start 脚本正是通过这个机制注入引导上下文的。

Hook 配置的作用域层级

Hook 可以定义在不同位置,作用域从大到小:

位置 作用域 可共享
组织托管策略(Managed Policy) 组织级别 管理员控制
~/.claude/settings.json 用户的所有项目 否
.claude/settings.json 单个项目 是(可提交到仓库)
.claude/settings.local.json 单个项目 否(gitignored)
插件的 hooks/hooks.json 插件启用时 是(随插件分发)
Skill/Agent 的 frontmatter 组件激活期间 是(定义在组件文件中)

Superpowers 使用的是插件级别 的 Hook(hooks/hooks.json),当用户安装并启用插件后自动生效。

Matcher 过滤机制

matcher 字段决定 Hook 何时触发,其语法取决于内容:

Matcher 值 解释为 示例
"*"、"" 或省略 匹配所有 每次事件都触发
仅含字母、数字、_、` ` 精确字符串匹配
包含其他字符 JavaScript 正则表达式 ^Notebook 匹配以 Notebook 开头的工具

不同事件的 matcher 匹配不同字段:

  • 工具事件 (PreToolUse 等):匹配 tool_name
  • SessionStart :匹配启动方式(startup、resume、clear、compact)
  • SubagentStart/Stop :匹配代理类型(general-purpose、Explore 等)
  • FileChanged :匹配文件名(如 .envrc|.env)

Superpowers 的 hooks.json 中 "matcher": "startup|clear|compact" 精确控制了只在新会话、清空、压缩时注入,排除了 resume(恢复会话已有上下文)。

实用 Hook 场景示例

虽然 Superpowers 只用了 SessionStart,但 Claude Code 的 Hook 体系可以做很多事情:

PreToolUse --- 拦截危险命令

json 复制代码
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{
        "type": "command",
        "if": "Bash(rm *)",
        "command": "block-rm.sh"
      }]
    }]
  }
}

脚本读取 stdin 的 JSON,检查命令内容,返回 permissionDecision: "deny" 阻止执行。

PostToolUse --- 自动格式化/Lint

json 复制代码
{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "run-linter.sh"
      }]
    }]
  }
}

每次文件被编辑或写入后自动运行 linter,将结果通过 additionalContext 反馈给 Agent。

UserPromptSubmit --- Prompt 校验

json 复制代码
{
  "hooks": {
    "UserPromptSubmit": [{
      "hooks": [{
        "type": "command",
        "command": "validate-prompt.sh"
      }]
    }]
  }
}

在用户提交 prompt 后、Agent 处理前进行检查,可以拒绝不合规的输入。

Stop --- 阻止 Agent 停止

json 复制代码
{
  "hooks": {
    "Stop": [{
      "hooks": [{
        "type": "command",
        "command": "check-tests-pass.sh"
      }]
    }]
  }
}

当 Agent 准备停止回复时检查测试是否通过,未通过则 exit 2 阻止停止,让 Agent 继续工作。

Skill Frontmatter 中的 Hook

Hook 还可以直接写在 Skill 的 YAML frontmatter 中,其生命周期与 Skill 绑定:

yaml 复制代码
---
name: secure-operations
description: Perform operations with security checks
hooks:
  PreToolUse:
    - matcher: "Bash"
      hooks:
        - type: command
          command: "./scripts/security-check.sh"
          once: true
---

once: true 表示该 Hook 只在会话中运行一次然后自动移除。


关键设计决策

1. 为什么只用一个 Hook 事件?

Superpowers 只使用 SessionStart,不使用 PreToolUse、PostToolUse 等其他 Hook 事件。原因是:

  • 引导上下文只需注入一次,之后通过上下文窗口自然持续生效。
  • 每次工具调用都触发 Hook 会带来显著的延迟开销。
  • using-superpowers 技能中的规则已经覆盖了后续所有决策点。

2. 为什么将完整技能内容注入而不是只注入路径?

早期版本只告诉 Agent "你有技能可以用,去读文件"。但 Agent 经常跳过读取步骤或延迟读取。将完整内容直接注入确保了 Agent 从第一条消息开始就掌握所有规则。

3. 为什么 Hook 脚本没有扩展名?

session-start 没有 .sh 扩展名。因为 Claude Code 在 Windows 上会自动检测 .sh 文件并在命令前加 bash 前缀,这会破坏通过 run-hook.cmd 路由的机制。使用无扩展名文件绕过了这个自动检测。

4. 为什么使用 printf 而不是 heredoc?

bash 复制代码
# 不用这种写法(bash 5.3+ 会挂起)
cat <<EOF
{"additionalContext": "$content"}
EOF

# 而是用这种
printf '{"additionalContext": "%s"}' "$content"

bash 5.3+(macOS Homebrew 默认版本)在 heredoc 中进行大变量展开时存在回归 bug,会导致脚本无限挂起。

5. 为什么 JSON 转义不用 sed/awk?

纯 bash 参数替换(${s//old/new})在所有平台上都可用,不依赖外部工具。Git Bash 的 PATH 可能不包含常用 Unix 工具,纯 bash 实现是最可靠的跨平台方案。


总结

Claude Code 提供了 30+ 种 Hook 事件、5 种处理器类型、多层作用域的完整 Hook 体系,覆盖了 Agent 生命周期的每个阶段。而 Superpowers 的设计哲学是"以最小干预实现最大效果":

  1. 只用一个事件 (SessionStart),一个脚本 (session-start),一次注入(using-superpowers 内容)------在 30+ 种可用事件中,只选择了最关键的一个
  2. 通过 polyglot 包装器和平台检测,一份核心逻辑支持 4 个平台 × 3 个操作系统
  3. 注入的引导上下文通过上下文窗口在整个会话中持续生效,无需 PreToolUse/PostToolUse 等高频 Hook 持续干预
  4. 引导上下文中的规则(1% 原则、反合理化表、技能优先级)驱动 Agent 自动发现和使用 14 个技能

这种设计使得 Superpowers 成为一个"安装即生效"的插件------用户安装后,无需任何额外配置或手动操作,Agent 就会在合适的时机自动调用正确的技能。同时,理解 Claude Code 完整的 Hook 体系,也为你在此基础上构建自定义工作流(如自动 lint、危险命令拦截、prompt 校验等)提供了清晰的路径。

相关推荐
鸽芷咕4 天前
Claude Code 报 429 “Rate limit reached“?先分清是限速还是额度用完,对症下药
人工智能·报错解决·编程工具·claude code
BryceBorder5 天前
Agent Memory 不只是聊天记录:手搓三大记忆系统
后端·agent·面经·codex·claude code·agent memory
youcans_5 天前
【嵌入式软件AI编程】16. Claude Code 与 VS Code 的协同开发
stm32·mcu·嵌入式·ai编程·claude code
Code_流苏5 天前
如何写好一个 Skills?
ai·agent·技能·skills
向上的车轮7 天前
Claude Code辅助遗留系统重构:可行性评估、小步落地与多仓WMS整合建议
claude code
明君6899 天前
一套专注 Android 逆向分析的 Skills
android·android逆向·agents·skills
小静AI工程实验室9 天前
Claude Code 实用教程:Windows、macOS、Linux 从安装到项目调试与验收
人工智能·python·开发工具·claude code
VIP_CQCRE9 天前
Claude Code 接入 Nano Banana MCP:在终端里完成 AI 图片生成、编辑与多图合成
ai·图像生成·mcp·claude code·ace data cloud
码哥字节9 天前
30K Star 神器,给 Claude Code 装上代码地图,Token 中位数省 65 倍
mcp·claude code