--- name: agent_hooks_design description: 当需要继续讨论或实现本项目的 hooks / 生命周期钩子功能时,应该索引本记忆 --- # Hooks / 生命周期钩子功能设计讨论(进行中) ## 调研结论 ### 主流实现 - **Claude Code**:最完整,20+ 事件、5 种 handler(command/http/mcp_tool/prompt/agent)、多层配置(全局/项目/本地/组织/插件/SDK)。 - **OpenAI Codex**:11 个事件、command 回调为主、有信任审查机制和企业托管 hooks。 - **Cursor**:`.cursor/hooks.json`,Beta,command 回调,项目/用户/企业三级。 - **GitHub Copilot**:`.github/hooks/*.json`,command/http/prompt 三种回调,Cloud Agent 也支持。 - **Windsurf/Cascade**:`.windsurf/hooks.json`,exit 2 阻断,12 个事件。 - **Aider / Continue.dev / Kimi Code / Devin**:无原生 hooks 或资料有限。 ### 共性模式 ``` Agent 事件发生 ↓ stdin 发送 JSON 事件载荷 → Hook 脚本 / HTTP 端点 ↓ 返回决策(allow/deny/ask/modify/injectMessage) ↓ Agent 根据决策继续执行 ``` ## 用户(项目 owner)对 hooks 的理解 > 钩子 = 发生一件事件之前/中/后 → 自动触发另一个事件。用 JSON 格式写条件和行为,分为全局/项目级,放在数据存储目录下/工作区内。 用户认可的核心:**事件驱动 + JSON 配置 + 全局/项目两级 + before/after 拦截**。 ## 已达成的设计共识 ### 1. 配置位置 - 全局:`~/.astrion/astrion/config/hooks.json` - 项目级:`/.astrion/hooks.json` - 未来可扩展:`.astrion/hooks.local.json`、企业策略级。 - 多层配置**合并执行**,不是覆盖(更安全)。 ### 2. 优先事件(MVP 范围建议) - `PreToolUse`:工具执行前拦截/修改 - `PostToolUse`:工具执行后触发后续动作 - `Stop`:模型/turn 结束时注入反馈 - `PreCompact`:上下文压缩前备份 ### 3. 优先回调类型 - MVP 只做 `command`(shell/python/任意可执行文件)。 - 后续可扩展 `http`、`prompt`、`agent`、`mcp_tool`。 ### 4. 通信协议(对齐 Claude Code/Codex) - stdin 输入 JSON 事件载荷 - stdout 返回 JSON 决策 - exit code:0=通过,1=非阻断错误,2=阻断 ### 5. JSON 结构草案 ```json { "version": 1, "disabled": false, "hooks": { "PreToolUse": [ { "name": "block-dangerous-rm", "matcher": "run_command", "if": "command contains 'rm -rf /'", "enabled": true, "max_repeats": null, "hooks": [ { "type": "command", "command": "python3 ~/.astrion/astrion/hooks/block_dangerous.py", "timeout": 5, "statusMessage": "检查危险命令...", "fail_policy": "continue", "on_error": "log" } ] } ], "Stop": [ { "name": "remind-check-completion", "max_repeats": 3, "hooks": [ { "type": "command", "command": "python3 ~/.astrion/astrion/hooks/remind_check.py", "timeout": 5 } ] } ] } } ``` ## 已讨论的具体例子 ### 例子 1:拦截危险命令 - 事件:`PreToolUse` - 条件:`matcher=run_command` + `if=command contains 'rm -rf /'` - 行为:调用脚本,返回 `permissionDecision: deny` ### 例子 2:edit_file 单行全替换触发审核 - 事件:`PreToolUse` - 条件:`matcher=edit_file` + `old_string` 只有一行 + `replace_all=true` - 行为:返回 `permissionDecision: ask` ### 例子 3:Stop 时自动插入 user 消息,最多 3 次 - 事件:`Stop` - 行为:返回 `injectMessage: {role: "user", content: "请仔细检查是否真的完成了所有工作"}` - "最多 3 次"可用 `max_repeats` 或由脚本自己维护状态文件。 ## 尚未决定的决策点 1. **`if` 条件表达式语法**: - 选项 A:简单规则 DSL(如 `command contains '...'`) - 选项 B:结构化 JSON(如 `{"field": "...", "op": "contains", "value": "..."}`) - 选项 C:交给 hook 脚本自己判断,`if` 只保留工具名匹配 2. **"最多 N 次"由谁负责**: - 框架负责 `max_repeats`(简单,但状态语义固定) - 脚本自己维护状态文件(灵活,框架更轻量) 3. **注入消息语义**: - `injectMessage.user`:会触发模型再回复一轮 - `addContext.system`:只是给下一轮加提示,不立刻触发回复 4. **hook 失败时的主流程策略**: - 默认 `continue`(用户配置错误不瘫痪智能体) - 或提供 `fail_policy: block` 让管理员强制策略 5. **工具名匹配**: - 是否同时支持内部工具名(`run_command`/`edit_file`)和 Claude Code 风格别名(`Bash`/`Edit|Write`) ## 推荐后续路线 1. 先定 JSON schema 和 `if` 语法。 2. MVP 实现 `command` 回调 + `PreToolUse`/`PostToolUse`/`Stop`。 3. 新增 `modules/hook_manager.py`。 4. 在 `core/main_terminal_parts/tools_execution.py` 和 `core/web_terminal.py` 插入 hook 调用。 5. 确保 API task 模式也走 hooks。 6. 补文档 `docs/hooks.md`。 ## 参考资料位置 - 调研报告:`research/claudecode_hooks/claudecode_hooks.md` - 调研报告:`research/codex_hooks/codex_hooks.md` - 调研报告:`research/other_agents_hooks/other_agents_hooks.md`