Archon DAG 节点 Hooks 实战指南:用 Claude Agent SDK 钩子控制工具、注入上下文与改写输入
【免费下载链接】ArchonThe first open-source harness builder for AI coding. Make AI coding deterministic and repeatable.项目地址: https://gitcode.com/GitHub_Trending/archon3/Archon
Archon 的 DAG 工作流节点支持hooks字段,可将 Claude Agent SDK 钩子(Hooks)直接挂载到单个节点上,在节点 AI 执行期间控制工具行为、注入上下文、修改工具输入,甚至紧急终止 Agent。读完本篇,你将掌握从快速上手、事件选型到响应格式、源码级原理的完整 Per-Node Hooks 实战方案,并能在自己的安全迁移、只读审查等工作流中直接落地。
重要前置条件:Hooks 仅对 Claude 生效。Codex 节点会对 hooks 发出警告并忽略(详见下文"源码证据"一节的 capability 检查)。
快速开始
在任意 AI 节点的 YAML 定义中声明hooks字段即可。下面的例子实现了一个"带护栏的 SQL 迁移生成"工作流——生成迁移的节点完全禁用 Bash:
name: safe-migration description: Generate SQL with guardrails nodes: - id: generate prompt: "Generate a database migration for $ARGUMENTS" hooks: PreToolUse: - matcher: "Bash" response: hookSpecificOutput: hookEventName: PreToolUse permissionDecision: deny permissionDecisionReason: "No shell access during SQL generation"这个声明式写法与 Archon 的 YAML 工作流体系完全一致:hooks定义在packages/workflows/src/schemas/dag-node.ts的节点 schema 之上,并由 hooks schema 负责校验。
工作原理
每个 hook matcher 有三个字段:
| 字段 | 是否必填 | 说明 |
|---|---|---|
matcher | 可选 | 用于按工具名过滤的正则表达式;省略则匹配所有工具 |
response | 必填 | 钩子触发时返回的 SDKSyncHookJSONOutput |
timeout | 可选 | 钩子超时秒数(默认 60) |
运行时,每个 YAML hook 都会被包装成一个极简回调:
async () => response没有自定义 DSL——response本身就是 SDK 类型,原样透传、不做任何改写。这一点在源码中有直接印证:buildSDKHooksFromYAML将每个 matcher 映射为hooks: [async (): Promise<unknown> => m.response](见 provider.ts)。
关键约束:使用hookSpecificOutput时,必须包含与事件键一致的hookEventName字段(例如在PreToolUse钩子内部写hookEventName: PreToolUse)。这是 SDK 的硬性要求——SDK 依靠该字段决定处理哪些事件专属字段,缺失会导致响应无法被正确解析。
支持的 Hook 事件
| 事件 | 触发时机 | matcher 过滤依据 |
|---|---|---|
PreToolUse | 工具执行前 | 工具名(如Bash、Write、Read) |
PostToolUse | 工具成功之后 | 工具名 |
PostToolUseFailure | 工具失败之后 | 工具名 |
Notification | 系统通知 | 通知类型 |
Stop | Agent 停止 | 不适用 |
SubagentStart | 子 Agent 生成 | Agent 类型 |
SubagentStop | 子 Agent 结束 | Agent 类型 |
PreCompact | 上下文压缩之前 | 触发器(manual/auto) |
SessionStart | 会话开始 | 来源(startup/resume/clear/compact) |
SessionEnd | 会话结束 | 退出原因 |
UserPromptSubmit | 用户提示词提交 | 不适用 |
PermissionRequest | 权限提示即将出现 | 工具名 |
Setup | SDK 初始化 | 触发器(init/maintenance) |
TeammateIdle | Agent 队友空闲 | 不适用 |
TaskCompleted | 后台任务完成 | 不适用 |
Elicitation | MCP 服务器请求用户输入 | 不适用 |
ElicitationResult | Elicitation 响应收到 | 不适用 |
ConfigChange | 设置/配置文件变更 | 来源(user_settings/project_settings等) |
WorktreeCreate | Git worktree 创建 | Worktree 名称 |
WorktreeRemove | Git worktree 移除 | Worktree 路径 |
InstructionsLoaded | CLAUDE.md/instructions 加载 | 记忆类型(User/Project/Local/Managed) |
工具名参考:Bash、Read、Write、Edit、Glob、Grep、WebFetch、Agent,以及 MCP 工具mcp__<server>__<action>。
这 21 个事件在 Archon 中被完整登记为 Zod 枚举(workflowHookEventSchema,见 hooks.ts),并通过.strict()拒绝任何拼写错误的事件名(例如preToolUse会被直接判为非法),从而在 YAML 解析阶段就能暴露 typo,而不是留到运行时静默失效。对应地,hooks.test.ts 中有专门用例验证"未知事件名会推入错误"这一行为。
响应格式(SDKSyncHookJSONOutput)
response对象支持以下字段:
| 字段 | 类型 | 效果 |
|---|---|---|
hookSpecificOutput | object | 事件专属响应(见下) |
systemMessage | string | 注入一条对模型可见的消息 |
continue | boolean | false表示停止 Agent |
decision | 'approve'/'block' | 顶层同意/阻止 |
stopReason | string | 停止时的原因说明 |
suppressOutput | boolean | 抑制输出发出 |
PreToolUse 的hookSpecificOutput
hookSpecificOutput: hookEventName: PreToolUse permissionDecision: deny | allow | ask # 控制工具是否执行 permissionDecisionReason: "..." # 原因(显示在日志中) updatedInput: # 修改工具参数 file_path: "/sandbox/output.ts" additionalContext: "..." # 注入到模型上下文中的文本PostToolUse 的hookSpecificOutput
hookSpecificOutput: hookEventName: PostToolUse additionalContext: "..." # 在工具结果之后注入的文本 updatedMCPToolOutput: ... # 覆盖模型看到的工具输出PostToolUseFailure 的hookSpecificOutput
hookSpecificOutput: hookEventName: PostToolUseFailure additionalContext: "..." # 工具失败后的上下文Elicitation 的hookSpecificOutput
hookSpecificOutput: hookEventName: Elicitation action: accept | decline | cancel # 响应 MCP elicitation content: { ... } # 表单字段值ElicitationResult 的hookSpecificOutput
hookSpecificOutput: hookEventName: ElicitationResult action: accept | decline | cancel # 覆盖 elicitation 结果 content: { ... } # 修改后的响应值实战示例
完全禁止某个工具
hooks: PreToolUse: - matcher: "Bash" response: hookSpecificOutput: hookEventName: PreToolUse permissionDecision: deny permissionDecisionReason: "Shell access not allowed in this node"带原因消息禁止工具
hooks: PreToolUse: - matcher: "Write|Edit" response: hookSpecificOutput: hookEventName: PreToolUse permissionDecision: deny permissionDecisionReason: "Only read operations are allowed — do not modify files"注意matcher是正则表达式,"Write|Edit"可以一次性匹配多个工具名。
工具使用前注入上下文(不拦截)
注意:这种方式不会阻止工具执行——它只是在工具运行前给模型追加指导。
hooks: PreToolUse: - matcher: "Write|Edit" response: hookSpecificOutput: hookEventName: PreToolUse additionalContext: "Only write to files in the src/ directory"重定向文件写入(修改工具输入)
hooks: PreToolUse: - matcher: "Write" response: hookSpecificOutput: hookEventName: PreToolUse permissionDecision: allow updatedInput: file_path: "/sandbox/output.ts"这里通过updatedInput改写工具参数,把写入目标强制重定向到沙箱目录。
每次工具调用后注入纠偏指令
hooks: PostToolUse: - response: systemMessage: "Check: is this output relevant to the task? If not, stop and explain why."注意此处省略了matcher,表示匹配所有工具;systemMessage直接给模型下达可见指令。
读取文件后注入上下文
hooks: PostToolUse: - matcher: "Read" response: hookSpecificOutput: hookEventName: PostToolUse additionalContext: "You just read a file. Do NOT modify it — analysis only."Shell 访问时紧急停机
hooks: PreToolUse: - matcher: "Bash" response: continue: false stopReason: "Emergency halt — shell access attempted"这是比deny更强硬的措施:continue: false会直接停止 Agent,而不仅仅是拒绝这一次工具调用。
单个节点上的多重 hooks
hooks: PreToolUse: - matcher: "Bash" response: hookSpecificOutput: hookEventName: PreToolUse permissionDecision: deny permissionDecisionReason: "No shell" - matcher: "Write|Edit" response: hookSpecificOutput: hookEventName: PreToolUse additionalContext: "Only write to files in src/" PostToolUse: - response: systemMessage: "Verify output before continuing"同一事件下可以声明多条 matcher,Archon 会按声明顺序依次注册(buildSDKHooksFromYAML中对每个 matcher 生成独立条目,见 provider.ts)。
完整工作流示例
name: safe-code-review description: Review code with guardrails nodes: - id: fetch-diff bash: "git diff main...HEAD" - id: review prompt: "Review this diff for bugs and security issues: $fetch-diff.output" depends_on: [fetch-diff] hooks: PreToolUse: - matcher: "Bash" response: hookSpecificOutput: hookEventName: PreToolUse permissionDecision: deny permissionDecisionReason: "Code review should not execute commands" - matcher: "Write|Edit" response: hookSpecificOutput: hookEventName: PreToolUse permissionDecision: deny permissionDecisionReason: "Code review is read-only" PostToolUse: - matcher: "Read" response: hookSpecificOutput: hookEventName: PostToolUse additionalContext: "Focus on security issues in this file" - id: summarize prompt: "Summarize the review findings from $review.output" depends_on: [review] allowed_tools: []该示例展示了 hooks 与 DAG 的组合用法:fetch-diff是纯 bash 节点(bash 节点不会执行 hooks,见 hooks.test.ts 中"bash 节点上的 hooks 被忽略"的测试);review节点用 hooks 建立只读护栏;summarize节点则通过allowed_tools: []关闭全部工具。
Hooks vs allowed_tools/denied_tools
| 特性 | allowed_tools/denied_tools | hooks |
|---|---|---|
| 完全阻止工具 | 是 | 是 |
| 注入上下文 | 否 | 是(additionalContext、systemMessage) |
| 修改工具输入 | 否 | 是(updatedInput) |
| 覆盖工具输出 | 否 | 是(updatedMCPToolOutput) |
| 停止 Agent | 否 | 是(continue: false) |
| 工具使用后的反应 | 否 | 是(PostToolUse) |
选型建议:简单的包含/排除用allowed_tools/denied_tools;需要上下文注入、输入改写或工具调用后反应时,选择hooks。两者也可以同时声明、各司其职——例如上面"完整工作流示例"中review节点用 hooks 做护栏、summarize节点用allowed_tools: []做全禁。
限制
- YAML 中只有静态响应—— hooks 每次都返回相同的 response。需要条件逻辑时,请在下游节点上使用
when:条件,或通过输出结构化结果的上游 bash 节点来门控执行。 - 仅 Claude—— Codex 节点会警告并忽略 hooks。
- 无 hook 事件流—— hook 生命周期事件(
hook_started、hook_progress)不会转发到 Web UI。
源码级原理:从 YAML 到 SDK 钩子的完整链路
如果想知道 hooks 在 Archon 内部如何从 YAML 变成真正的 SDK 钩子,可以沿着下面这条调用链阅读源码:
YAML 解析与校验:
parseNodeHooks使用workflowNodeHooksSchema(Zod)对原始 YAML 进行校验,未知事件、非对象response、缺response的 matcher 都会被收集进错误列表;空事件数组会被过滤掉,全部为空时 hooks 字段整体返回undefined(见 loader.ts 与 hooks.test.ts 中的大量边界用例)。节点配置透传:dag-executor 在构建节点配置时把
hooks原样写入nodeConfig(见 dag-executor.ts),交由 provider 内部自行翻译。SDK 钩子构建:Claude provider 的
buildSDKHooksFromYAML把每个 matcher 转换为 SDK 的HookCallbackMatcher——matcher与timeout原样透传,response被包装成async () => m.response的零逻辑回调(见 provider.ts)。测试中已明确验证"回调返回的正是原 response 对象、不做任何改动"(hooks.test.ts)。能力警告:
dag-executor的 capability 检查表把hooks与 provider 的hooks能力位挂钩——Claude 的 capabilities 声明hooks: true(见 capabilities.ts),而 Codex 未声明该能力,于是声明了 hooks 的节点在运行时会被警告"该能力将被忽略"(见 dag-executor.ts)。工作流验证器validator.ts同样会对不支持的 provider 给出Remove the hooks field or switch to a provider that supports hooks的提示(见 validator.ts)。
这套"静态 YAML → 校验 → 透传 → SDK 包装 → 能力门控"的链路,正是声明式 hooks 无需自定义 DSL 却能稳定工作的原因。
SDK 参考与延伸阅读
关于SyncHookJSONOutput类型的权威定义、全部 hook 事件参考以及 matcher 模式,请查阅 Claude Agent SDK 官方文档(Anthropic 的 Claude Code SDK 页面)。
相关指南:
- Per-Node MCP Servers —— 通过
mcp:字段接入外部工具 - Per-Node Skills —— 通过
skills:字段注入领域知识 - 工作流编写指南 —— hooks 所依赖的 DAG 节点与
when:条件体系
【免费下载链接】ArchonThe first open-source harness builder for AI coding. Make AI coding deterministic and repeatable.项目地址: https://gitcode.com/GitHub_Trending/archon3/Archon
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考