[进阶篇18] 构建OpenCode事件钩子实现工作流自动化 前言你是不是每次改完代码都要手动跑一遍测试、格式化、lint检查或者每次PR合并后都要手动去更新文档、发通知、部署这些重复的手工操作明明可以让AI自动替你完成。上篇我们优化了大型项目的上下文管理AI在处理百万行代码时也能保持清醒了。但现在还有一个“效率黑洞”没解决——大量重复的手工操作依然占据着你的时间。代码提交后的测试、文件修改后的格式化、会话结束后的通知……这些能不能让OpenCode自动完成建议先点个关注收藏这个专栏这篇我们来用OpenCode的事件钩子系统构建自动化工作流——让AI在文件修改后自动跑测试、在会话结束后自动发通知、在工具调用前自动做安全检查真正实现“写代码剩下的交给OpenCode”。上篇回顾上篇我们构建了四层上下文管理体系——用/compact做被动压缩、用ACP做智能剪枝、用DCP做自动清理、用Context Manager做预索引大型项目中的AI上下文终于不再“爆炸”了。现在AI的“脑子”够用了但手脚还不够勤快。每次你做完一件事还得手动触发下一件事——改完代码要手动跑测试、写完文档要手动提交、会话结束要手动通知。本篇就是给OpenCode装上“自动化的手脚”——让它在合适的时机自动执行合适的动作。环境与前置说明本篇依赖上篇的产出成果OpenCode已安装并可用熟悉插件开发的基本流程event钩子了解TypeScript/JavaScript插件编写本篇会用到以下插件# YAML Hooks插件——声明式自动化推荐入门opencode plugin opencode-yaml-hooks-gf# 或者手动安装如果上述命令不生效bunaddopencode-yaml-hooksopencode-yaml-hooks是目前最成熟的声明式钩子方案。它通过hooks.yaml文件配置自动化规则不需要写TypeScript代码适合90%的自动化场景。如果你需要更复杂的逻辑也可以用TypeScript插件直接订阅event钩子。文章目录前言上篇回顾环境与前置说明核心内容第一步理解“事件钩子”到底是什么第二步安装opencode-yaml-hooks——零代码自动化第三步配置第一个自动化规则——文件修改后自动格式化第四步配置工具执行前后的钩子——安全门禁第五步配置会话生命周期钩子——会话开始/结束自动化第六步高级钩子配置——scope、runIn与async第七步综合实战——构建完整的自动化工作流异常处理与常见坑报错1YAML格式错误导致钩子不生效报错2action: stop不生效危险操作仍然执行报错3file.changed钩子在文件修改后没有触发本章产出总结作者互动与资源引导下篇预告核心内容第一步理解“事件钩子”到底是什么目标搞清楚OpenCode的事件钩子系统是什么以及它能用来做什么自动化。你可能会问事件钩子不就是监听事件吗跟前面学的event钩子有什么区别OpenCode的事件钩子系统本质上是同一个东西——插件通过event钩子订阅系统事件。但“事件钩子”这个概念在OpenCode生态里有两种不同的使用方式方式一声明式YAML钩子opencode-yaml-hooks在hooks.yaml文件中定义“当X事件发生时执行Y动作”。不需要写代码适合快速配置自动化规则。方式二程序式TypeScript钩子在TypeScript插件中直接订阅event钩子用代码实现复杂的自动化逻辑。OpenCode的事件系统基于中央总线event bus运作组件发布事件如session.created、file.edited、tool.execute.before总线将事件分发给所有订阅者插件通过event钩子消费事件你可以在插件中订阅33种以上的系统事件覆盖会话生命周期、文件变更、消息流、工具执行、LSP诊断等全场景。注意了声明式YAML钩子和程序式TypeScript钩子不是互斥的。你可以同时使用两者——用YAML钩子处理简单的文件变更自动化用TypeScript插件处理复杂的业务逻辑。运行验证这一步不需要跑代码。你只需要记住一个核心概念——事件钩子 “当X发生时自动做Y”。第二步安装opencode-yaml-hooks——零代码自动化目标安装YAML Hooks插件让自动化配置像写配置文件一样简单。声明式YAML钩子是入门自动化的最快方式。你不用写一行TypeScript代码只需要在一个YAML文件里描述“什么事件触发什么动作”。安装方式# 通过opencode plugin命令安装opencode plugin opencode-yaml-hooks-gf# 或者用bun直接安装如果上述命令不生效bunaddopencode-yaml-hooks然后在opencode.json中注册插件{$schema:https://opencode.ai/config.json,plugin:[opencode-yaml-hooks]}创建钩子配置文件。YAML Hooks支持全局和项目两个位置类型路径作用范围全局~/.config/opencode/hook/hooks.yaml所有项目生效项目项目根目录/.opencode/hook/hooks.yaml仅当前项目生效注意了全局钩子先加载项目钩子后加载项目钩子可以覆盖或扩展全局钩子。运行验证安装完成后在TUI中输入/hooks如果插件支持该命令或者检查插件是否在列表中opencode plugin list|grepyaml-hooks如果能看到opencode-yaml-hooks说明安装成功。第三步配置第一个自动化规则——文件修改后自动格式化目标配置一个file.changed钩子让OpenCode在文件修改后自动运行代码格式化。这是最常用、也最安全的自动化场景——你改完代码OpenCode自动帮你格式化。创建项目级钩子配置文件mkdir-p.opencode/hooktouch.opencode/hook/hooks.yaml在.opencode/hook/hooks.yaml中写入# .opencode/hook/hooks.yaml# 钩子规则列表hooks:# 规则1代码文件修改后自动格式化-event:file.changed# 触发事件文件被修改conditions:# 条件只匹配代码文件-matchesCodeFiles# 内置条件匹配 .ts, .js, .py 等actions:# 动作执行格式化-bash:npx prettier --write {{ .Paths }}# 用Prettier格式化修改的文件# 规则2TypeScript文件修改后自动运行类型检查-event:file.changedconditions:-matchesAnyPath:**/*.ts# 匹配所有TypeScript文件-matchesAnyPath:**/*.tsx# 匹配所有TSX文件actions:-bash:npx tsc --noEmit# 运行TypeScript类型检查逐行解释一下event: file.changed当任何文件被修改时触发conditions可选的条件过滤只有满足条件才执行动作matchesCodeFiles内置条件匹配常见的代码文件扩展名matchesAnyPath自定义路径匹配支持glob模式actions要执行的动作列表可以是bash命令、command命令或tool调用{{ .Paths }}模板变量会被替换为实际修改的文件路径列表注意了file.changed是最干净的文件级钩子适合linting、格式化、测试选择、索引和原子提交等工作流。它会自动去重——同一个文件在短时间内多次修改只会触发一次钩子。运行验证保存配置文件后在项目中修改一个代码文件比如改一行代码然后保存。观察终端——你应该能看到Prettier自动运行并且修改的文件被格式化了。第四步配置工具执行前后的钩子——安全门禁目标在AI调用危险工具如bash、edit前后插入安全检查或日志记录。tool.before.*和tool.after.*钩子让你在AI执行工具的前后插入自定义逻辑。在.opencode/hook/hooks.yaml中添加hooks:# 之前的规则保持不变...# 规则3禁止读取.env文件-event:tool.before.read# 在read工具执行前触发action:stop# 阻止工具执行conditions:-matchesAnyPath:**/.env# 匹配.env文件-matchesAnyPath:**/.env.*# 匹配.env.local等actions:-bash:|echo ❌ 安全策略禁止读取 .env 文件 exit 2 # 退出码2触发action: stop# 规则4危险命令执行前记录审计日志-event:tool.before.bash# 在bash工具执行前触发actions:-bash:|echo [AUDIT] $(date): AI 执行命令: {{ .Command }} echo [AUDIT] $(date): AI 执行命令: {{ .Command }} .opencode/audit.log# 规则5文件修改后自动运行测试-event:tool.after.edit# 在edit工具执行后触发conditions:-matchesCodeFilesactions:-bash:npm test -- --findRelatedTests {{ .Paths }}逐行解释一下tool.before.read在read工具执行前触发action: stop配合bash脚本的exit 2可以阻止工具执行tool.before.bash在bash工具执行前触发适合审计和命令过滤tool.after.edit在edit工具执行后触发适合运行测试或索引{{ .Command }}模板变量在tool.before.bash中表示要执行的命令注意了action: stop仅在tool.before.*钩子上有效且需要bash脚本以exit 2退出。如果脚本以其他状态码退出钩子会继续执行但不会阻止工具。运行验证配置完成后在TUI中让AI“读取.env文件的内容”。AI应该会收到错误提示无法读取该文件。再让AI执行一个bash命令如ls -la检查.opencode/audit.log中是否出现了审计记录。第五步配置会话生命周期钩子——会话开始/结束自动化目标在会话创建、删除、空闲时触发自动化动作。会话级别的钩子让你在会话的整个生命周期中插入自动化逻辑。在.opencode/hook/hooks.yaml中添加hooks:# 之前的规则保持不变...# 规则6会话创建时加载项目上下文-event:session.created# 新会话创建时触发actions:-bash:|echo 新会话已创建: $(date) echo 新会话已创建: $(date) .opencode/session.log# 规则7会话空闲时自动生成总结-event:session.idle# 会话变为空闲时触发actions:-bash:|echo ✅ 会话完成: $(date) # 可以在这里触发通知、提交代码等# 规则8会话删除时清理临时文件-event:session.deleted# 会话被删除时触发actions:-bash:rm -rf .opencode/temp/*# 清理临时文件逐行解释一下session.created新会话创建时触发session.idle会话变为空闲时触发注意session.idle已弃用建议用session.status检测Agent完成工作session.deleted会话被删除时触发注意了session.idle钩子不支持async: true且不能用于阻止会话结束——它只是一个“通知”钩子。运行验证配置完成后启动一个新会话。检查.opencode/session.log中是否出现了“新会话已创建”的记录。完成对话后退出检查是否出现了“会话完成”的记录。第六步高级钩子配置——scope、runIn与async目标了解钩子的高级配置选项精细控制钩子的作用范围和执行方式。YAML Hooks提供了三个高级配置字段让你精细控制钩子的行为。scope控制钩子触发范围值含义all默认主会话和子会话都可以触发main只有根会话可以触发child只有子会话可以触发-event:file.changedscope:main# 只在根会话中触发actions:-bash:npm run build# 构建任务只在根会话中运行runIn控制动作执行位置值含义current默认在触发钩子的会话中执行main在根会话中执行-event:tool.after.editrunIn:main# 在根会话中执行actions:-bash:git add . git commit -m auto: formatasync异步执行当async: true时钩子立即返回动作在后台异步执行。适合不阻塞主流程的任务。-event:file.changedasync:true# 异步执行不阻塞actions:-bash:npm run lint# linting在后台运行注意了async: true不能用于tool.before.*和session.idle钩子。异步钩子只能使用bash动作。运行验证配置一个带scope: main和async: true的钩子在子会话中触发它观察动作是否在根会话中异步执行。第七步综合实战——构建完整的自动化工作流目标把前面学到的所有钩子组合起来构建一个“编码 → 格式化 → 测试 → 审计”的完整自动化流水线。现在我们把所有技能整合到一个完整的hooks.yaml中# .opencode/hook/hooks.yaml# 完整的自动化工作流配置hooks:# 文件变更自动化 # 1. 代码文件修改后自动格式化-id:auto-format# 可选ID用于后续覆盖event:file.changedconditions:-matchesCodeFilesactions:-bash:npx prettier --write {{ .Paths }}# 2. 测试文件修改后自动运行对应测试-event:file.changedconditions:-matchesAnyPath:**/*.test.ts-matchesAnyPath:**/*.spec.tsactions:-bash:npm test -- --findRelatedTests {{ .Paths }}# 3. 文档文件修改后自动更新索引-event:file.changedconditions:-matchesAnyPath:docs/**/*.mdasync:true# 异步执行不阻塞actions:-bash:npm run docs:build# 工具执行安全 # 4. 禁止读取敏感文件-event:tool.before.readaction:stopconditions:-matchesAnyPath:**/.env-matchesAnyPath:**/.env.*-matchesAnyPath:**/secrets.jsonactions:-bash:|echo ❌ 安全策略禁止读取敏感文件 exit 2# 5. 危险命令审计-event:tool.before.bashactions:-bash:|echo [AUDIT] $(date) | 命令: {{ .Command }} .opencode/audit.log# 6. 限制危险命令仅示例不实际执行-event:tool.before.bashaction:stopconditions:-matchesAnyPath:rm -rf /# 匹配危险命令actions:-bash:|echo ❌ 安全策略禁止执行危险命令 exit 2# 会话生命周期 # 7. 会话创建时记录-event:session.createdscope:mainactions:-bash:|echo [SESSION] 创建: $(date) .opencode/session.log# 8. 会话完成时自动总结和提交-event:session.idlescope:mainrunIn:mainactions:-bash:|echo [SESSION] 完成: $(date) .opencode/session.log # 如果有未提交的改动自动提交 if [ -n $(git status --porcelain) ]; then git add . git commit -m auto: OpenCode session completed at $(date) fi逐行解释关键配置id: auto-format给钩子一个唯一ID方便后续在另一个配置文件中覆盖或禁用matchesAnyPath支持glob模式匹配文件路径多个actions按顺序执行任意一个失败会中断后续动作scope: mainrunIn: main确保提交操作只在根会话中执行一次运行验证完成配置后在一个真实项目中正常使用OpenCode完成一次编码任务。观察修改代码文件后Prettier是否自动运行如果修改了测试文件对应的测试是否自动运行尝试让AI读取.env文件是否被阻止会话结束后.opencode/session.log中是否有记录如果有未提交的改动是否被自动提交异常处理与常见坑报错1YAML格式错误导致钩子不生效配置了hooks.yaml但没有任何钩子被触发原因YAML文件格式错误——缩进不对、缺少必要字段、或者字段名拼写错误。解决方案用YAML验证工具检查格式如yamllint hooks.yaml确认hooks是数组以-开头确认每个钩子都有event字段确认每个钩子都有非空的actions数组重启OpenCode后查看启动日志是否有解析错误报错2action: stop不生效危险操作仍然执行配置了tool.before.read action: stop但AI仍然读取了敏感文件原因action: stop需要bash脚本以exit 2退出才能触发阻止逻辑。解决方案确认bash脚本中使用了exit 2actions:-bash:|echo 阻止执行 exit 2 # 必须用 exit 2确认钩子是tool.before.*类型action: stop只支持pre-tool钩子检查是否有其他钩子覆盖了该规则查看OpenCode日志确认钩子是否被触发报错3file.changed钩子在文件修改后没有触发修改了文件但file.changed钩子没有执行原因file.changed只对通过OpenCode工具如edit、write修改的文件生效对你在IDE中手动修改的文件不触发。解决方案确认文件修改是通过OpenCode的edit或write工具完成的如果需要在IDE中手动修改后也触发考虑使用文件系统监听工具如watchman配合外部脚本检查conditions是否过滤掉了你的文件——用matchesAnyPath: **/*测试是否所有文件都能触发确认hooks.yaml文件路径正确项目/.opencode/hook/hooks.yaml本章产出总结完成本篇后你获得了以下能力/产出序号产出物/能力说明1理解事件钩子系统知道OpenCode的事件驱动架构和33种事件类型2YAML Hooks安装安装了opencode-yaml-hooks插件3文件变更自动化配置了file.changed钩子自动格式化代码4安全门禁配置了tool.before.*钩子阻止读取敏感文件5会话生命周期自动化配置了session.created和session.idle钩子6高级钩子配置掌握了scope、runIn、async的用法7完整自动化流水线构建了“编码→格式化→测试→审计”的完整工作流事件钩子让OpenCode从“你指挥它干活”变成了“它自己找活干”。从今天开始你的每一次代码修改都会自动触发格式化、测试、审计——你只需要专注于写代码剩下的重复工作交给OpenCode的钩子系统。作者互动与资源引导你在配置自动化钩子的过程中有没有遇到什么特别的需求或者你写了什么好用的钩子规则想跟大家分享欢迎在评论区留言我看到就会回复——自动化工作流的可能性是无限的每个人的场景都不一样期待看到你的创意。如果觉得这个专栏对你有帮助关注我后续每一篇更新你都不会错过关注后私信我发送暗号“爱学Python”我会把Python全栈学习路线图和本专栏的源码包发给你我们还有一个技术交流群群里的小伙伴们每天都在讨论OpenCode的各种自动化玩法。想进群的朋友在评论区扣个“1”我拉你进来。下篇预告下一篇是[[项目篇19] 初始化OpenCode智能问答机器人项目结构]我们会进入专栏的项目实战篇——从零开始搭建一个基于OpenCode的智能问答机器人把前面学到的所有知识插件开发、向量记忆、多模型路由、事件钩子整合到一个真实项目中。如果本篇对你有帮助点赞、收藏、关注走一波咱们下篇见