Files
plane-agentd/docs/usage.md
T

106 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 使用说明:在 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. 一轮的完整流程
1. **触发**: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)。
2. **tick 的步骤**:先 poll 所有在途运行(每个一次远程调用:直连亚秒到约 2 s,走 Warpgate 时约 10 s),再按编号从小到大挑 Todo 项。依次检查:终端是否可达、并发槽位、串行组、busy 进程。
- 启动前先把 `launching` 标记落盘,防止重复启动。
- 启动后把项改为 In Progress 并指派给终端账号,以终端账号发评论 `[worker] 第 k 轮开始:codex / gpt-6-astra / high @ win10,新线程,run=GW-26-1。`
3. **实测耗时**(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)。
4. **结束时**:以终端账号回帖。
- 第一行是 `[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. 回答问题和续跑
1. 在项上发评论回答,开头不要写 `[worker]`,这类评论永远会被跳过。
2. **把状态改回 Todo,并把指派人改回原终端**(例如 `window10`)。这一步是坑:如果指派人还是 oregon 就改 Todo,会派给 oregon 的 Claude。因为终端或执行器变了,会**重建线程**并附交接摘要。
3. 同一终端、同一执行器、线程续了不到 8 轮时,走 `codex exec resume` 或 `claude --resume`,只发送上次之后的新评论(按评论 ID 判断)。
4. 单发评论只会触发一次空 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 步)
1. GWENT 新建工作项,标题 `冒烟 oregon 往返`。描述:`只回复一行 [review] ok;不要读写或修改任何文件,不要运行命令。` oregon 的 Claude 是 acceptEdits,并且在指挥用的 checkout 里运行,所以这句必须写。
2. 指派人**只选 oregon**,不加标签(默认 sonnet),状态设为 **Todo**。
3. 约 1–1.5 分钟后:状态变成 In Progress,出现 oregon 发的评论 `[worker] 第 1 轮开始:claude-code / sonnet @ oregon,新线程,run=GW-n-1。`
4. 再过约 1–3 分钟(历次冒烟 1.5–3 min):出现评论 `[claude-code] 第 1 轮结束(exit=0 …)` 加 `[review] ok`,状态变为 Review、指派 oregon。
5. 可选,测续线程:评论 `请只回复 [review] ok 2`,状态改回 Todo(指派保持 oregon)。开始评论会写"续线程 xxxx",结束后回 `[review] ok 2`。最后手动改成 Done。
- 超过 3 分钟没动静:看 heartbeat 的 `skipped`,常见原因是 oregon 槽位被占,或指派人不对。
## 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}` 是空钩子。