Logo
热心市民王先生

核心能力验证

能力验证 API分析

深入验证 Claude Code 与 OpenCode 的 Hook API 与实现细节

Claude Code Hook 架构

Hook 类型与生命周期

Claude Code 提供了 17 种 Hook 事件类型,覆盖从会话启动到终止的完整生命周期。这些事件可以分为以下几类:

会话生命周期 Hooks:

事件触发时机可否阻断
SessionStart会话开始或恢复时
SessionEnd会话终止时
StopClaude 完成响应时
PreCompact上下文压缩前

用户交互 Hooks:

事件触发时机可否阻断
UserPromptSubmit用户提交提示词时
PermissionRequest权限对话框出现时
Notification发送通知时

工具执行 Hooks:

事件触发时机可否阻断
PreToolUse工具调用执行前
PostToolUse工具调用成功后
PostToolUseFailure工具调用失败后

子代理 Hooks:

事件触发时机可否阻断
SubagentStart子代理启动时
SubagentStop子代理完成时
TeammateIdleAgent Team 成员空闲时

任务与配置 Hooks:

事件触发时机可否阻断
TaskCompleted任务标记完成时
ConfigChange配置文件变更时
WorktreeCreate创建工作树时
WorktreeRemove移除工作树时

Hook 注册与触发机制

Claude Code 的 Hook 注册采用声明式配置方式,支持多层级配置文件:

配置优先级(从高到低):
1. ~/.claude/settings.json        - 用户全局配置
2. .claude/settings.json          - 项目配置(可提交到仓库)
3. .claude/settings.local.json    - 项目本地配置(gitignored)
4. Plugin hooks/hooks.json        - 插件配置
5. Skill/Agent frontmatter        - 技能/代理内嵌配置

配置结构示例:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/validate.sh",
            "timeout": 60
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "prettier --write $FILE_PATH"
          }
        ]
      }
    ]
  }
}

四种 Hook 处理器类型:

  1. Command Hook (type: "command"): 执行 Shell 命令,通过 stdin 传入 JSON,stdout 返回结果
  2. HTTP Hook (type: "http"): POST 请求到指定 URL,通过响应体返回结果
  3. Prompt Hook (type: "prompt"): 发送到 Claude 模型进行单轮评估,返回 yes/no 决策
  4. Agent Hook (type: "agent"): 启动子代理执行多轮验证,可使用工具

Hook 能力边界

Hook 能做什么:

  • 阻断或允许特定工具调用
  • 修改工具参数(通过 hookSpecificOutput
  • 向 Claude 上下文注入额外信息
  • 触发外部系统通知
  • 执行任意 Shell 命令

Hook 不能做什么:

  • 直接调用 Claude Code 的工具(只能通过 stdout 间接影响)
  • 访问 Claude Code 内部状态(只能访问 Hook 输入数据)
  • 异步等待用户输入后继续执行(但支持后台异步执行)
  • 修改已发生的工具执行结果(PostToolUse 只能记录,不能撤销)

OpenCode Hook 架构

Hook 类型与生命周期

OpenCode 的 Hook 系统作为 Plugin API 的一部分,提供了更底层的事件订阅能力。事件类型按功能域分组:

Command Events:

  • command.executed: 命令执行完成

File Events:

  • file.edited: 文件被编辑
  • file.watcher.updated: 文件监视器更新

LSP Events:

  • lsp.client.diagnostics: LSP 诊断信息
  • lsp.updated: LSP 状态更新

Message Events:

  • message.part.removed: 消息部分移除
  • message.part.updated: 消息部分更新
  • message.removed: 消息移除
  • message.updated: 消息更新

Permission Events:

  • permission.asked: 权限请求
  • permission.replied: 权限回复

Session Events:

  • session.created: 会话创建
  • session.compacted: 会话压缩
  • session.deleted: 会话删除
  • session.diff: 会话差异
  • session.error: 会话错误
  • session.idle: 会话空闲
  • session.status: 会话状态
  • session.updated: 会话更新

Tool Events:

  • tool.execute.before: 工具执行前(可阻断
  • tool.execute.after: 工具执行后

TUI Events:

  • tui.prompt.append: 追加提示
  • tui.command.execute: 执行命令
  • tui.toast.show: 显示通知

Experimental Events:

  • experimental.session.compacting: 会话压缩前
  • experimental.chat.messages.transform: 消息转换

Hook 注册与触发机制

OpenCode 的 Hook 通过 Plugin 函数返回值 注册:

import type { Plugin } from "@opencode-ai/plugin"

export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
  return {
    // 工具执行前 Hook
    "tool.execute.before": async (input, output) => {
      if (input.tool === "bash") {
        // 修改输出参数
        output.args.command = sanitizeCommand(output.args.command)
      }
    },
    
    // 工具执行后 Hook
    "tool.execute.after": async (input, output) => {
      console.log(`Tool ${input.tool} executed`)
    },
    
    // 会话空闲 Hook
    "session.idle": async ({ event }) => {
      await $`osascript -e 'display notification "Session completed!"'`
    }
  }
}

插件加载顺序:

  1. 全局配置 (~/.config/opencode/opencode.json)
  2. 项目配置 (opencode.json)
  3. 全局插件目录 (~/.config/opencode/plugins/)
  4. 项目插件目录 (.opencode/plugins/)

Hook 能力边界

Hook 能做什么:

  • 修改工具输入/输出参数
  • 抛出异常阻断工具执行
  • 调用 OpenCode SDK 与系统交互
  • 添加自定义工具
  • 注入环境变量
  • 自定义会话压缩行为

Hook 不能做什么:

  • 脱离插件系统独立配置(必须编写代码)
  • 直接持久化状态(需要自行实现存储)
  • 跨会话共享状态(每次插件加载是独立的)

能力差距对比

功能对比矩阵

功能特性Claude CodeOpenCode差距分析
声明式配置✅ JSON 配置❌ 需编程Claude Code 用户友好
命令行管理/hooks 菜单❌ 无Claude Code 易于管理
HTTP Hook✅ 原生支持⚠️ 需自行实现Claude Code 集成更方便
Prompt Hook✅ LLM 评估❌ 无Claude Code 支持智能决策
Agent Hook✅ 多轮验证✅ 通过子代理两者能力相当
自定义事件❌ 仅预定义⚠️ 有限支持OpenCode 更灵活
工具注册❌ 仅 Hook✅ 可注册工具OpenCode 扩展性更强
运行时修改✅ 修改输出对象✅ 修改输出对象两者能力相当
阻断执行✅ Exit 2 / JSON✅ 抛出异常机制不同,效果相同
超时控制✅ 可配置⚠️ 无内置Claude Code 更安全

架构差异分析

┌─────────────────────────────────────────────────────────────────┐
│                    Claude Hook 架构                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌──────────┐    JSON     ┌───────────┐    stdin/stdout         │
│  │ Claude   │ ──────────► │ Hook      │ ◄──────────────────►    │
│  │ Code     │             │ Script    │   Exit Code + JSON      │
│  │ (主进程)  │ ◄────────── │ (子进程)   │                        │
│  └──────────┘   结果      └───────────┘                         │
│                                                                 │
│  特点: 进程隔离、声明式配置、确定性控制                            │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│                    OpenCode Hook 架构                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌──────────────────────────────────────────────────┐           │
│  │              OpenCode Runtime (Bun)               │           │
│  │  ┌──────────┐    直接调用    ┌─────────────────┐  │           │
│  │  │ Core     │ ─────────────► │ Plugin Function │  │           │
│  │  │ System   │ ◄───────────── │ (Hook Handler)  │  │           │
│  │  └──────────┘   修改对象     └─────────────────┘  │           │
│  └──────────────────────────────────────────────────┘           │
│                                                                 │
│  特点: 同进程、编程接口、灵活扩展                                 │
└─────────────────────────────────────────────────────────────────┘

关键架构差异:

  1. 执行隔离 vs 共享运行时

    • Claude Code 的 Hook 在独立子进程中执行,崩溃不会影响主进程
    • OpenCode 的 Hook 与主系统共享运行时,异常可能导致系统不稳定
  2. 通信机制

    • Claude Code 使用 stdin/stdout + JSON 通信,跨语言兼容
    • OpenCode 直接操作 JavaScript 对象,类型安全但绑定语言
  3. 扩展性

    • Claude Code 专注于 Hook 功能,扩展性受限于预定义事件
    • OpenCode Hook 是插件系统的一部分,可结合工具注册、MCP 集成等实现更复杂功能

参考资料