【免费下载链接】openbot
A local-first desktop workspace for persistent AI teammates. Run Codex, Claude, and Grok with dedicated workspaces, task queues, file sharing, browser control, and agent-to-agent collaboration.
在 OpenBot 的生产环境 Skill 目录中,workflow-playbook负责把“我们每周都在手工做的那件事”整理成一份人能照着做、Agent 能照着跑、并且可以逐段验收的流程说明,同时只在条件成熟的地方提出最小自动化方案。本文以 SKILL.md 为骨架,结合仓库中的 Skill 装载机制、Routine 调度 schema 与 Automation API,讲清楚这个技能的四步工作流如何落到 OpenBot 的真实执行原语上,以及哪些边界一旦越界就会把“可靠的 playbook”变成“看起来跑起来了的假自动化”。
技能定位:一个 automation 类别的 Marketplace Skill
workflow-playbook在 catalog.json 中的元数据非常克制:slug为workflow-playbook,category为automation,source为openbot,featured为false。它不作为独立 Agent 出现,而是被Operations Planner这个 Agent 引用:
| 项目 | 内容 |
|---|---|
| Agent | Operations Planner |
| 定位 | Turns repeatable work into reliable playbooks |
| 绑定技能 | workflow-playbook+project-plan |
| 关键约束 | “Do not claim an automation is connected or running until it has actually been configured and tested.” |
这条约束与技能正文最后一句“do not enable a recurring job without a request”互为表里:流程文档可以立刻交付,自动化必须显式被请求、并且被验证过。同目录的project-plan负责范围、依赖与验收口径,workflow-playbook负责流程本身的逐步建模,两者组合后,一个“把流程交出去”的任务才会同时具备范围感和可执行性。
从技能装载角度看,它遵循 Agent Skills 规范:一个文件夹<name>/加一个SKILL.md,frontmatter 只有name(等于文件夹名)与description。按 skills-and-plugins 文档 的说明,OpenBot 安装技能时会同时写入.agents/skills/<slug>与.claude/skills/<slug>(因为 Claude Code 不读.agents/skills),副本而非软链,哈希记录在.openbot/skills-lock.json,禁用项存放在.openbot/skills-disabled/。这意味着技能本身是一份纯文本资产:它的价值全部体现在你写下的流程结构里,而不是某个隐藏的运行时。
输入盘点:先确认事实,再谈流程
技能的第一节Inputs要求先识别六类事实:
- 触发(trigger)——这件事什么时候开始?是收到工单、每周一早上,还是某人说“该发版了”。
- 输入(inputs)——开始之前必须已经存在什么:导出文件、工单号、上一版发布说明。
- 相关人(people)——谁做决策、谁执行、谁验收。
- 已有工具(tools already available)——注意措辞是 “already available”。
- 期望产出(expected output)——交付物长什么样,写到哪。
- 当前失败点(current failure points)——过去在哪一步卡住、返工或漏项。
最关键的一句是:“Do not assume access to a service simply because it is named.” 流程里出现“把结果同步到 CRM”,并不等于 Agent 或当前账号真的能访问 CRM。在 OpenBot 里这句话有非常具体的落点:技能的可用工具取决于 Agent 安装了什么技能、挂了哪些 MCP server、以及浏览器是否已经在目标站点登录。文档里说 MCP 配置不存在统一文件格式,OpenBot 在会话开始时才把 server 交给各 provider;密码类凭据则由 1Password / Bitwarden 连接器托管,Agent 拿不到 token。因此输入盘点阶段就应该把“名字”翻译成“可用性证据”,否则第 4 步的自动化建议会全线失真。
一个可直接复用的盘点表:
| 维度 | 必须写下的内容 | 反例(不可接受) |
|---|---|---|
| 触发 | 事件来源与判定条件 | “有人要求的时候” |
| 输入 | 字段、格式、来源系统、责任人 | “相关数据” |
| 工具 | 具体工具名或 MCP 工具名、登录状态 | “用你手上的工具” |
| 产出 | 目标位置、格式、验收人 | “整理一下发出来” |
| 失败点 | 最近三次失败的具体位置 | “有时候会出问题” |
第 1 步:把每一步映射到输入、动作、输出、负责人
Workflow的第 1 条要求:“Map each step to its input, action, output, and owner. Separate decisions from mechanical transformations.”
这一步的产出是一张四列表,而不是散文:
| # | 输入 | 动作 | 输出 | 负责人 | 类型 |
|---|---|---|---|---|---|
| 1 | 已合并 PR 列表 | 汇总变更条目 | 变更清单 | 发布负责人 | 机械变换 |
| 2 | 变更清单 | 判断是否构成破坏性变更 | 升级说明段落 | 技术负责人 | 决策 |
| 3 | 升级说明 | 写入发布说明文件 | 草稿 PR | 发布负责人 | 机械变换 |
| 4 | 草稿 PR | 批准公开 | 已批准 PR | 产品负责人 | 决策 |
“区分决策与机械变换”不是为了排版好看,而是因为它直接决定哪一段可以被自动化。机械变换只要输入齐、输出可校验,就有自动化空间;决策段即使能被模型草拟,也必须保留一个人来签字。这与 OpenBot 的权限模型一致:审批(approvals)需要人响应,而浏览器接管(browser takeover)和密钥类问题必须回到 OpenBot 内完成,不能通过本地脚本接口代办(详见 automation 文档)。
同时注意owner列不能空着。“未分配”是一个显式状态,而不是省略——这一点与project-plan里 “owner or unassigned” 的写法相呼应。
第 2 步:定义完成条件、重试上限、重复防护与可恢复状态
第 2 条要求:“Define completion, retry limits, duplicate prevention, and the state needed to resume safely after interruption.”
这四项恰好在 OpenBot 中都有对应实现,可以逐条落到字段和行为上。
完成条件(completion)
完成条件必须是可判定的断言,例如“发布说明 PR 已被批准且 CI 通过”,而不是“弄好了”。在 OpenBot 中,一次 Routine 运行的终态由RoutineRunStatus表达,取值包括queued、running、needs-attention、succeeded、failed、interrupted、cancelled(见 ipc-routines.ts)。这给验收提供了一个机器可读的判据:succeeded才算跑完,needs-attention意味着有人在等回答,interrupted意味着被打断需要重跑。
重试上限(retry limits)
重试上限要写成数字和条件,例如“失败后最多重试 2 次,间隔 10 分钟;连续 3 次失败升级到值班”。在 OpenBot 侧,一个 run 本身不带重试键——automation 文档明确指出 “Routine runs have no retry key; retrying a run can start it twice.”,因此重试策略必须写在 playbook 里,由执行者(人或外层脚本)来保证,不能指望运行时替你幂等。
重复防护(duplicate prevention)
重复防护有两层实现证据。
第一层是命名去重:create_routine在创建前会把名字trim().toLowerCase()后与已有 routine 比较,命中则直接报错并提示改用update_routine,错误信息里带出已存在 routine 的routineId(routine-scheduler.ts)。这让“同名重复创建”在工具层就被拦住。
第二层是消息去重:消息路由支持clientMessageId(1–128 字符),同一 agent 与同一 key 在 24 小时内(包括重启后)返回首次回执。对应的自动化 curl 示例在 automation 文档 中给出。注意:这条幂等保证属于消息路由,不属于 routine run 路由,写 playbook 时要区分清楚。
可恢复状态(state needed to resume safely)
“中断后可安全恢复”要求你把状态显式落在文件或记录里,而不是留在某次对话的上下文里。OpenBot 提供了两个原语:
- Routine 运行历史:
RoutineRunFields记录scheduledFor、status、error,以及可选的missed(count与until,用于表示“OpenBot 关闭期间积压的到期次数”,上限常量为ROUTINE_MISSED_COUNT_LIMIT = 999)。 - 等待(wait):Agent 用
openbot.await_event打开一个等待,把waitId交给用户;之后由某次 routine 运行或带waitId的本地脚本事件唤醒,运行会重放请求与备注。Agent 最多同时有 20 个打开的等待,可用openbot.list_waits/openbot.close_wait管理。
把这两者写进 playbook 的形式是:“若构建未结束,登记 waitId 并结束本轮;由build-finishedroutine 唤醒;若 6 小时未唤醒,由人接手。” 这样“中断”就不再是丢失状态,而是一个有名字、有超时、有兜底的中间态。
与“关闭期间到期”相关的策略
missedPolicy决定 routine 在 OpenBot(或服务器)关闭期间到期的那些occurrence怎么处理(ipc-routines.ts、routine-tool-schema.ts):
| 取值 | 行为 |
|---|---|
skip | 记录并丢弃这些到期点(默认,一次性计划除外) |
run-once | OpenBot 启动时只跑最新的一次,其余记录在案(once计划默认) |
这条策略必须写进 playbook 的异常处理节,否则“周一早上的汇总”在长假后会变成十次连跑。
第 3 步:授权边界、人工裁决与凭据隔离
第 3 条要求:“Identify which external changes require authorization and where a person must resolve ambiguity. Keep credentials out of the playbook.”
哪些外部变更需要授权
判断标准是“变更是否对外可见或不可撤销”。在 OpenBot 的实现里,可以把这条规则落成三档:
| 档位 | 例子 | OpenBot 中的落点 |
|---|---|---|
| 只读 | 拉取导出、读取工单 | 无额外授权 |
| 可逆写 | 写草稿、建分支 | 由 Agent 权限与审批策略约束 |
| 不可逆/对外 | 发送邮件、合并、改配置 | 必须有人批准;浏览器接管与密钥问题回到 App 内完成 |
本地脚本接口明确写着:它可以回答问题和接受/拒绝审批,但浏览器接管与 secret 问题必须在 OpenBot 中完成;并且“A script cannot change the agent's permissions or turn Local scripts on”。这正好支撑“授权点必须显式标注在执行者列上”这一要求。
人在哪里裁决歧义
歧义不是失败,而是需要指定裁决人的分支。常见写法:“若变更清单里存在数据库迁移,则由技术负责人在 30 分钟内判定是否需要回滚方案;未判定前流程停在草稿状态。” 在 OpenBot 里,这类停顿表现为 run 进入needs-attention,或 Agent 打开一个等待并在聊天中告知用户。
凭据绝不进入 playbook 正文
这是技能里唯一一条带“Keep ... out of”的硬性要求。仓库中有两条对应的安全设计可以作为依据:
- 任务需要的 API key 通过
openbot.request_api_key走表单收集,保存为<userData>/agent-api-keys/<agentId>/<NAME>(0600 文件、0700 目录,位于所有 workspace 之外),Agent只拿到名字和路径,由它自己在命令里读取;保存时会注册到日志脱敏。 - 密码类凭据由 1Password / Bitwarden 连接器托管,Agent 与 provider 都拿不到 token、密码或验证码;连接器的面板会遮蔽 header 与环境变量值。
因此 playbook 里应该写“从$OPENBOT_API_KEY_FILE读取密钥”,而不是写密钥本身,也不是写读取密钥的具体命令行参数(避免凭据出现在进程参数里)。automation 文档对 token 也有同样告诫:不要把 token 放进命令参数,Linux 上其他用户能读到进程参数,应使用-H @headers。
第 4 步:只对“输入齐备且结果可验证”的步骤提出自动化
第 4 条要求:“Propose automation only for steps with available inputs and a verifiable result. State integration gaps instead of claiming the workflow is connected.”
这是一条筛选规则,可写成两个问题的与运算:
- 输入是否已经在手(文件路径、API 返回、上一段产出)?
- 结果是否可验证(能比对、能断言、能被人一眼判对错)?
两者都为真,才进入自动化候选;否则进入“集成缺口”清单。
自动化候选的落地形态:create_routine
在 OpenBot 中,“周期性或时间相关的重复工作”应交给 Routine,而不是让 Agent 反复手动执行。这一点在开发者指令里写得很直接:遇到 “every morning” 或 “remind me” 这类请求,应创建 routine。工具定义位于 openbot-tools.ts,参数如下:
| 参数 | 类型/取值 | 说明 |
|---|---|---|
agentId | 可选字符串 | 目标 Agent;省略即自己 |
name | 1–80 字符 | Routine 名,同名会被拒绝并提示改用update_routine |
instruction | 1–100000 字符 | 每次运行要做什么,必须自包含 |
schedule | RoutineSchedule | 见下表 |
active | 布尔,默认true | 是否启用;建议在评审前以false创建 |
timezone | IANA 时区,≤128 字符 | 省略时取该轮对话发送者的时区,未知则取服务器时区 |
limitPolicy | wait/skip,默认wait | provider 额度用尽时的行为 |
missedPolicy | skip/run-once | OpenBot 关闭期间到期点的处理 |
schedule的完整形态定义在 ipc-routines.ts,校验形态在 routine-tool-schema.ts:
kind | 必填字段 | 约束 |
|---|---|---|
hourly | minute0–59 | 每小时固定分钟 |
daily | timeHH:mm | 每天 |
weekdays | time | 周一至周五 |
weekly | weekday0–6(0=周日)、time | 每周 |
monthly | day1–31、time | 每月 |
interval | amount1–100000、unitminutes/hours/days、anchorAtISO 时间 | 最小 3 分钟(ROUTINE_MINIMUM_INTERVAL_MINUTES) |
advanced | months1–12、days、time | days支持every-day/days-of-week/days-of-month;time支持at-time或every(分钟/小时) |
custom | expression≤255 字符 | Cron 表达式,最小间隔同为 3 分钟 |
once | dateYYYY-MM-DD、time | 只跑一次,随后自动暂停;仅存在于本机 host,发布的 Team API 会拒绝 |
其中once的“仅本机”特性是一个值得在 playbook 里明说的边界:一次性提醒在团队 API 投影里不存在,跨设备/服务端场景不要依赖它。
指令必须自包含
ROUTINE_INSTRUCTION_RULE是workflow-playbook与实现之间最重要的一座桥(routine-tool-schema.ts):每次运行都会开一个新的 provider 会话,只能看到最新的聊天消息。所以“按之前那样检查邮箱”这种写法会让运行直接失去上下文。
规则要求指令里写明:
- 用哪个服务、哪个工具(例如
openbot_browser+ 站点 + 已登录标签页,或具体的 MCP 工具、协作 Agent); - 用哪个账号;
- 具体步骤;
- 报告什么、报到哪;
- 什么时候什么都不报;
- 禁止出现 “as before” 或对聊天的指代。
“什么时候什么都不报”不是客套。OpenBot 为此提供了routine_no_update工具:在定时/脚本/webhook 运行中,如果确实没有可报告的内容,调用它会把本轮文本答案折叠进运行记录、不发通知;而如果确实需要报告,就不该调用它。对应的失败语义由routine_report_failure承担:任务因依赖不可用而无法完成时,运行以失败终态结束,并在历史中可见,但答案照常给出。
这两条工具的存在,让 playbook 的“完成 / 无事 / 失败”三分法可以真正被机器表达,而不是靠人在通知里猜。
集成缺口要明说
“State integration gaps instead of claiming the workflow is connected.” 的落地写法示例:
缺口:当前 Agent 没有挂载 CRM 的 MCP server,第 5 步“回写客户记录”只能产出待粘贴文本。 需要:在 Agent 的 MCP 设置中启用对应 server,或用
openbot_browser打开已登录的 CRM 标签页。
对比一下错误写法:“第 5 步会自动回写 CRM。”——这正是 Operations Planner 明确禁止的“声称已连通”。
从 Playbook 到 Routine:一次完整的映射示例
把前四步的产出压缩成一条可创建的最小自动化,示意如下(字段名均来自create_routine的 schema):
{ "name": "weekly-release-notes", "instruction": "Read merged pull requests from the last 7 days in repository openbot (use the GitHub MCP tool with owner and repo arguments). Group them as Added / Fixed / Changed. Write the draft to releases/next.md in the workspace. Report the file path and the count of entries. Flag any entry whose title contains 'breaking'. Report nothing if no pull requests were merged; call routine_no_update in that case.", "schedule": { "kind": "weekly", "weekday": 1, "time": "09:00" }, "active": false, "timezone": "Asia/Shanghai", "limitPolicy": "wait", "missedPolicy": "run-once" }几个刻意的选择对应前文的原则:
active: false:先建后验,符合“未经请求不要开启周期任务”。仓库里 Dr. Eggbot 的两个健康检查 routine 也是以 paused 状态安装的("active": false)。timezone显式给出,避免依赖“发送者时区”这种隐式默认。missedPolicy: "run-once":长假后只补跑最新一次,而不是积压十次。- 指令里点名工具、仓库、输出路径、报告内容与静默条件,无任何“像之前那样”的指代。
- 没有写任何凭据;需要 GitHub 身份时依赖已连接连接器提供的
gh/git凭据助手或 MCP 授权。
创建后应立刻用list_routines读回确认(Agent Designer 技能里对 routine 也要求“创建后读回确认”),再做一次test_routine手动测试运行。test_routine只是把一次手动运行排入队列,适合当作 playbook 的第一次验收。
用本地脚本触发并验收:把“可验证结果”变成机器判据
当流程的触发点不在时间表上,而在本机某个长任务结束时,workflow-playbook的“输入齐备 + 结果可验证”对应到 OpenBot 的Local scripts API。它不是默认开启的:设置是按 Agent的、默认关闭,需要在 Agent 设置的Permissions中打开Local scripts,且 Agent 无法为自己或队友开启。
开启后,OpenBot 在<userData>/automation/写三个文件(目录 0700、文件 0600,仅同 OS 用户可读):url、token、headers。每次启动都会换新端口与新 token,命令在运行时才读取文件,所以重启前复制的命令仍然可用。
触发一次 routine 的最小写法(macOS/Linux):
long-job; curl -sS -X POST "$(cat "$OPENBOT_AUTOMATION/url")/v1/agents/<agentId>/routines/<routineId>/run" \ -H @"$OPENBOT_AUTOMATION/headers" \ -H 'Content-Type: application/json' \ -d '{"payload":"long-job ended with code 0"}'用 CLI 时不必手写请求:
openbot-cli list # 列出开启了 Local scripts 的 Agent openbot-cli run "Ada" "Run the tests and tell me what failed" --wait openbot-cli status "Ada" <deliveryId> openbot-cli run "Ada" - --wait --json < task.md把验收写进 playbook 时,几张表最有价值。
Routine run 的状态码与拒绝原因(automation 文档):
| 状态 | 含义 |
|---|---|
| 202 | 已入队,不代表已执行 |
| 400 | body 非 JSON、payload非字符串、waitId非法 |
| 401 | token 缺失或错误 |
| 403 | 带Origin头或非本机Host,或该 Agent 未开启 Local scripts |
| 404 | Agent 或 routine 不存在 |
| 409 | Agent 当前不能接受该运行(例如正在删除) |
| 413 | body 超过 32 KiB,或 payload 超过 4000 字符 |
| 415 | Content-Type不是application/json |
| 429 | 该 Agent 最近一小时已接受 30 次本地脚本运行 |
CLI 退出码可以当作 playbook 的分支条件:
| 退出码 | 含义 | playbook 中的动作 |
|---|---|---|
| 0 | 完成(--wait时该轮结束) | 进入验收检查 |
| 1 | 该轮失败/被停止/被取消,或请求被拒 | 按重试上限重试,超限升级 |
| 2 | 命令行错误或存在同名 Agent | 修正调用,不重试 |
| 3 | Agent 在等人(提问、审批、浏览器接管) | 转人工,回答后用status继续 |
| 4 | 等待超时(Agent 仍在工作) | 记录 deliveryId,稍后status |
| 5 | OpenBot 未运行、无 Agent 开启 Local scripts、或找不到 Agent | 环境检查 |
--timeout(90s、5m、2h;默认30m)只停止等待,不停止工作——这一点必须写进 playbook 的“超时”分支,否则执行者会误以为任务被取消了。
payload的传递也有明确语义:它会附在 routine 指令之后,位于--- event from a local script ---标题下,并带一行提示让 Agent 把它当数据而非指令阅读;运行历史会保留它,所以被重启打断的运行会重新带上它。这正是“中断后可安全恢复”的实现基础,也提醒你:payload 是数据通道,不是注入指令的地方。
交付物:流程、异常处理、验收检查、最小自动化计划
Deliverable一节要求返回四件东西,并且只写“被请求的层级”:
Return the process, exception handling, acceptance checks, and a minimal automation plan. Draft instructions or code only at the level requested; do not enable a recurring job without a request.
建议的交付结构(可直接套用):
1. 流程
第 1 步的四列表格,加上每一步的“完成定义”。
2. 异常处理
按“异常 → 检测方式 → 处理 → 升级对象”四列写,覆盖至少这几类:
- 输入缺失或格式不符(停止,回退到上一责任人);
- 外部服务不可用(有限次数重试,然后记录缺口);
- 额度用尽(
limitPolicy: wait排队到重置,或skip丢弃并在历史中标记cancelled); - 关闭期间到期(
missedPolicy行为,并说明长假后的预期); - 需要授权或存在歧义(转人工,等待 ID 与超时时间写清楚)。
3. 验收检查
每条都要能被别人独立执行,例如:
openbot-cli run ... --wait退出码为 0;- run 历史终态为
succeeded; - 产出文件存在且包含 N 个小节,标题与模板一致;
- 无变更时通知数为 0(
routine_no_update生效)。
4. 最小自动化计划
只列已通过“输入齐备 + 结果可验证”双条件的步骤,每项包含:对应 routine 名、schedule、输入来源、验证方式、以及尚未解决的集成缺口。默认以active: false起草,等验收通过、并且用户明确要求后再启用。
常见失败模式
对照源码与文档,以下五种写法最容易把 playbook 写坏:
- 把“工具名”当“权限”。技能第一条就警告不要因为提到某服务就假设有访问权;MCP 会话按 token 绑定、凭据由连接器托管,缺的就是缺的,要写进缺口清单。
- 指令依赖聊天上下文。
ROUTINE_INSTRUCTION_RULE说明每次运行都是新会话,只看到最新聊天消息;“as before” 会让运行失去执行路径。 - 把凭据写进流程。哪怕写在“附注”里也不行;正确做法是指向密钥文件路径或由连接器提供。
- 默认开启周期任务。
create_routine的active默认是true,很容易在评审前就跑起来;技能要求“without a request 不要开启”,因此显式传false。 - 用重试解决幂等问题。routine run 没有重试键,盲目重试可能启动两次;重复防护要落在名字去重、
clientMessageId(消息路由)和流程内的“先查后写”上。
相关文件索引
- 技能正文:marketplace/production-catalog/skills/workflow-playbook/SKILL.md
- 目录元数据与 Agent 绑定:marketplace/production-catalog/catalog.json
- 发布目录说明(版本、重复与更新规则):marketplace/production-catalog/README.md
- 技能装载与目录规则:docs/architecture/skills-and-plugins.md
- Routine 工具定义:src/backend/openbot-tools.ts
- Routine schema 与指令规则:src/backend/routine-tool-schema.ts
- 调度器(含同名去重):src/backend/agent/routine-scheduler.ts
- 契约类型(schedule / 状态 / 策略):packages/contracts/src/ipc-routines.ts
- 输入上限常量:packages/contracts/src/input-limits.ts
- 本地脚本 API 与 CLI:docs/automation.md
- 相邻技能(范围与验收口径):marketplace/production-catalog/skills/project-plan/SKILL.md
【免费下载链接】openbot
A local-first desktop workspace for persistent AI teammates. Run Codex, Claude, and Grok with dedicated workspaces, task queues, file sharing, browser control, and agent-to-agent collaboration.
相关推荐
OpenBot pstack 实战:用 opening-a-pr playbook 把每个改动变成可评审、可合并的 PR
OpenBot pstack 实战:用 opening a pr playbook 把每个改动变成可评审、可合并的 PR opening a pr 是 psta
OpenBot secure-code-guidance 技能实战:把安全审查与安全实现变成可执行流程
OpenBot secure code guidance 技能实战:把安全审查与安全实现变成可执行流程 在 OpenBot 的 Marketplace 生产目录
在 OpenBot 中编写与修改 Agent Skill:poteto-mode 的 authoring-a-skill playbook 实战指南
在 OpenBot 中编写与修改 Agent Skill:poteto mode 的 authoring a skill playbook 实战指南 potet
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考