本教程教你用 Claude Code 的三层调度能力——会话内 /loop、Cron 计划任务、后台无头 -p——搭建一个会自己定时体检仓库的巡检 Agent。学完你能分清" REPL 开着轮询""定时触发""服务器无人值守"三种自动化的边界,并产出一份可跑的巡检流水线。适合已经装好 Claude Code、写过一两个 slash 命令、想让 AI 在你不盯着时也能干活的开发者。
claude --version 确认)/loop、claude -p、自定义 slash 命令的基础写法jq 与系统 cron/systemd很多人把"自动化"当成一个东西,结果在错的层级上使劲。Claude Code 在 2026 年其实有三层调度,它们的触发条件和持久性完全不同:
| 层级 | 触发条件 | 持久性 | 典型用途 |
|---|---|---|---|
CLI /loop |
REPL 处于空闲时才触发 | 仅当前会话 | 开发时盯着终端,每 15 分钟轮询一次 |
Cron 计划任务(CronCreate) |
REPL 空闲时触发 | 可选持久化到 .claude/scheduled_tasks.json |
工作日早上自动跑深度巡检 |
后台无头 -p |
由外部调度器(系统 cron / systemd / CI)驱动 | 进程级,跟普通脚本一样 | 服务器无人值守,笔记本合上也跑 |
关键认知:前两层只在 Claude Code 这个 REPL 进程开着、且不在回答问题时才会触发。 真正"合上笔记本还在跑"的无人值守,必须靠第三层——外部调度器把 claude -p 当成一个普通 shell 命令拉起来。这三层不是互斥,而是按"你在不在场"组合使用。
flowchart TD
A[想自动跑某件事] --> B{你正盯着终端吗?}
B -- 是,想实时盯 --> C[/loop 15m /命令<br/>会话内轮询]
B -- 否,但 REPL 常开 --> D{需要跨会话存活吗?}
D -- 否 --> E[会话级 CronCreate]
D -- 是 --> F[持久化 CronCreate<br/>写入 scheduled_tasks.json]
B -- 否,机器都不一定开 --> G[外部调度器<br/>系统cron/systemd/CI]
G --> H[claude -p 无头执行]
C --> I[产出健康报告]
E --> I
F --> I
H --> I
I --> J{有 critical 告警?}
J -- 是 --> K[推送到 webhook/邮件]
J -- 否 --> L[归档到 .inspections/]
调度只是"定时器",真正干活的是被调度的命令。我们先造一个只读、幂等、输出结构化 JSON 的 /inspect-repo。新建 .claude/commands/inspect-repo.md:
---
description: 巡检当前仓库健康度,输出结构化 JSON 报告
argument-hint: [focus-area]
allowed-tools: Bash(git status:*), Bash(git log:*), Bash(git rev-list:*), Bash(npm test:*), Bash(npm audit:*), Read, Grep
---
你是仓库健康巡检 Agent。对当前仓库做**只读**巡检,最后只输出一段原始 JSON(不要 Markdown 代码围栏、不要解释文字)。
## 巡检项
1. 版本控制:`git status --porcelain` 统计未提交文件数;`git rev-list --count @{u}..HEAD` 与 `git rev-list --count HEAD..@{u}` 算领先/落后远端提交数
2. 测试:`npm test --silent` 统计通过/失败
3. 依赖:`npm audit --json` 统计 critical/high 漏洞数
4. 代码债:Grep 统计 `TODO|FIXME|XXX` 数量
5. 分支:当前分支名与最近 24h 提交数
用户额外关注:$ARGUMENTS(可能为空)
## 输出 schema(严格按此结构,顶层就是对象)
{
"branch": "字符串",
"score": 0到100的整数,
"uncommitted": 整数,
"ahead": 整数, "behind": 整数,
"tests": {"passed": 整数, "failed": 整数},
"audit": {"critical": 整数, "high": 整数},
"todoCount": 整数,
"alerts": [{"level":"critical|warning|info","area":"字符串","message":"字符串"}],
"summary": "一句话总结"
}
操作说明:把文件放到仓库的 .claude/commands/ 下即可,无需注册。allowed-tools 把权限收窄成只读命令,巡检阶段绝不写文件——这是无人值守能安全跑的前提。
预期结果:在 REPL 里输入 /inspect-repo 测试与依赖,Agent 跑完测试和审计,吐出一段纯 JSON。你可以手动 claude -p "/inspect-repo" | tail -1 看一眼,确认输出确实能被 jq 解析。
常见问题:
- 输出带了 ```json 围栏导致 jq 报错:把命令里的"只输出原始 JSON"再强调一遍,或在外层用 sed 剥围栏。
- npm test 跑太久:在 allowed-tools 里把命令换成 npm test -- --bail 或限定超时;巡检追求快而非全。
- 没有远端分支导致 @{u} 报错:在 prompt 里加"若无上游分支,ahead/behind 填 0"。
/loop 做会话内实时轮询/loop 是最轻的一层——它假设你正坐在终端前,只是想让某个命令每隔几分钟自动重跑。语法:
/loop 15m /inspect-repo 测试
这会每 15 分钟重跑一次 /inspect-repo,默认间隔是 10m。它的两个硬约束要记住:
进阶:动态节奏。固定间隔有时浪费——巡检没问题就该拉长间隔,有问题才该盯紧。当你用不带间隔的 /loop(动态模式)时,调度器会调用 ScheduleWakeup 让 Claude 自己决定下次多久后醒来。你可以这样指挥:
用动态 loop 巡检仓库:如果上次报告 score≥90,下次 30 分钟后再查;如果有 critical 告警,5 分钟后复查确认是否自愈。
这比写死的 15m 聪明得多——健康的仓库少打扰,生病的仓库密集复查。
预期结果:终端里每隔一段时间自动出现一份新的 JSON 报告,上方有一行 narrator 提示下次触发时间。
常见问题:
- 忘了循环还在跑:用 /loop(不带参数)可查看当前循环;不需要时记得停掉,否则一直占会话。
- 间隔设成 5m 反而很慢:5 分钟内每次触发都让缓存失效(prompt cache 5 分钟 TTL),成本会涨。健康仓库宁可设 30m。
/loop 解决"现在盯着",但你想"每个工作日早上自动深度巡检一次"——这就轮到 Cron 计划任务。它用标准 5 字段 cron 表达式(分 时 日 月 周),由 CronCreate 创建:
帮我建一个持久化的定时任务:每个工作日早上 9 点左右,跑一次
/inspect-repo 深度,把报告写到.inspections/<日期>.json。
Claude 会调用工具,大致等价于:
{
"cron": "13 9 * * 1-5",
"prompt": "/inspect-repo 深度,并把结果保存到 .inspections/ 目录",
"recurring": true,
"durable": true
}
为什么是 13 9 而不是 0 9? 这是个真实成本/稳定性细节:所有人写"9 点"都会落 0 9 * * *,请求在同一秒打到 API 上形成尖峰。把分钟错峰到 13、27、43 这类非整点,既不影响业务,又躲开了"整点拥堵"。持久化(durable: true) 会把任务写进 .claude/scheduled_tasks.json,下次启动 Claude Code 自动恢复——这是它和 /loop 最大的区别。
两个硬限制务必知道:
- 只在 REPL 空闲时触发:和 /loop 一样,你必须开着 Claude Code 进程。任务到点了但你没开 REPL,就不会补跑(除非是 durable 的 one-shot,下次启动会补做漏掉的)。
- 循环任务 7 天自动过期:recurring 任务最多跑 7 天,到期后自动删除。长期巡检要么每周重建一次,要么——更稳的做法——交给第四步的外部调度。
预期结果:CronList 能看到这条任务;到点且 REPL 空闲时,会自动出现一次巡检回合并落盘报告。
常见问题:
- 到点了没触发:九成是 REPL 没开、或正忙。计划任务是"会话内闹钟",不是系统级守护进程。
- durable: true 后改不动了:用 CronList 拿到 ID,再 CronDelete <id> 重建。
- 一次性提醒怎么写:recurring: false,把分/时/日/月钉死,到点跑一次就自删。
-p 做"服务器无人值守"前三层都依赖"REPL 开着"。真正的无人值守——服务器跑着、你下班了、笔记本合上——必须让外部调度器把 claude -p 当普通命令拉起。这才是 -p 无头模式在自动化里的主战场。
写一个 inspect-and-alert.sh,把巡检、落盘、告警串起来:
#!/usr/bin/env bash
# inspect-and-alert.sh — 无人值守巡检 + 关键告警
set -euo pipefail
REPO="/srv/myapp"
STAMP="$(date +%FT%H%M)"
REPORT="$REPO/.inspections/$STAMP.json"
mkdir -p "$REPO/.inspections"
cd "$REPO"
# 关键:plan 权限 + 限回合数,无人值守绝不能让模型乱写文件
claude -p "/inspect-repo 生产环境" \
--permission-mode plan \
--output-format json \
--max-turns 30 \
> "/tmp/claude-envelope-$STAMP.json"
# --output-format json 返回的是信封,真正的报告文本在 .result 里
jq -r '.result' "/tmp/claude-envelope-$STAMP.json" > "$REPORT"
# 解析 critical 告警,决定是否报警
CRITICAL=$(jq '[.alerts[]? | select(.level=="critical")] | length' "$REPORT")
SCORE=$(jq '.score // 100' "$REPORT")
echo "[$(date +%FT%T)] score=$SCORE critical=$CRITICAL -> $REPORT"
if [ "$CRITICAL" -gt 0 ] || [ "$SCORE" -lt 60 ]; then
curl -fsS -X POST "$ALERT_WEBHOOK" \
-H 'Content-Type: application/json' \
--data-binary "@$REPORT"
fi
然后用系统 cron 或 systemd timer 把它挂上:
# crontab -e —— 每天早上 6:13 跑一次(注意 % 在 crontab 里要转义,这里没有)
13 6 * * * /usr/local/bin/inspect-and-alert.sh >> /var/log/inspections.log 2>&1
为什么这里用系统 cron 而不是 CronCreate?因为系统 cron 由操作系统的 cron 守护进程驱动,与 Claude Code 进程无关——就算你根本没启动 Claude Code 的 REPL,它照样到点拉起一个全新的 claude -p 进程跑完即退。这是"无人值守"四个字的真正含义。
-p 在自动化里的关键参数:
| 参数 | 作用 | 自动化里的意义 |
|---|---|---|
--output-format json |
整个回合结束后输出一个 JSON 信封 | 下游 jq 可解析,stream-json 则是流式事件 |
--permission-mode plan |
只读规划,不改文件 | 无人值守时默认收窄到最安全 |
--max-turns 30 |
限制最大回合数 | 防止模型陷入死循环烧钱 |
--session-id <id> / --resume |
复用会话上下文 | 让巡检"记得"上次状态,做趋势对比 |
--add-dir <path> |
额外授权访问目录 | 巡检多个微服务仓库时用 |
预期结果:第二天早上一看 /var/log/inspections.log,能看到一行 score=88 critical=0 -> .inspections/2026-07-04T0613.json;出问题时你的 webhook 收到告警。
常见问题:
- .result 解析出来还是带围栏:在 slash 命令里把"只输出原始 JSON"再加粗强调,或脚本里加 sed -n '/^{/,/^}/p' 兜底。
- npm test 在 -p 里卡住:无人值守没有人工超时干预,务必在命令或脚本层加 timeout 120 npm test。
- CI 里跑要排队:claude -p 是有并发上限的,CI 矩阵里别一次性扇出几十个,串行或限并发。
光有三层不够,价值在于组合。下面这套设计把"你在场/不在场"两种状态都用上:
/loop(在场):开发时 /loop 20m /inspect-repo 测试,盯着测试和依赖,出问题立刻在终端看到。-p(全不在场):服务器每天 6:13 跑一次,只有出 critical 才打扰你——健康时静默归档,生病时 webhook 推送。为了让三层共享同一份"判断标准",把它们都指向同一个 /inspect-repo 命令。这样无论谁触发,输出的 schema 完全一致,告警脚本只需写一套。
进阶可以叠一个 Stop 钩子做收尾:当任何一次巡检回合结束时,钩子把当次 score 追加进 .inspections/trend.csv,长期就能画出仓库健康趋势线。注意钩子只是"每次回合结束自动跑一段脚本",真正的定时还是由上面三层负责——别把职责搅混。
最后给一个安全清单,无人值守前逐条核对:
allowed-tools 只放只读工具,写操作一律剥离。-p 默认 --permission-mode plan,确需改代码时再单独跑一个"修复"流水线,且只在沙箱容器里 --dangerously-skip-permissions。--max-turns 和脚本级 timeout,双重防失控。CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 减少无人值守时的非必要请求。/inspect-repo 不要去 Read .env、*.key。/inspect-repo、1.5 小时搭外部 cron 流水线、余下时间做告警联调。/loop + 系统 cron 两层,预计 2 小时。-p、权限模式,建议排在入门篇之后。jq 解析的结构化报告、能否配置出"健康静默/生病告警"的策略。/loop 与 cron 工具的权威说明。-p 无头模式、--output-format、Agent SDK 的完整参考。--permission-mode plan 换成在沙箱内的 acceptEdits,让 Agent 不仅诊断还自动提 PR,配合 Stop 钩子做收尾验证。claude -p,让它对比一周数据、输出"健康度在恶化还是好转"的周报。/loop 与 cron 计划任务的官方权威说明,含 v2.1.72 版本要求与 7 天过期规则claude -p 无头模式、--output-format json/stream-json、Agent SDK 的完整参数参考[!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 等场景全覆盖。
