tianshu-mcp · diff
git:20261006.455e074 to git:20261006.ee417ec
1 added, 1 removed. Audit A to A.
---
name: tianshu-mcp
description: 让外部 AI-Agent(codex/zcode/traework/kimicode/qoder/opendesign/minimax)做项目开发并自动验收、失败返修的编排方法。当任务需要“叫一个 AI-Agent 去开发/改代码/补测试并验收,不行就返修”时先加载本技能:按它用 mcp__tianshu-mcp__ 的 13 个工具(run_task/continue_task/query_task/list_tasks/get_task_report/verify_task/rework_task/cancel_task/get_profiles/wait_task/wait_any/prepare_visual_baseline/approve_visual_baseline)派活、等待、验收、返修、视觉基准,并按硬失败错误码快速定位卡点。小改动或纯问答不需要。
triggers: '开发|编码|写代码|改代码|实现功能|加功能|修复|重构|补测试|写测试|验收|返修|返工|重做|自动验收|自动返修|任务书|ai.?agent|子代理|外部.?agent|agent|codex|zcode|traework|kimicode|kimi.?code|qoder|opendesign|open.?design|minimax|mini.?max|claude|编排|项目开发|派活|派单'
---
# tianshu-mcp 编排技能:叫外部 AI-Agent 开发并验收
**你是总指挥,不是开发**。你不改项目代码,只通过本 MCP 派活、轮询、读报告、驱动返修,并把结论如实汇报给用户。
**首行强指令**:动手前读完本文件。任务书模板、六种派活示例、meta 字段全表(§4)、错误码速查(§5)、项目级验收配置模板、needs_user/取消示例在同目录 `usage-examples.md`,需要时用读取文件工具查看,长方法论不必背。
---
## 0. 一分钟心智模型
```text
run_task(秒回 taskId,异步)
→ wait_task 阻塞等到停点(终态或 needs_user;超时后再调一次继续等)
→ 需要进度细节时 query_task 轮询(5–10 秒一次)
├─ needs_user → §5:让用户在客户端处理 → continue_task 恢复
├─ 硬失败 → §9:读 agentEndReason,不要当“agent 没做好”重试
└─ 终态 → §6:读 get_task_report 的 checks / analysis / visual
→ 验收失败且 autoFixRounds>0 → 自动返修(先落修复计划,再回原会话)
→ 人工不满意 → rework_task(taskId, feedback=针对性摘要)
```
三条不变式:
1. **异步契约**:`run_task` 只返回 `taskId`;严禁把它当同步调用等结果。
2. **验收是唯一裁判**:agent 说“完成”不算通过,`get_task_report` 的 checks 才算。
3. **不空转**:同一诊断只重试一次;第二次仍失败就带证据汇报,或换 agent / 缩小任务。
---
## 1. 工具面(13 个)
| 工具 | 能力 / 审批 | 作用 | 关键入参 |
|---|---|---|---|
| `run_task` | write + 审批 | 派活给外部 agent;**异步**返回 `taskId` | 见 §3 |
| `query_task` | read | 轮询状态 + agent 日志尾(`tailLines` 缺省 40 行) | `taskId`、`tailLines?` |
| `wait_task` | read | **阻塞等待**单任务到停点(终态或 `needs_user`)或超时;超时后再次调用继续等。纯只读、无害 | `taskId`、`timeoutMs?`(缺省 50000、上限 600000) |
| `wait_any` | read | **阻塞等待**一组任务(1..20)中数组顺序首个到停点者;返回其快照 + 全部状态 | `taskIds`、`timeoutMs?` |
| `list_tasks` | read | 查历史任务(每行:taskId / status / agent / project / 摘要) | `projectPath?`、`status?`、`limit?`(缺省 50,上限 200) |
| `get_task_report` | read | 读某轮验收报告 **Markdown 全文** | `taskId`、`round?`(0-based,缺省最新) |
| `verify_task` | execute(不改源码、无需审批) | 对任务或任意项目**独立验收**(会跑项目命令、可产生构建产物,故 `readOnlyHint=false`;不改源码、无需审批) | `taskId` 或 `projectPath` 二选一、`extraChecks?`、`checksMode?`、`baselineRef?` |
| `rework_task` | write + 审批 | 手动返修:终态任务重新入队续跑(同 agent/项目、同一轮次记账) | `taskId`、`feedback?` |
| `continue_task` | write + 审批 | 恢复 `needs_user`(仅 codex/zcode/kimicode/qoder/opendesign/minimax;traework 与 spawn 类不支持) | `taskId`、`message`(必填) |
| `cancel_task` | write + 审批 | 取消运行中任务(GUI agent 尽力点停止并回读) | `taskId`、`reason?` |
| `get_profiles` | read | 看当前机器实际探测结果(可用性、profileStatus、探测来源) | — |
| `prepare_visual_baseline` | write + 审批 | 视觉基准**候选**准备(截图或导入参考图) | `projectPath` 等,见 §8 |
| `approve_visual_baseline` | write + 审批 | **用户明确授权后**批准候选,写入正式基准 | `candidateId`、`expectedDigest`、`approvalNote` |
---
## 2. 何时不要用(边界)
- **小改动 / 纯问答 / 只读代码分析**:直接做,不要为本技能开任务。
- **本 MCP 未连接**:工具面里看不到 `mcp__tianshu-mcp__*` 时,先提示用户按天枢 `config.json → mcp.servers.tianshu-mcp` 接入(见项目 `docs/tianshu-integration.md`),**不要空转**,更不要假装调用。
- **agent 未安装 / 未登录**:`get_profiles` 报 `[FAIL] 不可用` 时如实转达,不要改路径硬试或换一个“看起来像”的窗口。macOS 上 `minimax` 为 `research` 且**禁止派发**(与 qoder/opendesign 同)。
---
## 3. 选 agent
所有内置 agent 都是 **GUI 驱动**(CDP 控制桌面端),不是 CLI。默认 `agentId` 取项目登记值,未登记时为 `codex`。
### 3.1 参数兼容矩阵(传错即报错,不会静默忽略)
| 参数 | codex | zcode | traework | kimicode | qoder | opendesign | minimax |
|---|---|---|---|---|---|---|---|
| `projectPath` | 必填 | **可省略**(无项目模式,见 §3.4) | 必填 | 必填 | 必填 | 必填(无项目派发现仅支持 zcode) | 必填(**不支持无项目派发**) |
| `model` | **必填**(面板模型名) | **必填**,`供应商/模型` | 可选 | **必填**(界面模型名) | 可选 | **必填**(界面模型名;精确匹配,未命中回显候选) | **必填**(界面模型名;精确匹配,未命中回显候选) |
| `modelSource` | ✗ | ✗ | ✗ | ✗ | 可选 `default`/`custom` | ✗ | ✗ |
| `reasoningLevel` | `低/中/高`(`low/medium/high`) | `低/low`、`中/medium`、`高/high`、`max`、`on/off`(以界面实际档位为准) | ✗ | `低/low`、`高/high`、`max`、`on`、`off` | `低/中/高/极高/最大/关闭思考` | ✗ | `default`/`低·low`/`中·medium`/`高·high`/`极高·xhigh`/`最大·max`(**含 `中`/`medium`**;以界面实际档位为准) |
| `mode` | ✗ | ✗ | **唯一支持**(`Work`/`Code`/`Design`) | ✗ | ✗ | ✗(用 `designDirection`) | ✗ |
| `designDirection` | ✗ | ✗ | ✗ | ✗ | ✗ | **必填**(`原型`/`文档`/`网站复刻`) | ✗ |
| `planDoc` | 可选 | ✗ | ✗ | ✗ | **必填**且必须可读 | ✗ | ✗ |
| `designSystem` | 可选 | ✗ | ✗ | ✗ | ✗ | 可选(**设计系统名**,如 `Claude`) | ✗ |
| `allowCreateProject` | ✗ | 可选(`false` 关自动导入) | ✗ | ✗ | ✗ | ✗ | ✗ |
| `contextWindow` | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | **可选**(`512K`/`1M` 等界面候选文本;**本适配器专属**) |
| `continue_task` | 仅 `login_required` / `user_confirmation` | `agent_question` 回发答案;其余作已处理确认 | **不支持** | 见 §5 | 见 §5 | 见 §5 | 见 §5 |
`reasoningLevel` 的中文别名 `极高`/`xhigh`、`最大`、`关闭思考` **只有 qoder 与 minimax 接受**(minimax 无 `关闭思考` 档,传了按越权报错),传给其他 agent 会直接报错。`max`/`off` 是全局取值,各适配器自行判定是否支持。`contextWindow` **仅 minimax 可用**,传给其他 agent 直接报错。
**默认值优先级**(不写参数时的取值顺序):
| 项 | 优先级 |
|---|---|
| `autoVerify` | 调用参数 > server 默认(**默认 `true`**,即默认开验收) |
| `autoFixRounds` | 调用参数 > agent 缺省 > server 默认 `0`(=不自动返修)。agent 缺省:codex 5,zcode 2,kimicode 2,qoder 3,minimax 2,traework 未设(落 server 默认 0) |
| `taskTimeoutMs` | 调用参数 > profile `timeoutMs`(GUI agent 均 30 分钟)> server 默认 30 分钟 |
### 3.2 逐个 agent 要点
- **`codex`**(默认,推荐先试):ChatGPT/Codex 桌面端,MSIX COM 激活 + CDP(Windows 冷启动实测 60–90 秒,首轮偏慢属正常;macOS spawn `.app` + CDP)。
`model` 必填且用**面板里的模型名**;`planDoc`/`designSystem` 会拼进初始指令且必须存在、在项目内。**不支持 `mode`**。
- **`zcode`**:ZCode 桌面端(Electron CDP)。`model` 必填 `供应商/模型`(如 `DeepSeek/deepseek-flash`);发送前确认「完全访问」权限模式;**不支持 `mode`**。支持省略 `projectPath` 的无项目模式(§3.4)。
`reasoningLevel` 可选:档位集合**随模型变化**,以界面实际渲染的选项为准(真机实测 3.14.3:当前模型只有 `on`/`off` 两档,触发器 `chat-thought-level-select-trigger`)。传了界面不存在的档位在**发送前**报错(`reasoning_level_invalid`),绝不静默沿用;不传则不触碰档位界面(沿用当前值)。**换模型必须重开任务**(`model` 在 `run_task` 时固化)。
项目绑定按「路径优先、无路径时按显示名」分层判定;3.14.x 侧边栏的 `workspace-item-*` 可能仍挂在 DOM 里但被滚出视口(issue #27:实测 42 个中 40 个不可见),采集时按可见性过滤,不可达时回落「打开文件夹」导入路径。
- **`traework`**:TraeWork / TRAE SOLO CN。`model` 可选;**唯一支持 `mode`**(不传时从任务书文本识别「切换 X 模式」,识别不到保持 `Work`);实现顺序固定为「新建会话 → 切模式 → 在目标模式内绑定项目」。窗口必须保持可见(发送依赖模拟输入)。**`continue_task` 不支持**。
- **`kimicode`**:Kimi Code 桌面端(普通 Electron,实测 1.0.2;CDP 基准端口 9666)。`model` 必填,直接填**界面模型名**(如 `K3`、`K2.8 Preview`、`stepfun/step-3.7-flash:free`)。
`reasoningLevel` 取值域刻意**不含 `中`/`medium`**(那不是任何模型的合法档位):官方模型 `低/low`、`高/high`、`max`;非官方模型只有 `on`/`off`。档位集合以**界面实际渲染的标签**为准,传了界面不存在的档位在发送前报错,绝不静默沿用;不传时官方档位沿用界面当前值、非官方强制 `on`。
**不支持 `mode`**;**`allowCreateProject` 不适用**;**`projectPath` 必填**(以工作区组织任务,不支持无项目派发)。未登记工作区经原生「添加工作区」对话框导入,同名/同路径歧义一律 fail-closed。
排查注意:模型/思考档位/执行模式菜单渲染在独立的 `Kimi Browser Overlay` 浮层窗口,别在主窗口找。
- **`qoder`**:仅 **Qoder CN**;`projectPath` 与可读 `planDoc` 必填。
`model`/`reasoningLevel` 可省略(沿用界面当前值并记录);指定模型时若「默认」与「自定义」两组同名,必须用 `modelSource` 消歧,否则报 `qoder_model_ambiguous`。
思考等级经「模型管理」设置并**重新打开回读**验证,不支持的档位在发送前报错;修改会保留为**全局偏好**(任务结束不还原),报告会说明影响。权限模式沿用当前设置,**不自动切「完全访问」**。
自动与手动返修都**先落修复计划**,再把失败说明、计划文件名、完整路径与**全文**发回原会话。**macOS 为 `research` 且禁止派发**(`unsupported_platform`)。
- **`opendesign`**:Open Design 桌面端(Electron,实测 0.24.1;CDP 基准端口 **9889**)。Windows 真机取证;macOS 为 `research` 且禁止派发。
`designDirection` **必填**(只支持「原型 / 文档 / 网站复刻」;`幻灯片`/`图片`/`HyperFrames` 在**入口**即拒绝);`designSystem` 传**设计系统名**(如 `Claude`);`mode` 不支持。
界面驱动已接线,可正常派活;仍 **fail-closed**:选择器漂移时硬失败 `selector_drift`(列出缺失键),模型未命中报 `model_unavailable` 并回显候选,设计方向非法在**入口**即拒绝。
详见 [docs/opendesign-cdp.md](../../docs/opendesign-cdp.md) 与 `.dsh/plans/opendesign-gui-adapter-plan.md`。
排查注意:外层启动器是「内嵌 Node 的 Electron」,**调用方若带 `ELECTRON_RUN_AS_NODE=1` 会被置为 Node 模式而拒绝调试端口**(受管启动已自动净化环境)。
- **`minimax`**:MiniMax Code 桌面端(Electron,实测 3.1.0;CDP 基准端口 **9999**)。Windows 真机闭环已通过;macOS 为 `research` 且禁止派发。
`model` 必填,填**界面模型名**(如 `M3.1-Flash-Preview`、`M3`、`deepseek-v4.1-flash`、`M2.7-highspeed`),按名字**精确匹配**,未命中报 `model_unavailable` 并回显可见候选。
`reasoningLevel` 可选:**这是唯一接受 `中`/`medium` 的适配器**(界面确实有该档);取值 `default` / `低·low` / `中·medium` / `高·high` / `极高·xhigh` / `最大·max`。
`contextWindow` 可选(**本适配器专属**,如 `512K` / `1M`):取值与档位一样**按界面实际候选校验**,不在候选内即发送前报错。
**不支持 `mode`**;**`projectPath` 必填**(不支持无项目派发)。
关键差异(真机取证得出,别按其他适配器的直觉用):
- **档位/窗口在「悬停模型项才展开的二级子菜单」里**,不是平铺项;且**候选集合随模型变化**——
实测 `M3.1-Flash-Preview` 六档 + 两个窗口、`M3` **无档位组**、`deepseek-v4.1-flash` **无窗口组**、`M2.7*` **无子菜单**。
对无子菜单的模型请求 `reasoningLevel` / `contextWindow` 会**直接报错**(不静默沿用界面当前值)。
- 模型弹层渲染在**独立渲染进程**(`Model menu` 窗口),排查时别在主窗口找。
- 「新建项目」是**两步**:应用内「创建项目」模态框 → 「选择文件夹」触发原生 `Select Directory` → 再点模态框的「创建项目」提交。
- 权限模式默认「始终授权」;找不到时只告警不自动切换(权限菜单候选项未取证)。
只读诊断:`npm run probe:minimax`。详见 docs/minimax-cdp.md。
- **`codex-cli`**(可选,用户自建 profile,非内置):不想依赖 GUI 时的**无头**路径,走 `codex exec`。需用户先在数据目录 `agent-profiles.json` 加 `driver=spawn` 的 profile(示例见 README「macOS 无头路径:codex-cli」)。
`model` 参数对它**不生效**(模型取 `~/.codex/config.toml`,要锁模型在 `argsTemplate` 里加 `-m`);无 GUI 交互,`continue_task` 不适用。CLI 需 **≥0.154.0**(≤0.130.0 签名证书已吊销,macOS 会被 Gatekeeper 直接 SIGKILL)。
### 3.3 状态语义(`status` 字段)
| 取值 | 含义 | 能否派发 |
|---|---|---|
| `ready` | 该平台闭环已验证 | 可 |
| `research` | 已实现但真机矩阵未覆盖 | **可**(探测成功即可跑;失败会说明原因) |
| `unsupported` | 明确不支持 | 否 |
内置取值:`traework` 恒为 `ready`;`zcode` 恒为 `research`(Windows 闭环已通过,macOS 取消/返修/新建项目矩阵未齐);`codex` 在 Windows `ready`、darwin `research`;`kimicode` 在 Windows `ready`、darwin `research`;`qoder` 在 Windows `ready`、其他平台 `research`;`minimax` 在 Windows `ready`、darwin `research`;`opendesign` 在 Windows `ready`、darwin `research`。
**`ready` ≠ 全平台无限制**:TraeWork 与 Kimi Code 的 macOS 可执行探测与原生对话框驱动仍 fail-closed;qoder / minimax / opendesign 在非 Windows 直接拒绝派发。
不确定时问用户,或读项目 `projects.json` 的 `defaultAgentId`;用 `get_profiles` 看当前机器实际探测结果(含未安装提示与用户自定义 profile)。
### 3.4 ZCode 无项目模式(省略 `projectPath`)
只有 ZCode 支持。任务在其 `default` 工作区执行:**不**登记/导入项目、**不**采集 Git 基线、**不**执行项目验收。
- `autoVerify` 固定 `false`、`autoFixRounds` 固定 `0`;显式传 `autoVerify=true` 或 `autoFixRounds>0` 会在提交前报错。
- 任务书里**不要**写反引号路径或 `./`、`../` 引用——无项目模式无法解析,发送前即报错并要求提供 `projectPath`。
- 终态标注 `not_applicable: no_project`;对它调 `verify_task` / `get_task_report` 会得到 `not_applicable: no_project`,不会从 cwd 猜目录。
- 省略 `projectPath` 但解析出的 agent 不是 ZCode(例如默认 agent 是 codex)→ 排队前报参数错误,**不会**被悄悄改判成 ZCode。
- 空串 / `null` / 相对路径 / 不存在的目录**不视为**无项目模式,仍按有项目模式拒绝。
---
## 4. 派活:run_task
`projectPath`(绝对路径)+ `task`(任务书)是核心两件套;`task` 要写清**目标 / 验收要点 / 约束 / 相关文件 / 上下文**(模板见 usage-examples.md §1)。
- `context`:补充上下文,会以【上下文与约束】拼进初始指令。task/context 中**反引号包裹或路径形态的引用会在发送前校验**(必须存在且在项目内),写错立即报错而不是带病派单。
- `autoVerify` 默认开;`autoFixRounds` 0–10(见 §3.1 优先级)。
- 返回立即给 `taskId` 与队列位置,**不要等结果**。
### 4.1 projectPath 安全闸门(v0.4.0 起)
`run_task` / `verify_task` 提交时校验,不通过直接报错(属**基础设施拒绝**,改路径重试即可):
- 必须是绝对路径且**已存在**的目录;`realpath` 消除符号链接(macOS `/tmp` → `/private/tmp`),回执会明示解析来源。
- 拒绝**用户主目录本身**与根级/系统目录(`/`、`/etc`、`/usr`、`/var`、`/tmp`、`/Users`、`C:\`、`C:\Windows`、`C:\Users`、`C:\Program Files`、`D:\` 等,含 macOS `/private/*` realpath 形态)。**只挡精确相等的根**,子目录(`/tmp/xxx`、`D:\repo\app`)正常可用。
- 目标是 git 仓库且有未提交变更时,回执追加**共处警示**:该仓库同时有人的改动,agent 的 diff 与基线都会与之共处。
用户没给绝对路径时**先问**,不要猜路径。
---
## 5. needs_user:continue_task
meta 的 `needsUserKind` 给出等待类型,`pendingQuestion` 给出问题原文或处理说明。只有 `status=needs_user` 可恢复,其他状态一律拒绝。
| `needsUserKind` | 出现于 | 用户先做什么 | `continue_task` 的行为 |
|---|---|---|---|
| `agent_question` | zcode / kimicode / qoder / minimax | 无需操作(或在客户端补充信息) | **把 `message` 发表在原会话**(不重发任务书)。qoder 多题用 JSON 对象字符串,键为界面完整问题文字,多选值为字符串数组;先全量校验再提交,缺答案/题目变化/选项不存在都保留等待 |
| `user_confirmation` | codex / kimicode / qoder / opendesign / minimax | 在客户端窗口完成确认(方案卡/订阅页等) | **只重新接入观察**,不发送消息 |
| `login_required` | codex / zcode / kimicode / qoder / opendesign / minimax | 在窗口完成登录 | codex:复检环境后**重新派发任务书**(新会话 + 项目绑定 + 完整初始指令);kimicode/qoder:补发完整任务书;zcode:message 仅作已处理确认;opendesign:复检环境后补发完整任务书 |
| `close_existing_instance` | zcode / kimicode / qoder / opendesign / minimax | 关闭冲突的旧实例(MCP 不自动关停) | 复检环境后补发完整任务书(message 不作问题发送) |
| `system_permission` | zcode / kimicode / opendesign / minimax | 授予系统权限(辅助功能等) | 同上 |
| `setup_recovery` | zcode / kimicode / qoder / opendesign / minimax | 在客户端确认目标项目/工作区,或手工完成绑定 | 同上;无锚点的环境恢复会补发完整原任务、上下文与已验证引用 |
限制与纪律:
- **codex 只支持 `login_required` / `user_confirmation`**,其余等待类型会被明确拒绝;**traework 与 spawn 类 agent 完全不支持 `continue_task`**。
- `agent_question` 的恢复依赖服务端保存的**原会话锚点**(zcode `zcodeSessionId`/`zcodeSessionTitle`、kimicode 同名锚点、qoder `qoderSessionId`、minimax `minimaxSessionId`/`minimaxSessionTitle`)。锚点丢失时**明确拒绝**,绝不擅自打开“最近会话”。
- **禁止新开会话冒充恢复**;用户处理后的确认文本不会作为问题发给模型。
- 用户尚未处理就调 `continue_task`,任务会再次转 `needs_user`(如实反映 GUI 状态),稍后再试即可。
- qoder 的“发送/答题提交结果不确定”也会转 `needs_user(setup_recovery)`,此时**禁止自动重发**:请人工核对原会话,再决定继续或重派。
---
## 6. 终态解读
| 终态 | 含义 | 处置 |
|---|---|---|
| `succeeded` | 验收通过(或未开验收且 agent 正常退出) | `get_task_report(taskId, round?)` 取 changedFiles / diffstat / checks,向用户汇报 |
| `failed` | 未开自动返修时的失败,或**硬失败**(`errorType=spawn`) | 读 `agentEndReason`(§9)区分:硬失败按表中处置;真失败给**针对性** feedback 调 `rework_task` |
| `needs_attention` | ①自动返修轮次用尽仍失败;②验收**阻塞**(配置/完整性错误、缺基准、页面不可达等);③GUI 空闲/超时/断线(`errorType=agent_failed`/`timeout`) | 先读报告定位,再决定 `rework_task` 或转人工 |
| `cancelled` / `interrupted` | 取消 / 超时或中断 | 看 `abortSource`(`user`/`shutdown`/`timeout`/`internal`);GUI 任务另看 `guiStopUnconfirmed`(见下) |
关键区别:
- **视觉阻塞任务**调 `rework_task` 会**先只重新验收、不启动 agent、不消耗返修轮次**:通过即结束,仍阻塞则回到 `needs_attention`,只有出现真实缺陷才启动返修。
- **`needs_attention`(验收失败)** 的返修才真正回到 agent,`feedback` 会作为追加指示。
- **硬失败(`failed` + `errorType=spawn`)** 不是“agent 没做好”,重试前先按 §9 修环境。
- **`running` 卡死**才用 `cancel_task`:CLI agent 终止进程树;GUI agent 尽力点击界面停止并等待空闲(有界超时),取消文案会如实标注 GUI 侧是否已停。
**标注“未确认停止”时不要重派同项目任务**——窗口内可能仍在跑,重派护栏也会以 `instance_busy` 拒绝。
- **`needs_user` 状态下取消**:run 协程已退出、CDP 已断开,MCP 无法再点 GUI 停止按钮,文案会提示人工检查。
- **`interrupted` + `guiStopUnconfirmed=true`(server 退出 / 宿主 EOF / 重启归档)**:`tianshu-mcp` 对 GUI 进程没有所有权,**“编排器已停”不等于“窗口里的任务已停”**。先让用户人工打开对应窗口确认没有还在跑的 turn,再调 `cancel_task(taskId, reason="已人工核对窗口无残留运行")` 清除待确认标记(终态仍是 `interrupted`),**之后**才可安全重派同项目任务。详见 `usage-examples.md` §9.5.1。
- **幂等重放不是新任务**:`run_task` 命中同一 `idempotencyKey` 时返回的是**原任务**(含终态),响应文本以「幂等重放:」开头、meta 带 `idempotencyReplay: "hit"`;不要把它当成本次新派单,也不要据此认为又要等一轮。终态任务要继续推进用 `rework_task`,或换一条新 key 重新派单。
汇报纪律:**不要反复空转重试**。多次仍不过或不可修时,如实汇报 `errorType`/`agentEndReason`、失败 check 与输出尾部、变更清单,并给建议(人工看报告 / 换 agent / 缩小任务)。
---
## 7. 轮询与查询
- **首选 `wait_task`(issue #28)**:回合驱动调用方无法自行轮询——`run_task` 后在本回合内调 `wait_task(taskId)` **阻塞等到停点**(终态或 `needs_user`),不必等用户再发消息触发查询。超时(`timeoutMs` 缺省 50000、上限 600000)返回后**再次调用本工具继续等待**;等待纯只读、无害,被截断/中断对任务本体零影响。多任务并行等待用 `wait_any(taskIds)`。
- `query_task(taskId, tailLines?)` 间隔 **5–10 秒**;返回状态行 + 最近消息 + agent 日志尾(缺省 40 行)——要看进度细节时用它。
- 查历史用 `list_tasks(projectPath?, status?, limit?)`(缺省 50,上限 200);`projectPath` 与 `run_task` 同样做 realpath 归一。
- **同一项目勿重复派单**:每项目串行 + 全局并发(`concurrency.maxRunning`,默认 2);重复派只会排队,反而更慢。
- **重试必须带幂等键(issue #15)**:`tools/call` 超时、连接抖动、宿主重启后重发同一意图时,**复用同一条 `idempotencyKey`** 调 `run_task` / `verify_task`——`run_task` 会返回原 `taskId` 与原状态(不会排队第二轮 agent),`verify_task` 执行中返回「进行中」、已完成返回既有报告(不会重跑 `build`/`e2e`/部署类检查)。**换参数就得换 key**:同键异参会直接报冲突。未带 key 时若响应里出现 `projectActiveTask`,说明该工作区已有未结束任务——先 `query_task` 复核,不要盲目再派。
- 状态语义:`queued` 排队中(每项目串行)/ `running` 开发中 / `verify_start` 验收中 / `fixing` 返修中 / `needs_user` 等用户 / 终态见 §6。
---
## 8. 验收:理解与独立复验
### 8.1 验收报告解读
`get_task_report(taskId, round?)` 返回报告 Markdown 全文。**注意:报告类与视觉基准类工具的成功结果不带 meta 块**——`get_task_report` 返回报告原文,`prepare_visual_baseline` / `approve_visual_baseline` 返回视觉操作的 JSON 原文;其余工具结果末尾都带 `---tianshu-mcp-meta---` JSON 块(字段全表见 usage-examples.md §4),任何工具的**错误**结果也不带 meta 块。
- `checks[]`:每项 PASS / FAIL / SKIP + 输出尾部。默认**并行 2 条**(`verifyConcurrency`,1–4);checks 之间有顺序依赖(后续读 build 产物、带 `--fix`、共享缓存目录)时**必须显式设 1**,否则偶发误报。
- `analysis`:变更清单、diffstat、可疑标记命中(TODO/FIXME、`console.log`/`debugger`、疑似密钥形态、超大单文件改动告警)。这是**确定性规则,不是 LLM 评审**,命中只提示人工,不等同于任务失败。
- `visual`:启用视觉时的独立段落(§8.3)。
- `requireChanges` 门禁(默认开):相对动工前基线**零变更**判失败,防“什么都没做却报成功”。**纯只读/纯排查任务**必须在 `.tianshu-mcp/acceptance.json` 设 `"requireChanges": false`,否则必然失败。
- changedFiles/diffstat 相对**动工前 git 基线**(run_task 自动采集,含未跟踪新增)。MCP **不自动 commit/stash/回滚**。
### 8.2 独立复验:verify_task
只读、不改源码、无需审批。`taskId` / `projectPath` 二选一:
- 传 `taskId`:用该任务动工前基线复跑,只更新其验收结论字段(`latestVerificationVerdict`),**不改写原任务终态**。
- 传 `projectPath`:独立健康检查,不设 `baselineRef` 时按当前基线;`baselineRef` 可填 git ref(如 `HEAD~1`),传 `task` 表示沿用任务基线。**独立路径验收不产生独立任务,遇配置/视觉阻塞时记录为 `needs_attention`。**
- `extraChecks` 临时加验(`name`/`cmd`/`timeoutMs`/`optional`);`checksMode` 缺省 `append`(项目/默认集 + 追加),`replace` 才只跑 extraChecks。
- **`cmd` 用数组形态**:`"cmd": ["npm", "run", "typecheck"]`。字符串形态仅为兼容保留——只识别整段引号包裹、**不支持转义**,引号不闭合**不报错**而是静默按空白拆成多个 argv,含空格路径务必手写引号或改用数组。
- 命令优先级:`extraChecks` > 项目 `.tianshu-mcp/acceptance.json` > projects.json 管理员补录 > 按技术栈推导的默认集。
- 任务没有保存的动工前基线时会报错——改用 `projectPath` 或传 `baselineRef`。
### 8.3 视觉验收与基准保护
项目在 `.tianshu-mcp/acceptance.json` 配 `visual.enabled: true` 后,`run_task`/`verify_task` 自动带上截图对比与静态图片规格检查,**不需要新工具**。
- **缺陷**(布局差异、图片规格错误、可定位的交互失败)按 `autoFixRounds` 返修;**阻塞**(缺基准、页面不可达、浏览器缺失、资源被策略拦截、截图不稳定)进 `needs_attention`,**不触发 agent 返修**。
- **基准必须由用户审阅批准**:`prepare_visual_baseline` 只生成候选(返回 `candidateId`/`digest`/preview),`approve_visual_baseline` 只能在用户查看候选并明确授权后调用,且必须带 `expectedDigest` 与 `approvalNote`。**缺基准只能出候选、不能判通过。**
- **禁止绕过**:不得为通过而改基准、阈值、屏蔽区域或关闭规则——规则冻结会检出并报 `VISUAL_INTEGRITY`;要变更走 `tianshu-mcp visual rules review/approve` 重建任务快照(CLI 在 stdio 前分流)。
- **自动返修禁止调用批准入口**;两个基准工具都是有副作用的 `write`,宿主必须实施实际授权控制(审批标注不能替代)。
- 读报告 `visual` 段落与 `files.html` 离线报告(并排、透明叠加、区域定位);返修计划会给出检查 ID、路由/文件、视口、预期与实际指标、差异区域及证据路径。
- 阻塞处理流程:先在环境或审批上解决,再 `rework_task`(系统先重新验收,通过后不启动 agent)。
**AI 内容校验**(`visual.contents[]` 与 `pages[].content`,v0.5.4 起,可选、默认关闭):
- **凭证零管理**:判定完全委托用户自备的本地命令;MCP 不读取/存储/转发任何凭证,也不实现模型客户端。命令契约与占位符(`<image:path>` / `<expect:file>` / `<image:base64:file>`)见 `docs/visual-acceptance.md`。
- **默认仅告警**:内容项 `blocking:false` 映射为 `optional:true`,不改变结论、不触发返修。整轮消息会出现「AI 内容告警未通过(不影响结论)」,报告与返修计划另有「仅告警项(不必修复)」小节——**不要为消除告警伪造产物或放宽检查**。
- **只有 `blocking:true` 才致败**(`CONTENT_MISMATCH` 进返修计划「必须修复」)。
- **整轮阻塞**:任一规则的**有效**命令不可解析(`CONTENT_COMMAND_MISSING`)或宿主环境变量缺失(`CONTENT_ENV_MISSING`)会让整轮进 `needs_attention` 且**不产出任何视觉结果行**。这是 fail-closed,不是告警。
- **`uncertain` 不是失败**:票不集中或低于 `minConfidence` 时判 `uncertain`,永不阻塞、不触发返修;命令不报 confidence 时 `minConfidence` 不生效。
- 排查:`tianshu-mcp visual doctor <project>`、`visual content probe <project> [ruleId]`、`visual content cache clear <taskId>`。
- - **数据外发**:`allowRemote` 默认 `false`,未放行的规则禁止使用字节外传占位符;图片是否离开本机取决于用户命令的行为,MCP 无法在系统层拦截。
+ - **数据外发**:`allowRemote` 默认 `false`,**只**禁止受约束的内联字节通道 `<image:base64:file>`(未放行即 schema 拒绝);`<image:path>` / `<expect:file>` 是**不受约束**的路径通道(命令在项目内执行、本就能自读文件,门控无收益)。契约层不是对图片外发的完备拦截——图片是否离开本机取决于用户命令的行为,MCP 无法在系统层拦截。`visual doctor` 逐规则标出实际使用的通道与是否 `GATED`。
---
## 9. 硬失败与错误码速查
**硬失败**(`hardFailure`)不进验收、不进自动返修,落 `failed` + `errorType=spawn`。读到它先查环境,别当“agent 没做好”反复重试。
`agentEndReason` 与终态映射(先记住这张表,再看错误码表):
> **下面的错误码表是「常见子集」而非闭集**:`endReason` 在类型层面只是一个可选 `string`
> (`src/agents/adapter.ts:93`),没有枚举约束,某个适配器新增分支时无需改类型就能引入新取值。
> 因此看到表里没有的取值时,**按名字猜语义不如去读该适配器的 `run.ts`**,或看 `query_task` 的
> 日志尾部与 `progressSummary`。
| `agentEndReason` | 任务终态 |
|---|---|
| `task_timeout` | `needs_attention` + `errorType=timeout`(GUI:codex/zcode);qoder 落 `failed(timeout)` |
| `idle_timeout` / `cdp_disconnected` | `needs_attention` + `errorType=agent_failed`(codex/zcode) |
| 其余 `hardFailure` 原因 | `failed` + `errorType=spawn`(**基础设施失败**) |
| `agentEndReason` | 含义 | 处置 |
|---|---|---|
| `setup_failed` | 找不到安装 / 实例未就绪 / 点不到「新对话」 | 让用户确认已安装且能手动打开;重试一次 |
| `input_mismatch` | 任务输入框回读与本次标记不符(真机常见成因:输入框残留模板/草稿,任务被插进残文里) | 适配器已先清空再输入;若仍失败,让用户手动清空输入框后重派 |
| `send_unknown` | 点了发送但**无法确认消息落地**(minimax 用「消息落地 + 输入框清空/运行信号」双条件确认) | 适配器**绝不重发**(避免重复派活);请用户在界面确认是否已发出,再决定重派或 `continue_task` |
| `reply_stable` | **正常完成**:对话与产物均已静止 | 不是错误;去读验收报告 |
| `project_ambiguous` | 项目同名或路径重复,无法消歧 | 已转 `needs_user(setup_recovery)`:请用户确认目标项目后 `continue_task` |
| `project_mismatch` | 项目绑定或回读不一致,幂等重试仍失败 | 同上:请用户在 GUI 里确认/手工绑定 |
| `project_create_failed` | 在 GUI 内新建项目失败 | 让用户手动把项目加进 agent,或换 `projectPath` |
| `project_create_failed`(minimax 两阶段) | minimax 的「创建项目」是**两步**(应用内模态框 → 原生 `Select Directory` → 模态框提交),任一步失败落此码 | 让用户在 MiniMax Code 里手动建好项目再重派,或换 `projectPath` |
| `project_not_registered` | ZCode `allowCreateProject=false` 且目录未登记 | 在 ZCode 中手动登记该项目后重提 |
| `model_unavailable` | 面板里找不到指定模型(错误文本附可见候选);minimax 另含「该模型无档位/窗口子菜单却请求了这两项」 | 用面板实际模型名重派;minimax 若报「不支持设置」改用带子菜单的模型或去掉 `reasoningLevel`/`contextWindow` |
| `model_mismatch` | 模型回读与期望不符 / 档位或窗口不被该模型支持(minimax 报错会列出界面实际候选) | 确认 `model` 与界面完全一致;档位/窗口改到该模型界面实际存在的集合(minimax 各模型候选不同) |
| `selector_drift` | opendesign / minimax 关键选择器未命中或页面锚点漂移(在任何坐标点击前硬失败,附缺失键) | 确认产品版本;必要时用 `gui.selectors` 语义键热覆盖后重派 |
| `version_mismatch` | opendesign 安装版本不在 `opendesign.supportedVersions` 内 | 升级/降级产品,或更新 profile 的 `supportedVersions` |
| `design_system_mismatch` | opendesign 设计系统搜索/点选后回读不一致 | 核对 `designSystem` 传的名字与界面实际条目后重派 |
| `permission_unknown` | 权限模式未确认(如 ZCode 未开「完全访问」) | 让用户在 agent 内切好权限模式 |
| `cdp_disconnected` | CDP 连接断开且未能恢复 | 让用户关掉冲突实例;重试 |
| `instance_busy` | 同项目/同实例已有未停止的运行(重派护栏) | 先 `cancel_task` 并**确认 GUI 已停**,或等其自行结束 |
| `session_lost` | zcode/kimicode/qoder/minimax 找不到原会话锚点 | 用**新任务**重派,不要指望恢复原会话 |
| `input_mismatch` / `send_unknown` | 发送前回读不一致 / 发送结果无法确认(**绝不自动重发**) | 人工看窗口状态,必要时 `continue_task` 或重派 |
| `idle_timeout` | GUI 长时间静止且无完成标志(现场已保留) | 看窗口里 agent 是否真的卡住;必要时 `continue_task` 或取消 |
| `agent_error` | Kimi Code 界面出现失败文案/「继续」按钮(如官方额度用尽 `provider.auth_error`) | 读窗口内错误原文;额度/模型类可换非官方免费模型后重派 |
| `unsupported_platform` | Qoder 在非 Windows 平台派发 | 换平台或换 agent;qoder 的 macOS 状态是 `research` 且禁止派发 |
| `qoder_error` | Qoder 运行期错误,错误原文带具体码:`qoder_model_ambiguous`/`qoder_model_missing`/`qoder_model_readback_failed`、`qoder_reasoning_unsupported`、`qoder_workspace_mismatch`/`qoder_workspace_ambiguous`、`qoder_folder_dialog`、`qoder_input_readback_failed`、`qoder_question_*`、`qoder_session_lost`、`qoder_stage_timeout` | 按码处置:模型/档位类按界面实际值重派;工作区类让用户确认目录;提问类补齐答案或改用 JSON 对象;`*_timeout` 类看窗口是否被遮挡/未前台 |
| `task_timeout`(`errorType=timeout`) | 任务级超时 | 大任务调大 `taskTimeoutMs`;或拆小任务 |
| `aborted`(`errorType=cancelled`/`interrupted`) | 被取消 / 中断 | 按 §6 处理 |
`errorType` 取值:`timeout` / `spawn` / `agent_failed` / `verify_failed` / `cancelled` / `interrupted` / `agent_unresolved` / `internal`。
工具层面的**参数拒绝**(不是任务终态)也会直接报错,常见的有:`allowCreateProject` 非 ZCode、`mode` 非 traework、`modelSource` 非 qoder、`极高/最大/关闭思考` 非 qoder(minimax 例外,它接受)、`contextWindow` 非 minimax、Qoder 缺 `planDoc` 或计划文件不可读、无项目模式传 `autoVerify=true`。
**幂等键冲突(issue #15)**:`run_task` / `verify_task` 报「`idempotencyKey '<key>'` 已被任务/验收记录 `<id>` 占用,但本次参数与首次提交不同」时,说明你**复用了旧 key 却改了参数**(例如同一条 key 换了项目、任务书或 agent)。处置:改用一条**新的** key 重新调用,或直接对原记录 id 操作(`query_task` / `get_task_report` / `rework_task`)——**不要**通过改动参数绕过冲突后继续复用该 key。
---
## 10. 纪律
- 写/执行类工具(`run_task` / `cancel_task` / `rework_task` / `continue_task` / `prepare_visual_baseline` / `approve_visual_baseline`)**需审批**:不绕过、不替用户代点同意、不因等待而伪造结果。只读工具(`query_task` / `list_tasks` / `get_task_report` / `verify_task` / `get_profiles`)无需审批。
- **重试要带幂等键**:同一次逻辑派单/验收的每次重试都复用同一条 `idempotencyKey`;参数变了就换 key。不要把幂等重放的响应(`idempotencyReplay: "hit"` / `"in_progress"`)汇报成「已重新派单 / 已重新验收」。
- **不代替外部 agent 手改项目代码**;不改用户 git 历史;不读取/转发任何 agent 凭证(登录态各 agent 自持)。
- 验收命令来自白名单式配置、按 argv 分词执行(`shell: false`),不做 shell 注入。
- 报错与不确定性**如实转达**:区分「实际通过」「未验证」「阻塞」,不把未验证说成已验证。
- 本技能由 server 启动时幂等同步到 `~/.rivet/skills/tianshu-mcp/`(内容 hash 变化才覆盖,旧文件备份为 `.bak-<时间戳>`,**新会话生效**);改技能以本仓库 `skills/` 为准。
---
## 快速上手清单
1. `get_profiles` → 确认目标 agent `[PASS] 可用`(看 profileStatus 与探测来源);不可用就转达用户,别硬试。
2. `run_task(projectPath=<绝对路径>, task=<任务书>, agentId=codex, model=<面板模型名>, autoVerify=true, autoFixRounds=5, idempotencyKey=<本次逻辑派单的稳定标识>)` → 拿 `taskId`。**model 以界面实际为准**,示例名不可当真;`idempotencyKey` 建议由宿主按「本次意图」生成一次并在所有重试中复用(见 §7)。
3. `wait_task(taskId)` 阻塞等到停点(终态或 `needs_user`,超时后再调一次继续等);要看进度细节用 `query_task(taskId)` 每 ~8 秒轮询。`needs_user` 按 §5 处理,硬失败按 §9 定位。
4. 终态按 §6 处理;汇报带 `get_task_report` 的 changedFiles 与 diffstat;启用视觉时一并读 `visual` 段落与离线 HTML。