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 不需要 matchertypeasync 字段。
  • 使用相对路径 ./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_contexthookSpecificOutput,但不去重,所以必须只输出一种格式,否则引导上下文会被注入两次。

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 :匹配启动方式(startupresumeclearcompact
  • SubagentStart/Stop :匹配代理类型(general-purposeExplore 等)
  • 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,不使用 PreToolUsePostToolUse 等其他 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 校验等)提供了清晰的路径。

相关推荐
布朗克1687 小时前
Claude Code提示词入门:CLAUDE.md编写完全指南
提示词·claude code
小坏讲微服务9 小时前
SpringBoot整合SpringAI配置多平台API密钥
java·人工智能·spring boot·后端·flask·ai编程·claude code
南宫乘风10 小时前
用 Skills 驱动 AI 开发:Matt Pocock 工作流在 DevOps 场景里的落地实践
devops·skills
Fzuim11 小时前
Claude Code AskUserQuestion 交互式提问机制深度解析
ai·agent·claude code
overwizard11 小时前
AI工程双剑:gstack与Superpowers实战指南
人工智能·claude code·vibe-coding·skills·cc switch
二月夜11 小时前
Claude Code 接入 DeepSeek V4
deepseek·claude code
带娃的IT创业者1 天前
Claude Code 源码泄露事件深度剖析:当 AI 编程工具不再“透明”
人工智能·ai编程·ai安全·源码泄露·claude code·工程伦理
Justinyh1 天前
安装与体验 Claude code、CC Switch、SuperPowers
大模型·agent·claude code·cc switch·superpowers
今天有个Bug1 天前
【Spec Coding】OpenSpec:AI 原生规格驱动开发(SDD)框架
ai编程·vibecoding·claude code·sdd·speccoding