# 三行速读

  1. Hook 系统让你在固定生命周期节点扩展行为,而不改 loop 主干。
  2. 返回码协议(继续 / 阻断 / 注入)让扩展行为可预测。
  3. 这章是 “横切能力工程化” 的起点。

# 先修知识

  • 理解 s07 的权限管道为何要集中在主流程。
  • 知道扩展点与主业务逻辑应分层。

# 读完后你应该能做到(可检验清单)

# 本篇要解决什么

系统越做越大后,一个常见问题是:每次加一点新行为,都要改主循环。久而久之,主循环会变得臃肿且难以测试。

s08 的目标是建立扩展插槽:在不改主循环结构的前提下,插入前后置行为。

# 用一个类比先理解

把主循环当 “高速公路主干道”,Hook 当 “收费站 / 监控站”:

  • 车流路线不变;
  • 但在固定节点可以做检查、记录、拦截、提示。

这样主干道稳定,扩展能力通过站点增长。

# 为什么这一步必须现在做

因为后续要接入更多横切能力(审计、策略、外部通知)。如果没有 hook 机制,所有需求都会挤进 loop,维护成本会指数上升。

# 关键代码怎么读

# 1) 先定义事件面

1
2
HOOK_EVENTS = ("PreToolUse", "PostToolUse", "SessionStart")
HOOK_TIMEOUT = 30

教学版只保留三个高价值事件,便于理解生命周期。

# 2) HookManager 负责装载与执行

1
2
3
4
5
6
class HookManager:
def __init__(...):
self.hooks = {"PreToolUse": [], "PostToolUse": [], "SessionStart": []}

def run_hooks(self, event: str, context: dict = None) -> dict:
...

职责边界清楚:读取配置、执行命令、返回聚合结果。

# 3) 返回码协议

1
2
3
4
5
6
if r.returncode == 0:
# continue
elif r.returncode == 1:
result["blocked"] = True
elif r.returncode == 2:
result["messages"].append(msg)

三态足够表达大多数场景:放行、阻断、注入提示。

# 4) workspace trust gate

1
2
3
4
def _check_workspace_trust(self) -> bool:
if self._sdk_mode:
return True
return TRUST_MARKER.exists()

先验证环境可信,再执行 hook,是非常重要的安全前置。

# 你可以怎么复现

  1. 配置一个 PreToolUse hook,对特定工具打印审计日志。
  2. 配置一个返回码 1 的 hook,验证阻断行为。
  3. 观察主循环结构是否无需改动。

# 常见误区

  • 误区 1:把主业务逻辑搬进 hook,导致行为不可控。
  • 误区 2:hook 超时策略缺失,影响主流程稳定性。
  • 误区 3:没有 trust gate,脚本执行面过大。

# 一句话总结

s08 的价值是 “把扩展做成机制”,而不是 “把需求堆进主循环”。

# 补充解读:Hook 系统的执行语义细节

# A. Hook 配置加载逻辑

1
2
3
config = json.loads(config_path.read_text())
for event in HOOK_EVENTS:
self.hooks[event] = config.get("hooks", {}).get(event, [])

这段定义了 Hook 的 “声明式扩展” 方式:不改 Python 主代码,通过配置就能扩行为。

# B. matcher 是 Hook 作用域控制器

1
2
3
4
5
matcher = hook_def.get("matcher")
if matcher and context:
tool_name = context.get("tool_name", "")
if matcher != "*" and matcher != tool_name:
continue

这意味着你可以把某个 hook 精确限定在单个工具上,而不是全局生效。

# C. Hook 环境变量注入

1
2
3
env["HOOK_EVENT"] = event
env["HOOK_TOOL_NAME"] = context.get("tool_name", "")
env["HOOK_TOOL_INPUT"] = json.dumps(context.get("tool_input", {}), ensure_ascii=False)[:10000]

这层注入给 hook 脚本足够上下文,让脚本能基于真实调用做判断。

# D. 可选 JSON stdout 协议

1
2
3
hook_output = json.loads(r.stdout)
if "updatedInput" in hook_output and context:
context["tool_input"] = hook_output["updatedInput"]

这让 Hook 不止能 “看” 和 “拦”,还能在受控范围内 “改输入”。非常适合做参数规范化。

# 进阶练习

  1. 写一个 PreToolUse hook,把高风险 bash 参数改成只读模式。
  2. 写一个 PostToolUse hook,把输出摘要写入日志系统。
  3. 对比 hook 超时前后主流程表现,验证超时隔离。

# 统一术语口径(本章)

  • Hook Event :预定义生命周期触发点(如 PreToolUse)。
  • Hook Contract :hook 返回码语义约定。
  • Trust Gate :未信任工作区禁止执行 hook 的安全门。

# 章节衔接(从易到难)

  • 本章解决 “扩展能力插槽化”。
  • 下一章 s09 进入 “跨会话记忆如何存、如何取、如何治理”。