你的 AI 智能体的 crontab,以 Markdown 写成。
OpenRoutine 是 Claude Code Routines 和 ChatGPT 定时任务的开源替代品 — 同样的无人值守智能体理念,去掉了供应商的锁。每个任务一个 Markdown 文件,frontmatter 里写 crontab 语法,底下接任何 AI 编程智能体。任务保存在你的仓库里,在你自己的机器上运行, 不受任何账号、套餐或用量上限的约束。
brew tap soulmachine/tap https://github.com/soulmachine/openroutine
brew trust --formula soulmachine/tap/openroutine
brew install openroutine
openroutine init # 生成配置,以及一个可参照的示例任务
任务就是一个文件
frontmatter 写明做什么、何时做、由谁做。正文就是提示词。 除此之外没有第二个需要查看的地方。
---
name: todo-digest
description: Nightly TODO/FIXME triage
cron: "0 2 * * *"
agent: claude
---
Review all open TODO and FIXME comments in this repository.
For any that are trivially fixable, fix them and open a pull
request. Summarize everything else in reports/todo-digest.md.
把它命名为 todo-digest.md 保存进仓库,用
openroutine add 注册一次,它就是这个任务的完整定义 — 和你提交的
其他内容一样,可以 diff、可以代码评审、可以 grep。
一个 Rust 守护进程运行你注册的任务文件:所有调度都在进程内完成,每个任务经由你 配置的智能体 CLI 运行,同时提供 REST 触发端点和一个本地 Web 界面,用于查看历史、 日志和暂停/恢复。
把 agent: claude 换成 agent: codex — diff 里只有一行 —
同一个任务就跑在另一家的智能体上,而这恰恰是任何一家供应商的调度器都永远不会
提供的能力。
建立在四个立场上
定时的智能体任务,说到底只是一段附带调度的提示词。认真对待这句话,其余一切都随之而来。
- 任务保存在你的仓库里
-
每个字段 — 调度、智能体、
disabled— 都是 Markdown 文件里的 frontmatter。停用一个任务是一次评审者看得见的提交,而不是藏在某人账号里的 不可见状态。 - 调度器就是守护进程
-
不是 launchd,也不是 crontab — 它们在被剥离的环境里运行智能体,没有
PATH也没有 API 密钥,是智能体任务悄无声息死掉的地方。自己掌握 调度器,换来的是 macOS 和 Linux 上完全一致的行为、真实的运行环境,以及诚实的 记账。 - 从构造上就与智能体无关
- OpenRoutine 从不直接调用模型 API。智能体只是一个命令模板,任何接受提示词的 CLI 都能用 — Claude Code、Codex、Gemini,或你自己写的。
- 一个二进制,零数据库
- 调度器、API 和界面装在同一个静态 Rust 二进制里。所有持久数据只有两种纯文本 格式:你拥有的 Markdown,和机器拥有的 JSON。
与供应商方案相比
几家大厂已经证明,编程智能体足以胜任无人值守的工作。但每一家都把这种周期性的工作 锁进了自家的技术栈。
| 能力 | Claude Code Routines | ChatGPT 定时任务 | OpenRoutine |
|---|---|---|---|
| 在哪里运行 | Anthropic 托管的云(或组织自建环境) | OpenAI 云;项目任务可在本地运行,但仅限桌面应用开启期间 | 你的机器,由 launchd/systemd 监管的无界面守护进程 |
| 任务在哪里定义 | Web 界面或 /schedule,存储在你的 claude.ai 账号里 |
聊天或 Scheduled 页面,存储在你的 OpenAI 账号里 | 你仓库里的 Markdown 文件 |
| 智能体 | 仅 Claude Code | 仅 GPT 模型 | 任何智能体 CLI:Claude Code、Codex、Gemini,或你自己的 |
| 触发方式 | 调度、API 端点、GitHub 事件 | 调度与变化监测,至多每小时一次 | cron 与一次性调度;REST 触发端点 |
| 管理界面 | claude.ai Web 界面 | 应用内的 Scheduled 页面 | 本地 Web 界面,无需账号 |
| 限制 | 订阅用量、每日运行上限 | 按套餐 3–15 个活跃任务;无人值守任务可能被自动暂停 | 只受你的硬件限制 |
| 可用性 | 研究预览版,付费套餐 | 付费套餐 | 开源 |
这笔交换在每个方向上都是诚实的:Routines 给你云端执行、GitHub 事件触发和托管沙箱; ChatGPT 给你打磨精致的跨设备收件箱和变化监测;OpenRoutine 给你本地文件、本地执行、 没有上限,以及随时更换智能体的自由。
如何使用
需要 Rust 工具链;仅支持 macOS 和 Linux(明确不支持 Windows)。
openroutine list # 每个任务、它的调度和健康状态
openroutine status # 守护进程是否在运行,以及它掌管着什么
openroutine run <task> --dry-run # 精确演示一次运行会做什么,但不启动任何东西
openroutine run <task> # 经由守护进程,立即触发一次
openroutine logs <task> --follow # 跟踪最新一次运行的日志
openroutine pause --all # 停止一切触发,守护进程保持运行
openroutine dashboard # 本地 Web 界面,无需账号
任务就是文件,所以其余操作都是普通的编辑:用
openroutine add 注册一次,然后随意修改 — 任务在即将运行时会重新读取
自己的文件,你刚改好的提示词就是实际运行的那一个。没有任何监视或轮询;让修改在
其他地方生效的是 openroutine reload,而一个不会再运行的任务 —
已完成、已损坏,或被 disabled 关掉 — 也只有经过它才会注意到修改。
要让它在一台你不守着的机器上长期运行,openroutine install
会把守护进程注册到 launchd 或 systemd — 按用户注册的服务,绝不需要 sudo。
部署一节讲了全部细节,包括那个人人都会中一次招的
登录 shell PATH 陷阱。
任何东西都能触发任务
守护进程在 127.0.0.1:7373 上提供 REST API,由 Bearer 令牌保护,
告警系统、部署流水线和 git 钩子都能发起一次运行。
curl -X POST http://127.0.0.1:7373/v1/tasks/todo-digest/fire \
-H "Authorization: Bearer $(openroutine token)" \
-d '{"text": "Sentry alert SEN-4521 fired in prod."}'
可选的 text 以“调用方提供的上下文”标注后送达智能体,而不是作为指令 —
任何能访问端点的一方都能发送 text,因此 text 必须无法重新定义任务本身。
现状
v1 已经实现:调度器、运行器、REST API 和 Web 界面,都在一个二进制里。
已知限制,皆为有意为之:没有 GitHub 事件触发,也没有通知(触发端点就是集成点); 状态写入对进程被杀是原子的,但没有针对断电做 fsync;Web 界面的渲染靠人工核验, 而非浏览器测试框架。