首页 › tutorials › 文件监听造事件驱动自动化Agent

文件监听造事件驱动自动化Agent

概述

本教程教你把 Claude Code 从"你敲一行、它回一句"的交互式工具,改造成一个被外部事件驱动的常驻 Agent:文件一保存、日志一出错、定时一到点,它就自动接管任务、调用子代理、跑完闭环。核心组合是 watchexec/entr 文件监听 + -p 头部模式 + --output-format stream-json 流式输出 + Stop/PostToolUse 钩子防跑飞。适合想用 Claude Code 搭建"代码守护进程""日志自愈机器人""保存即审查"流水线的开发者和 DevOps 工程师。

前置条件

核心心智模型:事件驱动 vs 交互式

传统 Claude Code 用法是交互式的:打开终端、输入提示、来回迭代。事件驱动自动化则把这个模型翻转过来——没有人类在键盘前,取而代之的是一个外部事件源(文件变化、cron、webhook、日志行),事件一发生就拉起一次 claude -p 调用。

这套模型有三个关键差异点:

  1. 触发是无人的:事件源决定"何时跑",不是你决定。
  2. 输出是结构化的:人类不在场看不懂自由文本,所以必须用 --output-format json 或 stream-json,让下游脚本能解析。
  3. 必须有护栏:无人值守最大的风险是"跑飞"——无限循环、改坏文件、烧光额度。护栏由 hooks 提供。

第一步:把 Claude Code 装进文件监听器

事件驱动的"事件源",最常用的是文件系统变化。watchexec 是跨平台首选,entr 更轻量。

先安装监听器:

# macOS
brew install watchexec entr jq

# Linux (Debian/Ubuntu)
sudo apt install entr jq
cargo install watchexec-cli   # 或从 release 下载二进制

# 验证
watchexec --version && jq --version

最朴素的"保存即审查"可以这样跑起来——在项目根目录执行:

# 监听所有 .py 文件变化,一变就审查
watchexec -e py -- claude -p "审查 src/ 下最近修改的 Python 文件,指出潜在 bug,输出 JSON:{file, issues:[{line, severity, message}]}"

预期结果:你随便改一个 src/foo.py 并保存,watchexec 检测到变化,立刻拉起一次 claude -p 调用,几秒后终端打印出该文件的审查结果。每保存一次就跑一次,全程无需你按回车。

常见问题:

第二步:用脚本把事件和 Agent 粘合起来

裸用 watchexec -- claude -p 太粗。真正的事件驱动需要把事件元数据喂给 Agent。下面这个脚本 monitor.sh 是生产可用的最小骨架:

#!/usr/bin/env bash
# monitor.sh —— 文件变化驱动的自动审查守护进程
set -euo pipefail

WATCH_DIR="${1:-src}"
EVENT_FILE="$2"   # watchexec 会把变化的文件路径写进这个变量

# 关键:用 --bare 跳过 hooks/MCP 自动发现,启动更快,守护进程更稳
# 用 --output-format json 拿结构化结果,用 --add-dir 让 Agent 能读全项目上下文
claude --bare -p \
  --add-dir "$WATCH_DIR" \
  --output-format json \
  "我刚修改了文件:$EVENT_FILE。
请:
1. 读这个文件
2. 找出 bug、坏味道、安全问题
3. 如果有严重问题(severity=critical),用 Edit 工具直接修复
4. 最后用 JSON 输出摘要:{file, fixed:[bool], issues:[...], summary}" \
  | jq '.'   # 格式化输出,方便人眼和下游管道读取

让 watchexec 把变化文件路径传进来:

watchexec -w src -e py \
  --shell=none \
  -- ./monitor.sh src "{$WATCHEXEC_COMMON_PATH}"

这里 {$WATCHEXEC_COMMON_PATH} 是 watchexec 的占位符,会被替换成实际变化的文件相对路径。

预期结果:保存 src/api.py,终端先打印一段 JSON,其中 fixed: true 且列出修复的问题——说明 Agent 不只是审查,还自动改了代码。

常见问题:

第三步:用 stream-json 做实时流水线

json 模式是一次性等到底才出结果,长任务(自动修 bug 可能要几十秒)期间终端一片黑。事件驱动场景下你往往想看到实时进度,用 stream-json:

claude --bare -p \
  --output-format stream-json \
  --verbose \
  "修复 src/auth.py 里的所有 lint 错误" \
  | jq --unbuffered -r 'select(.type=="tool_use") | "🔧 调用工具: \(.name) → \(.input.file_path // "")"'

stream-json 会逐行吐出 JSON 事件:system(初始化)、assistant(模型思考)、tool_use(要调工具)、tool_result(工具返回)、result(最终结果)。用 jq 过滤 tool_use 事件,就能实时打印"Agent 正在读哪个文件、改哪个文件",相当于一个简易进度监控。

预期结果:终端像日志流一样滚动输出 Agent 的每一步动作,而不是干等几十秒。

第四步:装上 hooks 护栏,防止无人值守跑飞

事件驱动 Agent 最大的风险是失控循环:Agent 改了文件 → 触发文件监听 → 又拉起一次 Agent → 又改文件……死循环。Claude Code 的 hooks 是确定性护栏,不依赖模型"自觉"。

在 .claude/settings.json 配置:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/guards/no-overwrite-guard.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "ruff format \"$(jq -r '.tool_input.file_path' )\" 2>/dev/null || true"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/guards/stop-queue.sh"
          }
        ]
      }
    ]
  }
}

三个钩子各司其职:

护栏脚本 .claude/guards/no-overwrite-guard.sh:

#!/usr/bin/env bash
# 阻止 Agent 覆盖受保护文件(如锁文件、生成产物)
INPUT="$(cat)"
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path')

# 保护模式:禁止动这些
if [[ "$FILE_PATH" =~ (package-lock\.json|\.env|dist/|build/) ]]; then
  echo "禁止修改受保护文件: $FILE_PATH" >&2
  exit 2   # exit code 2 = 阻止该工具调用,把 stderr 反馈给 Agent
fi
exit 0      # exit code 0 = 放行

关于 Stop hook 的硬限制(必须知道):Claude Code 规定,如果 Stop hook 连续 8 次让 Agent 继续跑(即不停让模型"再做一轮"),第 9 次会被强制打断。这是为了防止无限循环。设计 Stop hook 时不要试图用它实现"永远不停",而是用来排空一个有限的任务队列。

第五步:用 Stop hook + 任务队列实现"自驱动到完成"

真正的事件驱动不是"跑一次就停",而是"一个事件触发后,Agent 自己把一组相关任务跑完"。这需要把待办任务持久化到文件,用 Stop hook 检查队列。

任务队列设计——/tmp/cc-tasks.txt,一行一个任务:

审查 src/auth.py 并修复 lint
审查 src/api.py 并修复 lint
跑 pytest 并修复失败的用例

Stop hook 脚本 .claude/guards/stop-queue.sh:

#!/usr/bin/env bash
# Agent 想停时,检查是否还有未完成任务
QUEUE="/tmp/cc-tasks.txt"

if [[ ! -s "$QUEUE" ]]; then
  # 队列空,真正结束
  exit 0
fi

# 弹出队首任务,喂回给 Agent 让它继续
NEXT_TASK=$(sed -n '1p' "$QUEUE")
sed -i '1d' "$QUEUE"   # 删掉队首

# 通过 JSON decision 让 Agent 继续,并注入新任务
jq -n --arg t "$NEXT_TASK" '{decision: "block", reason: "队列未空,继续处理下一个任务:\($t)"}'

这里 decision: "block" 配合 reason 是 Stop hook 的约定:告诉 Claude Code"别停,这是原因,继续做"。Agent 读到 reason 后会接着干下一个任务。配合前述 8 次硬上限,单个事件最多驱动 8 轮——足够处理一个小队列,又不会失控。

实战案例:代码守护进程 codewatch

把前五步组装成一个完整的、可运行的守护进程——监听 src/,文件一变就让子代理审查并修复,跨文件问题丢进队列串行处理。

目录结构:

my-project/
├── src/
│   ├── auth.py
│   └── api.py
├── .claude/
│   ├── settings.json
│   ├── agents/
│   │   └── code-reviewer.md      # 子代理:专门做审查
│   └── guards/
│       ├── no-overwrite-guard.sh
│       └── stop-queue.sh
└── codewatch.sh                   # 守护进程入口

子代理定义 .claude/agents/code-reviewer.md(事件驱动常配子代理,让主 Agent 专注编排):

---
name: code-reviewer
description: 审查单个 Python 文件,找出 bug 和安全问题,必要时直接修复。当需要审查代码改动时调用。
tools: Read, Edit, Grep
---

你是资深 Python 代码审查员。审查时:
1. 先通读整个文件,理解意图
2. 按 severity(critical/high/medium/low) 标注问题
3. critical 和 high 直接用 Edit 修复
4. 输出 JSON:{file, fixed_issues, remaining_issues, summary}

守护进程入口 codewatch.sh:

#!/usr/bin/env bash
# codewatch —— 文件变化驱动的自愈代码守护进程
set -euo pipefail

WATCH_DIR="${1:-src}"
QUEUE="/tmp/cc-tasks-$(basename "$PWD").txt"
: > "$QUEUE"   # 清空队列

echo "👁  守护进程启动,监听 $WATCH_DIR (Ctrl+C 退出)"

# 初始化队列 + 关键:把队列路径告诉 Stop hook
export CC_QUEUE="$QUEUE"

watchexec -w "$WATCH_DIR" -e py --debounce 600 --shell=none -- \
  bash -c '
    FILE="{$WATCHEXEC_COMMON_PATH}"
    # 把任务压入队列(保持单一 Python 审查任务串行,避免并发抢同一文件)
    echo "用 code-reviewer 子代理审查并修复 $FILE" >> "'"$QUEUE"'"
    # 拉起 Agent,它会读到队列里的任务,靠 Stop hook 逐个消化
    claude --bare -p \
      --add-dir "'"$WATCH_DIR"'" \
      --permission-mode acceptEdits \
      "处理 /tmp 队列里的代码审查任务。每个任务委托 code-reviewer 子代理完成。"
  '

启动它:

chmod +x codewatch.sh .claude/guards/*.sh
./codewatch.sh src

然后去编辑器里改坏一个文件(比如在 src/auth.py 故意留个未关闭的文件句柄、加个 eval(user_input)),保存。你会观察到:

  1. watchexec 检测到 .py 变化,压一个任务进队列
  2. claude --bare -p 启动,读到队列,派 code-reviewer 子代理审查
  3. 子代理发现 eval 漏洞,用 Edit 修复;PostToolUse hook 自动 ruff format
  4. 主 Agent 想停 → Stop hook 看到队列还有任务 → 弹出下一个 → 继续
  5. 队列清空 → Stop hook 返回放行 → Agent 真正退出,等下一次文件变化

这就是事件驱动的完整闭环:人类只负责"保存文件"这一个动作,审查、修复、格式化、串行调度全自动化。

flowchart TD
    A[人类保存 src/auth.py] --> B[watchexec 检测文件变化]
    B --> C[任务压入 /tmp 队列]
    C --> D["claude --bare -p 启动<br/>读取队列"]
    D --> E[PreToolUse 护栏: 拦截危险文件]
    E --> F[委托 code-reviewer 子代理]
    F --> G[子代理审查+Edit修复]
    G --> H[PostToolUse: ruff 自动格式化]
    H --> I{Agent 想停}
    I -->|Stop hook 查队列| J{队列还有任务?}
    J -->|是| K[弹出队首 注入继续] --> F
    J -->|否| L[真正退出 等待下次事件]
    K -.8次上限.-> M[强制熔断 防跑飞]

    style A fill:#e1f5e1
    style L fill:#e1f5e1
    style M fill:#ffe1e1
    style E fill:#fff3e0
    style H fill:#fff3e0

进阶:多事件源与并发隔离

单个文件监听器只是起点。真实场景会接多个事件源:

并发隔离用 git worktree:多个事件同时到达时,给每个任务开一个临时 worktree,避免改同一文件打架(这正是"worktree 并行扇出批量跑任务"的思路,事件驱动里把它作为并发后端)。注意 worktree 模式下 hooks 配置和 .claude/agents 仍从主仓库读取,护栏一致。

调试与可观测性

无人值守最怕"不知道它刚才干了啥"。三个排查手段:

  1. 看流式事件:开发期始终用 --output-format stream-json | jq,每个 tool_use 都可见。
  2. 审计日志:在 codewatch.sh 里把每次 claude -p 的输出 tee 到带时间戳的日志: bash claude --bare -p ... | tee -a "logs/$(date +%Y%m%d-%H%M%S).json"
  3. hook 失败定位:PreToolUse hook 的 exit code 2 才是"阻止并反馈",其他非零退出码只是"hook 出错但放行"——别搞混,否则护栏形同虚设。

延伸阅读

参考来源

  1. Run Claude Code programmatically — Claude Code Docs — 头部/-p/--bare/JSON 输出格式的权威参数说明。
  2. Hooks reference — Claude Code Docs — 全部 hook 事件、JSON 输入输出 schema、退出码与 Stop hook 8 次熔断机制。
  3. Event-Driven Agent Automation — Claude Code Guide (cc.bruniaux.com) — 把交互式翻转为事件驱动的完整方法论。
  4. Claude Code in CI/CD and Headless Automation — hidekazu-konishi — 无人值守管道的工程实现细节。
  5. Claude Code Hooks: Complete Guide with 20+ Examples (2026) — aiorg — PreToolUse 拦截、PostToolUse 自动格式化、Stop 队列的即用型示例。

训练营适用性评估

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入