10 KiB
10 KiB
使用说明:在 Plane 上派活给各机器上的 agent
核对依据:agentd/core.py、agentd/webhook.py、config/agentd.yaml、LXC 上的实际状态、Plane GWENT 项目的标签和成员(2026-10-22)。代码或配置改了要同步改这里。
1. 派单需要的字段
- 必填:状态设为
Todo,指派人里至少有一个终端账号(window10或oregon)。标题加描述就是任务书,原样进入 prompt。标签可选,模块与调度无关。 - 有多个指派人时,按 Plane 返回的顺序,第一个能对上终端的账号生效(
core.py的route())。所以"kappiee + window10"会派到 win10。 - 只指派
kappiee、指派mac(暂无终端)或不指派:route()返回空,这一项被静默跳过。Plane 上不会有任何评论,只在heartbeat.json的skipped里记一条no route for assignee kappiee,agentd.log里在原因第一次出现时记一行。 - 只有
Todo状态的项会被拾起(pick())。Backlog、Waiting、Review 永远不会自动执行。唯一例外是处于 In Progress、等待临时性重试的项。
2. 终端、执行器和默认值
| Plane 指派人 | 终端 | 执行器 | 默认模型 / effort / 档位 | 运行目录(日志和输出) |
|---|---|---|---|---|
window10 |
win10(Tailscale 直连 SSH,Warpgate 兜底;Windows 计划任务) | codex(codex exec,workspace-write) |
gpt-6.1-sol / medium / fast |
C:\…\gwent\runtime\agentd\<run_id>\(prompt.md run.ps1 events.jsonl last.md stderr.txt exit.txt) |
oregon |
oregon(Tailscale 直连 SSH,Warpgate 兜底;setsid nohup) |
claude-code(claude -p --permission-mode acceptEdits) |
sonnet / (不传 effort)/ — |
/home/ubuntu/.gwent-board/agentd-runs/<run_id>/(out.json 等) |
kappiee / mac / 无人 |
不派 | — | — | — |
- 两个终端的并发都是 1,按终端计数,跨项目共享。
- win10 设了
busy_processes: [codex]:agentd 自己在 win10 上没有在途运行、却发现有codex.exe在跑时,不派单(busy_process codex (… not started by agentd))。 - oregon 的运行直接在
/home/ubuntu/Documents/wjj/project/gwent里改文件。这正是指挥所用的 checkout。
3. 代码里实际生效的标签
Plane 里目前只建了 4 个标签:model:astra、model:sol、effort:high、needs-game。其余前缀的标签要先在 Plane 里建出来才能挂上。
| 标签 | 效果(route()) |
|---|---|
model:astra |
改用 gpt-6-astra,effort high(来自 by_label 配置) |
model:sol |
改用 gpt-6.1-sol,tier fast |
model:<x>(其他任意) |
模型名原样改成 x,例如 oregon 上的 model:opus。模型名与执行器相关:model:astra 挂在 oregon 的项上会让 claude 失败 |
effort:<x> |
只对 codex 生效。claude 的命令模板里没有 {effort},所以被忽略 |
tier:<x> / tier:none |
只对 codex 生效,改档位或去掉档位参数 |
needs-game |
串行组 game:同组同时只跑一项;env 类失败会暂停整组,直到该项离开 Waiting。needs-* 不是通用前缀,只有配置里写了的才生效 |
exec:<executor> |
要求同名执行器存在且终端支持。现在每个终端只有一个执行器,例如 exec:codex 挂在 oregon 上只会得到 executor codex not available 跳过,等于没用 |
cap:<x> |
终端的 capabilities 里必须有 x。win10 有 [android, game],oregon 没有,不满足就跳过 |
budget:2h / budget:90m |
覆盖超时时间,默认 4 h |
多个标签按顺序处理,后面的覆盖前面的。
4. 一轮的完整流程
- 触发:Plane 的工作区级 webhook(
issue和issue_comment事件)约 1 s 内送到http://10.77.10.249:8790/plane。- 接收端用 HMAC 校验签名,只认 GWENT 项目,其他项目返回 202 忽略。
- 等 3 s,把这期间的投递合并成一次 tick。tick 跑的就是 cron 脚本。
- tick 运行中又来投递时,结束后再补跑一次。锁被占用(退出码 75)时每 15 s 重试,最多 2 min。
- 兜底:cron 每 2 分钟一次 tick,同一把
cron.lock。 - agentd 自己回帖、改状态也会产生投递,所以每个有动作的 tick 后面都会多一次空 tick(实测 11.1 s)。
- tick 的步骤:先 poll 所有在途运行(每个一次远程调用:直连亚秒到约 2 s,走 Warpgate 时约 10 s),再按编号从小到大挑 Todo 项。依次检查:终端是否可达、并发槽位、串行组、busy 进程。
- 启动前先把
launching标记落盘,防止重复启动。 - 启动后把项改为 In Progress 并指派给终端账号,以终端账号发评论
[worker] 第 k 轮开始:codex / gpt-6-astra / high @ win10,新线程,run=GW-26-1。
- 启动前先把
- 实测耗时(runbook 记录和 LXC 的 webhook.log):
- 建项到投递约 1 s,再加 3 s 合并窗口。
- win10 启动的那次 tick 91.4 s(GW-26:建项 01:25:14,开工评论 01:26:49)。
- oregon 启动的 tick 约 72 s。
- 空 tick 4.6–4.8 s。
- 以上是 Warpgate 时期的数字,瓶颈在中继调用,与触发方式无关。
- PAD-12 起两个终端都走 Tailscale 直连:win10 启动由约 10 次中继调用变成 busy 检查 + 1 次启动调用,收尾由约 7 次变成 2 次。目标是建项到开工评论 ≤ 15 s,上线后在这里补实测。直连不通时这一轮自动走 Warpgate,只是慢,派单行为不变(design §9)。
- 结束时:以终端账号回帖。
- 第一行是
[codex] 第 k 轮结束(exit=…,run=…,终端 win10,日志 <运行目录>),下面是 agent 的最后消息原文(<pre>包裹,超过 6000 字截断,并注明全文所在路径)。 - 再按最后消息首行的标签流转(
transition()):
- 第一行是
| 首行 | 状态 / 指派人 |
|---|---|
[review] |
Review,指派 oregon(reviewer) |
[question] / [blocked] |
Waiting,指派 oregon(answerer) |
[progress] |
回到 Todo,留在原终端,下一 tick 续同一线程。连续 12 轮后转 Waiting |
| 没有标签但 exit=0 | 按 review 处理,并注明"未按协议标注首行" |
注意:Waiting 和 Review 都指派给 oregon,不是 kappiee。没有任何东西会自动处理这两个状态,由指挥(或你)介入。
5. 失败:回帖 [worker] 第 k 轮失败:类型=crash|timeout|env|logic,run,exit,重试 n/3。… 并附上最后一帧输出。
- 临时性错误(stderr 尾部匹配超时、429、5xx、连接被拒等)自动重试,退避 2/5/10 min,续原线程,状态保持 In Progress。
- 续线程那一轮出现非临时性失败时,立即在新线程重跑一次,并附交接摘要。
- 其余情况转 Waiting,指派 oregon。超时会先 kill 进程树。逻辑类失败永不自动重试。
5. 回答问题和续跑
- 在项上发评论回答,开头不要写
[worker],这类评论永远会被跳过。 - 把状态改回 Todo,并把指派人改回原终端(例如
window10)。这一步是坑:如果指派人还是 oregon 就改 Todo,会派给 oregon 的 Claude。因为终端或执行器变了,会重建线程并附交接摘要。 - 同一终端、同一执行器、线程续了不到 8 轮时,走
codex exec resume或claude --resume,只发送上次之后的新评论(按评论 ID 判断)。 - 单发评论只会触发一次空 tick,不会让 agent 动起来,必须改回 Todo。运行期间发的评论,跑着的那一轮看不到,下一轮才带上。
6. 取消和停止
- 把运行中的项移出 In Progress(改成 Waiting、Backlog、Cancelled 都可以)。下一 tick 会 kill 进程树,回帖
[worker] 运行已取消:工作项状态被改为 X(run=…),释放槽位和串行组,保留线程 ID(cancel())。 - 如果移到的是 Todo:同一 tick 里先取消,再立刻按新一轮重新派发(续原线程),相当于"带上新评论重启"。
- 运行已经结束时(
exit.txt已写)再移动:结果照常回帖,但不再改状态,也不重试。 - 暂停整个终端:把它的
concurrency设为 0(需要改配置,不能在 Plane 里操作)。
7. 日志和状态的位置(LXC)
/var/log/plane-agentd/{agentd.log, cron.log, webhook.log}/var/lib/plane-agentd/{agentd-state.json, heartbeat.json}:heartbeat 里有skipped及原因、inflight、down。- 健康检查:
GET http://10.77.10.249:8790/healthz - 任务产出本身在终端的 repo 里,gwent 的惯例是 win10 的
runtime/edits/GW-k/。
8. 用手机试一下(冒烟测试,5 步)
- GWENT 新建工作项,标题
冒烟 oregon 往返。描述:只回复一行 [review] ok;不要读写或修改任何文件,不要运行命令。oregon 的 Claude 是 acceptEdits,并且在指挥用的 checkout 里运行,所以这句必须写。 - 指派人只选 oregon,不加标签(默认 sonnet),状态设为 Todo。
- 约 1–1.5 分钟后:状态变成 In Progress,出现 oregon 发的评论
[worker] 第 1 轮开始:claude-code / sonnet @ oregon,新线程,run=GW-n-1。 - 再过约 1–3 分钟(历次冒烟 1.5–3 min):出现评论
[claude-code] 第 1 轮结束(exit=0 …)加[review] ok,状态变为 Review、指派 oregon。 - 可选,测续线程:评论
请只回复 [review] ok 2,状态改回 Todo(指派保持 oregon)。开始评论会写"续线程 xxxx",结束后回[review] ok 2。最后手动改成 Done。- 超过 3 分钟没动静:看 heartbeat 的
skipped,常见原因是 oregon 槽位被占,或指派人不对。
- 超过 3 分钟没动静:看 heartbeat 的
9. 通知和手机 App(2026-10-22 核实)
- Plane 官方手机 App 可以登录自建的 Commercial 版(选 "Self hosted sign in",填
https://plane.kappiee.com)。plane.kappiee.com 只对内网和 tailnet 开放,手机要开 Tailscale。 - 自建实例没有手机推送:Plane 文档原文 "Push notifications are currently available only for Plane Cloud users."(docs.plane.so/devices/mobile)。App 里只能在收件箱看到通知。
- 收件箱只收你被指派、被 @、创建或订阅的项。Waiting 和 Review 现在都指派给 oregon,不会进你的收件箱。需要你处理的项,由指挥改成指派 kappiee 或 @你。
- 真正推到手机要走外部渠道:给 Plane 配 SMTP 发邮件,或用 ntfy 之类。计划放在最后(PAD-13)。agentd 里现在的
notify: {kind: none}是空钩子。