1. 为什么我要在 Claude Code 里折腾 Cron 定时任务
Claude Code 的 Cron 定时任务,简单说就是给 AI 编码助手装了一个闹钟:到点了它自己醒来,按你事先写好的 prompt 去干活,干完把结果丢回给你。它适合谁?适合那些每天要重复做同一件检查、同一份汇总、同一次轮询的开发者——比如每隔十分钟看一次部署状态、每天早上汇总昨天的 git 提交、每周一生成一份依赖升级清单。这些事本身不难,难的是你总得记得去做,而人恰恰最容易忘。
我之前的做法很土:开一个终端挂着watch,或者写个 shell 脚本塞进系统 crontab。问题是脚本只能执行写死的命令,遇到"接口返回 500 了帮我看看日志里有没有线索"这种需要理解上下文的任务,脚本就傻了。Claude Code 的 Cron 把执行者从 shell 换成了 AI Agent,你描述目标,它自己决定调哪些工具、怎么处理异常。这篇就按"从零到能跑"的顺序,把配置骨架、TaoToken 通道接入、创建触发验证、以及我踩过的坑一次讲清楚。
需要先明确一个边界:Claude Code 的 Cron 不是操作系统级的 cron 守护进程,它只在 Claude Code 运行期间生效。你可以把它理解成"会话内的调度器",Claude Code 一关,任务就不触发了。想让任务在重启后还在,得靠durable: true把它写进磁盘。这个前提决定了它适合"开发期间的自动化",而不是"服务器上的常驻运维"。
2. 前置准备:用 TaoToken 统一 Key 和 API 通道
在写任何定时任务之前,先把模型通道理顺。Claude Code 这类工具默认走官方端点,但很多人在国内网络环境下会遇到连接不稳定的问题,配置里改来改去很折腾。我的做法是统一走 TaoToken 的 API 通道,一个 Key 管所有模型调用,配置只写一次,后面 Cron 任务触发时用的也是同一条通道,不会出现"手动对话能通、定时任务超时"这种割裂。
TaoToken 官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api 。注意 API 地址后面不加任何查询参数,保持干净。
第一步,去控制台创建 API Key。打开 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,登录后在 API Keys 页面新建一个 Key,复制出来。这个 Key 就是后面所有配置里要填的凭证,建议单独建一个给自动化任务用,方便出问题时单独吊销,不影响你手动对话用的那个。
第二步,确认你要用的模型名。不同任务对模型的要求不一样:定时轮询这种轻量任务用便宜快速的模型就够,日报汇总这种需要一定理解能力的可以用强一点的。模型列表在文档里能查到,接入说明看 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。
第三步,把 Key 写进环境变量,别硬编码在配置文件里。这样配置文件可以进 git,Key 不会泄露:
# Linux / macOS,写进 ~/.bashrc 或 ~/.zshrc export TAOTOKEN_API_KEY="sk-你的key" export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="$TAOTOKEN_API_KEY"# Windows PowerShell,写进 $PROFILE $env:TAOTOKEN_API_KEY = "sk-你的key" $env:ANTHROPIC_BASE_URL = "https://taotoken.net/api" $env:ANTHROPIC_API_KEY = $env:TAOTOKEN_API_KEY这里有个细节值得说:Claude Code 读的是ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY这两个变量,所以我把 TaoToken 的 Key 赋给ANTHROPIC_API_KEY,等于让 Claude Code 以为自己在连官方端点,实际走的是 TaoToken 通道。这样 Cron 任务触发时,模型调用和手动对话走的是同一条路,行为一致。
如果你更习惯用配置文件而不是环境变量,Claude Code 的settings.json里也能指定。但环境变量的好处是切换方便,而且不会把 Key 写进项目目录。我两种都用过,最后留在环境变量方案上。
3. 可复制的配置骨架:settings.json 与 config.toml
Claude Code 的配置分两层:一层是settings.json,管运行环境和行为;另一层是任务本身的参数,通过 CronCreate 工具传入。很多人以为要手写 cron 表达式,其实不用——你用自然语言告诉 Claude,它帮你翻译。但理解参数含义能让你在排查问题时心里有数。
先看settings.json的骨架。这个文件放在项目根目录的.claude/下,或者用户级的~/.claude/下。项目级配置只对当前项目生效,用户级对所有项目生效。我建议自动化任务相关的配置放用户级,避免每个项目都要复制一遍:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的key" }, "permissions": { "allow": [ "Bash(curl:*)", "Bash(git log:*)", "Read" ] }, "hooks": { "PostToolUse": [ { "matcher": "Edit", "hooks": [ { "type": "command", "command": "echo \"$(date) edited\" >> .claude/hook_log.txt" } ] } ] } }permissions.allow这一项很关键。Cron 任务触发时是无人值守的,如果任务里要跑curl或git log,而权限没放开,任务会卡在权限确认上,等于白设。把定时任务会用到的命令提前加进白名单,是让自动化真正跑起来的前提。上面这个例子里我放开了curl和git log,你可以按自己任务的实际需要增减。
再看config.toml。如果你用的是某些支持 TOML 配置的客户端或包装层,骨架长这样:
[api] base_url = "https://taotoken.net/api" api_key = "sk-你的key" timeout_seconds = 120 [model] default = "claude-sonnet-4-20250514" fast = "claude-haiku-4-20250514" [cron] enabled = true timezone = "Asia/Shanghai" max_concurrent_jobs = 3timezone这一项容易被忽略。cron 表达式默认按本地时间解释,如果你的机器时区和你的预期不一致,任务会在错误的时间触发。显式写上Asia/Shanghai能避免这类问题。max_concurrent_jobs限制同时运行的任务数,防止多个任务挤在一起把通道打满。
任务本身的参数通过 CronCreate 传入,四个字段:
| 参数 | 含义 | 示例 |
|---|---|---|
| cron | 5 段表达式,分 时 日 月 周 | */10 * * * *每 10 分钟 |
| prompt | 到期时执行的描述 | "检查 PR #42 是否合入" |
| recurring | true 周期任务,false 一次性 | true |
| durable | true 存盘,false 仅本次会话 | true |
cron 表达式速查,五个字段从左到右是分、时、日、月、周:
*/5 * * * * 每 5 分钟 0 * * * * 每小时整点 0 9 * * * 每天 9:00 0 9 * * 1-5 工作日 9:00 30 14 28 2 * 2 月 28 日 14:30(一次性) 0 0 1 * * 每月 1 号零点4. 创建、触发、验证:完整动作演示
配置就绪后,实际操作比想象中简单。你不需要手写 CronCreate 调用,直接用自然语言对 Claude 说就行。下面走一遍完整流程。
4.1 创建一个周期任务
在 Claude Code 里输入:
每 10 分钟检查一次 https://taotoken.net/api 是否可达, 如果连续两次失败就告诉我,并附上最近一次的错误信息。Claude 会把它翻译成类似这样的调用:
CronCreate( cron: "*/10 * * * *", prompt: "curl -s -o /dev/null -w '%{http_code}' https://taotoken.net/api,如果返回不是 200 就报告状态码", recurring: true, durable: true )注意durable: true,这样任务会写进.claude/scheduled_tasks.json,Claude Code 重启后自动恢复。如果你只是临时试一下,用durable: false,会话结束任务就没了。
4.2 查看已创建的任务
直接问:
列出我所有的定时任务Claude 调用 CronList,返回类似:
job_id: job_a1b2c3 cron: */10 * * * * prompt: 检查 https://taotoken.net/api 可达性 recurring: true durable: true next_run: 2025-06-01 14:30:00next_run是下一次触发时间,用来确认时区和表达式是否符合预期。如果这个时间不对,八成是时区问题,回去检查config.toml里的timezone。
4.3 验证任务真的会触发
最稳的验证方法是创建一个一分钟后就触发的一次性任务,看它是否按时执行。比如现在是 14:29,你输入:
一分钟后提醒我检查今天的构建结果Claude 创建:
CronCreate( cron: "30 14 1 6 *", prompt: "提醒用户检查今天的构建结果", recurring: false, durable: false )等到 14:30,Claude Code 空闲时会把这条 prompt 交给模型执行,你会看到它主动发消息提醒你。如果没触发,先确认 Claude Code 是否在运行、是否处于空闲状态——任务在 REPL 忙碌时会排队,不会打断你当前的对话。
4.4 删除任务
验证完不需要的任务,直接说:
把 job_a1b2c3 删掉Claude 调用 CronDelete 完成清理。周期任务即使不手动删,也会在第 7 天最后一次触发后自动过期,这是内置的保护机制,防止忘记清理的任务无限跑下去。
5. 本篇常见错误排查
5.1 任务创建了但从不触发
最常见的原因是 Claude Code 没在运行。Cron 是会话内的调度器,进程不在,任务自然不触发。如果你需要"关掉终端也继续跑"的效果,那得用系统级 crontab 去定时拉起 Claude Code 的命令行模式,而不是依赖内置 Cron。另一个原因是任务处于排队状态——你正在和 Claude 对话,它优先处理当前交互,定时任务会等空闲。
5.2 触发时报权限错误
任务里的命令没在白名单里。回到settings.json的permissions.allow,把用到的命令加进去。比如任务要跑git log,就加"Bash(git log:*)"。注意通配符的位置,Bash(curl:*)表示允许所有 curl 调用,写窄了会拦不住。
5.3 时间对不上
三个检查点:一是config.toml里的timezone是否设置正确;二是 cron 表达式是 5 段不是 6 段,Claude Code 用的是标准 5 段格式,没有秒字段;三是 cron 本身有秒级抖动,系统故意加了随机偏移来避免任务同时涌向通道,所以不要指望它精确到秒。
5.4 durable 任务重启后丢失
检查.claude/scheduled_tasks.json是否存在且可写。如果这个文件被 gitignore 或者目录权限不对,任务写不进去。另外确认创建时确实传了durable: true,默认值是 false,不传就不存盘。
5.5 模型调用超时
如果任务触发后卡住或报连接错误,先手动跑一次同样的 prompt,确认 TaoToken 通道本身是通的。手动能通、定时不通,多半是环境变量没被 Claude Code 进程继承——比如你在 shell 里 export 了,但 Claude Code 是从桌面图标启动的,读不到。这种情况把配置写进settings.json的env字段更稳妥。
6. 把定时任务接进你的自动化流程
到这里,创建、触发、验证、排障的闭环就走完了。回到最开始那个判断:Claude Code 的 Cron 适合开发期间的自动化,不适合替代服务器上的常驻调度。它的价值在于把"需要理解上下文"的重复检查交给 AI,而不是把"写死的命令"再包一层。
如果你打算长期用,建议把模型通道固定下来,别每次换。TaoToken 的 Coding Plan 适合需要长期跑编码和 Agent 任务的场景,入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ,一个 Key 覆盖对话和定时任务,配置不用改来改去。想先手动验证模型行为再决定任务怎么写,可以去模型对话页 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite 试几条 prompt,确认输出符合预期后再固化成定时任务。Key 的管理和轮换在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite ,接入细节看文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。
最后留一个我实际在用的组合:工作日早上 8:55 汇总昨天的 git 提交,每 30 分钟检查一次部署端点,每周一生成依赖升级清单。三个任务都设了durable: true,权限白名单里放开了git log和curl。跑了两周,唯一一次没触发是因为我关了 Claude Code 去开会——这恰好说明它的边界在哪,也说明它该用在哪。