Files
obsidian-vault/output/研究文章/Trellis × 飞书实现闭环初步方案.md
2026-08-31 09:21:12 +08:00

46 KiB
Raw Permalink Blame History

Trellis × 飞书实现闭环初步方案

状态:V1 两个全局 skill 已实现并完成本地结构、契约 fixture 与独立前向验证;真实 Base POC 尚未运行
更新时间:2026-07-26
范围:只讨论“如何发现待实现工作、如何在 Inline / Trellis 之间路由、如何在完成后回写飞书”;不展开具体 coding 规则。
证据分层:文中明确区分「Trellis 官方文档事实」、「现有 Matt 文档提取」和「本文推导 / 推荐」。

版本注意:本机 trellis --version 已核对为 0.6.8,本次在线文档导航显示 0.6.9。两者在个别配置名称 / 默认值上可能有差异;真实项目 POC 必须以目标项目实际生成的 .trellis/ 文件、本地脚本和安装版本为准。

1. 结论先行

目前已确认把实现侧闭环定义为:

  1. 飞书 Base 管“待做什么、由谁做、依赖谁、当前业务状态”,是 Spec / Ticket 队列和对外状态的事实源。
  2. Trellis 管复杂工作的本地执行上下文:任务、PRD、技术设计、实施计划、检查上下文、归档和 journal。
  3. repo 管实现与验证事实:代码、测试、ADR、差异和可回放的验证结果。
  4. 普通小功能继续 Inline,不为了状态同步强行创建 Trellis 任务;复杂功能严格使用“1 Spec = 1 Trellis task”,Ticket 只作为该 task 内可刷新的实施计划和验收单元,不再映射为 Trellis child task。
  5. 已实现两个职责分离的全局显式 skill:
    • start-work-feishu:识别当前飞书用户,列出其负责的 Spec / Ticket,让用户选择,然后路由到 Inline 或 Trellis。
    • close-work-feishu:承担“部分收口、最终收口、对账重放”。它按 Spec 查找全部子 Tickets,分析可收口项并交给用户 review / 确认;只有被确认的 Tickets 或 Spec 才写入 已完成。
  6. Trellis 路径的 Spec 最终收口必须以归档事件为准,不能以 finish 事件为准。官方明确:after_finish 只表示当前 session 解除任务指针,任务可能仍在其他 session 继续;外部系统 done 应接 after_archive。Ticket 的部分收口可提前进行,但不得因此关闭 Spec。官方:架构全景
  7. 不把 lifecycle hook 当成唯一保障。官方规定 hook 失败只警告、不阻断主任务操作;因此必须由显式 close skill 完成飞书写入与回读。本方案中 hook 至多记录可重放的 pending / outbox 事件。官方:config.yaml 配置
  8. 所有完成态都以人类 review 为必要门禁。Agent 可以分析哪些 Ticket 已满足验收,但不能自行将它们或父 Spec 置为 已完成。

2. 本文如何区分事实与方案

标签 含义 能否当成已存在能力
[官方事实] 来自用户给出的 5 篇 Trellis 官方文档 可,但仍应以项目当前生成文件和安装版本为准
[Matt 提取] 来自已完成的《Matt 工作流 × 飞书 CLI 全流程总结》 可作为当前飞书 POC 和工作流合约
[推导 / 推荐] 基于上述事实对新闭环的设计 未标记实现时不能当成已有能力
[V1 已实现] 已写入全局 skill 并完成本地验证的合约 可用于 fixture;真实 Base 能力仍需目标项目 POC

本文不会把本方案的 skill、字段、任务元数据或 CLI 语法误写成 Trellis 内置能力。

3. Trellis 官方文档事实整理

3.1 定位与事实源

[官方事实] Trellis 将自己定位为“Team-level Agent Harness with built-in LLM wiki”:

  • Agent Harness 管 workflow state、hook、skill、sub-agent 和平台适配。
  • LLM wiki 把 spec、task、research、journal 放在仓库文件里。
  • workflow、spec、task 受 Git 跟踪;workspace memory 按 developer 隔离。
  • 它的核心思路是把 AI coding 当成“工作流 + 知识管理”,而不是一次性聊天。

来源:官方:架构全景

Trellis 本地内容的职责边界如下:

内容 位置 职责
Workflow 合约 .trellis/workflow.md Plan → Execute → Finish、skill 路由和每轮 next action
团队稳定规范 .trellis/spec/ 可跨任务复用的团队知识
任务事实 .trellis/tasks/<task>/ PRD、设计、实施计划、research、实现 / 检查 context manifest
开发者记忆 .trellis/workspace/<developer>/ 开发者 journal 和索引
当前任务指针 .trellis/.runtime/sessions/<session-key>.json 把一个 AI session / 窗口指向一个任务

来源:官方:架构全景

3.2 任务结构和上下文加载

[官方事实] 典型任务目录包含:

.trellis/tasks/<task>/
├── task.json
├── prd.md
├── design.md
├── implement.md
├── implement.jsonl
├── check.jsonl
└── research/
  • task.json 承载状态、优先级、负责人、分支、PR URL、父子关系和扩展元数据。
  • prd.md 承载需求、约束、验收标准和 out-of-scope。
  • 复杂任务使用 design.md 和 implement.md。
  • implement.jsonl / check.jsonl 分别列实现与检查所需的 spec / research 文件。
  • 实现 / 检查的标准读取顺序是“JSONL entries → prd.md → 可选 design.md → 可选 implement.md”。

来源:官方:架构全景

3.3 任务状态与生命周期

[官方事实] 默认状态是:

flowchart LR
    NoTask["no_task\n当前 session 无 active task"] -->|create| Planning["planning\n需求与规划"]
    Planning -->|start| Progress["in_progress\n实现、验收、收尾"]
    Progress -->|archive| Completed["completed\n归档前写入"]
    Progress -.->|finish| Detached["只清除当前 session 指针\n不等于任务完成"]
  • no_task 由 hook 在没有 active task 时合成。
  • 创建任务后是 planning,启动后是 in_progress。
  • completed 由 archive 在归档前写入,正常不会作为 live breadcrumb 长时存在。
  • active task 按 session 隔离;同一仓库的不同窗口可以做不同任务。

来源:官方:架构全景

[官方事实] 任务 lifecycle hook 是“命令事件”,不是通用 status watcher:

事件 确切含义 是否可作为外部 done 判定信号
after_create 任务目录已创建 否
after_start 任务进入 in_progress 可用于写“进行中”
after_finish 当前 AI session 已解除任务指针;任务可能在其他 session 继续 否
after_archive 任务已归档 是,官方指定的完成事件;但它不证明外部写入已成功

来源:官方:架构全景

3.4 Finish 边界

[官方事实] Trellis 把实现、工作 commit 和收尾记账分开:

  1. implement / check 产出通过检查的 diff。
  2. 主会话做最终验证并更新 spec。
  3. 工作 commit 先发生。
  4. /trellis:finish-work 如果发现当前任务改动未提交会停止,之后才归档任务并写 workspace journal。

/trellis:finish-work 不是提交功能代码的命令。

来源:官方:架构全景

本文之后所说的“finish-work 之后收口”,统一解释为:目标项目已按它的 workflow 完成最终验证,且对应 task 已真正 archive。它绝不等同于底层 task.py finish,后者只是 session detach。官方 native finish-work 与本地 Trellis × Matt 的 archive --no-commit 收尾也不同;实现 skill 不猜测用户输入的名称,而是回读 archived task 证明这个门禁。

3.5 Workflow 的可定制点和不可随意更改的边界

[官方事实] .trellis/workflow.md 集中定义:

  • Phase 和分步说明。
  • Skill Routing,即“用户意图 → auto-trigger skill”。
  • [workflow-state:STATUS] 每轮面包屑。
  • task.py 命令参考。

可添加自定义状态、新 Phase、Plan 分支或新 skill 路由,但有三类约定受脚本依赖:

  • [workflow-state:STATUS]...[/workflow-state:STATUS] 标签格式。
  • ## Phase X + #### X.Y 标题层级。
  • 真实 task.py 子命令名。只改 Markdown 不会改变 CLI。

面包屑文本下一条用户消息生效;Phase / step 正文和 skill routing 下一个 session 生效。

来源:官方:定制 Workflow

3.6 Skill 与 sub-agent 的选型

[官方事实] 三种扩展点的职责不同:

扩展点 适合的问题 本闭环中的判断
Command 用户显式决定进入的会话边界 可作为手动补偿入口,但本文不预设具体命令
Sub-agent 需要隔离 prompt / 角色约束的子进程 不是 Spec / Ticket 选择和飞书状态回写的必需条件
Skill 根据意图自动触发、能力或阶段级的可复用工作流 适合本闭环的主要扩展点

Skill 的 description 应该写“什么情况下触发”,正文应再做触发自检、列明动手前必读文件、给出固定输出格式。Codex 的项目级 skill 在 .codex/skills/{name}/SKILL.md,官方同时使用 .agents/skills/ 作为跨平台共享层。

来源:官方:定制 Skill

[官方事实] Trellis 原生提供 trellis-implement、trellis-check、trellis-research 三个 sub-agent。Codex 也可使用 inline 模式,由主会话通过 skill 读取同一批 task artifacts;自定义 sub-agent 若要拿到同类上下文,要约定 task-local JSONL 并遵守相同读取顺序。

来源:官方:定制 Sub-agent

3.7 config.yaml 和 lifecycle hook

[官方事实] .trellis/config.yaml 是应跟仓库提交的项目级共享配置,控制 session journal commit、任务 lifecycle hook、package 映射和 Codex 派发模式。

  • 不应把机器身份、token、API key 或机器绝对路径放进该文件。
  • 开发者身份放 .trellis/.developer;凭证放环境变量或常规密钥管理。
  • hooks 支持 after_create、after_start、after_finish、after_archive,命令会收到指向当前 task.json 的 TASK_JSON_PATH。
  • Hook 失败只打印警告,不会阻断任务操作。
  • 在当前在线配置文档中,codex.dispatch_mode 记为默认 inline,sub-agent 用于选择旧派发模式。但这一点存在明确的本地版本差异,见 3.8;本方案不应依赖该默认值。
  • session_auto_commit 默认为 true。若团队希望手动 review / commit Trellis 记账改动,可设为 false。

来源:官方:config.yaml 配置

3.8 在线文档与本机可执行事实的版本边界

[本机验证] 2026-07-26 实际执行:

trellis --version  -> 0.6.8
lark-cli --version -> 1.0.76

在线 Trellis 文档导航已显示 v0.6.9 changelog;本机 0.6.8 已安装模板中,codex.dispatch_mode 的默认值是 auto,inline 是显式退出 sub-agent 派发,sub-agent 只是 auto 的兼容别名。这与当前在线配置页的描述不一致。

因此:

  • 本文只依赖稳定的 task / artifact / lifecycle 语义,不把 dispatch_mode 当成飞书闭环的主集成点。
  • 真正实现时,以目标项目的 trellis --version、.trellis/config.yaml、已生成 agent / skill 文件和 python3 ./.trellis/scripts/task.py --help 为可执行事实源。
  • trellis update 后必须检查本地 workflow 覆盖和 .new / migration 差异,不直接假设在线文档与目标项目已同步。

4. 从现有 Matt 文档提取的“实现管理”

本节只提取实际开发时的管理思想,不扩展 implement / tdd / code-review 的编码规则。本节来源均为本地文档:《Matt 工作流 × 飞书 CLI 全流程总结》。

4.1 三类事实源不重叠

[Matt 提取]

系统 管理内容
Feishu Base 当前状态、类别、负责人、进度、时间、父子关系和阻塞关系
Feishu Wiki / Docs Spec、Triage Notes、Agent / Human Brief 等长文档
repo 代码、测试、ADR、领域上下文和被拒绝 enhancement 的决定

直接含义是:新闭环不应该在 Trellis 中复制一份“飞书当前业务状态”,也不应该把完整 Wiki Spec 长期复制为第二份权威文档。

4.2 Spec 和 Ticket 的管理含义

[Matt 提取]

  • Spec 是“问题、方案、验收边界”的聚合产物;完整内容在 Wiki,Base 保存可查询摘要和状态。
  • Ticket 是 tracer-bullet 垂直切片;每张 Ticket 是 Base 记录,V1 不建独立 Wiki,而是沿 所属父项 找到父 Spec 和完整文档。
  • Ticket 的 前置依赖 使用真实 Base record ID 建图。
  • 当一张 Ticket 所有 blocker 都已完成且它尚未认领时,它才是可执行 frontier。

因此,“当前用户的 Ticket”不能只做 负责人 = 当前用户 的扫描;列表还应该区分“可开始、可恢复、被阻塞”。

4.3 实现状态机和完成门禁

[Matt 提取] 主执行流包含:

ready-for-agent / ready-for-human
  → 进行中
  → 阻塞 ⇄ 进行中
  → 待评审 ⇄ 进行中
  → 已完成

关键一致性规则:

  • 状态=阻塞 时,阻塞原因 和 下一步 必须非空。
  • 设置 已完成 前必须有具体 验证证据;无法验证时要写“未运行”和原因,不能伪装完成。
  • 完成度、下一步、阻塞原因 需与状态一致。
  • Base create / update 后必须 record-get 或完整分页回读,ok:true 本身不是最终证据。

4.4 身份和责任分离

[Matt 提取]

  • API 执行者是 bot。
  • CLI 工作流真实发起人写入 最后更新人。
  • 负责人 是当前执行责任人,不因 bot 执行 API 而被覆盖。
  • 每次 Base create / update 都刷新 最后更新人。

这意味着“当前用户”应从已验证的 Feishu CLI 用户身份取得,不能将 macOS 用户名、Trellis .developer 文本或 bot 身份直接当成飞书 负责人。

4.5 当前已完成与未闭环的部分

[Matt 提取] 当前飞书硬依赖适配已覆盖 setup、Spec、Tickets 和 Triage;implement、tdd、code-review 等下游流程只是通过公共 issue-tracker 合约消费同一 Base。

所以当前真正的缺口不是“再建一套开发规范”,而是:

  1. 实现前如何从 Base 得到当前用户可执行的工作。
  2. 如何将选中的 Spec / Ticket 和 Inline 会话或 Trellis task 稳定关联。
  3. 实现结束后如何把实际验证证据、代码引用和终态回写 Base。
  4. 外部回写失败时如何可见、可重试,而不是把任务误报为已闭环。

4.6 本地 Trellis × Matt 覆盖层的实现管理原则

[Matt 提取] 本仓库现有 Trellis × Matt 工作流 已经把实际开发分成三种模式:

模式 管理含义
Inline 简单、局部、根因明确且一个上下文可完成;不创建 Trellis task
Matt without Trellis 不属于 Inline,但仍可单会话完成;用最匹配的工程方法,不为“看起来正式”创建 task
Trellis + Matt 跨会话、多项稳定决策、多交付物或 durable research;Trellis 管生命周期,Matt 管当前阶段方法

与本闭环直接相关的管理原则是:

  • 一个 lifecycle owner,一个 method owner:Trellis 管 task 状态与恢复;实现方法不再自建第二套任务状态。
  • prd.md、条件性的 design.md / implement.md 是 task-level 执行事实;跨会话任务用 Current Checkpoint 记录已完成、证据、下一步和 blocker。
  • 实现 agent 不修改 Trellis 状态、requirements 或 acceptance criteria,不执行 Git 写操作;主会话负责完整 diff、最终验收、checkpoint 和用户沟通。
  • 飞书的选择、外部写入确认和状态回读也应归主会话,不下放给 coding sub-agent。
  • 本地覆盖不使用旧的 commit-first trellis-finish-work,而是以 archive --no-commit + add_session.py --no-commit 记账;commit / push / PR 仍只由用户明确授权。

这里有一个必须在设计中显式消歧的术语冲突:

  • 你说的 Inline 开发 = 不创建 Trellis task。
  • Trellis 的 Codex dispatch_mode: inline = 已经处在 Trellis task 里,只是由主 Codex agent 直接实现。

两者不能共用一个判断条件。

5. 设计思考:五个关键问题及已确认解法

以下是可对外审查的设计推理,不是把内部思维过程当成事实。

5.1 Spec、Ticket 和 Trellis task 不是同一层概念

概念 回答的问题 推荐角色
Spec “为什么做、做到什么程度才算完成” 复杂开发的业务聚合根
Ticket “按什么可验证切片推进,哪些切片已解锁” 可刷新的实施计划 / 验收单元
Trellis task “本地这次复杂执行需要什么上下文和生命周期” 本地执行容器

[已确认] 严格使用 1 Spec = 1 Trellis task。Ticket 只作为该 task 的动态执行计划、frontier 和验收单元,不映射为 Trellis child task。这样只保留一个 task lifecycle,避免 Trellis 任务树和 Base Ticket 依赖图双轨漂移。

5.2 两套状态机必须指定单向事实源

[推荐] 不做“两边任意修改、互相最后写入覆盖”的双向同步。

事实 权威来源 另一侧如何使用
负责人、优先级、Spec/Ticket 关系、前置依赖 Feishu Base Trellis 启动 / 恢复时读取快照
Spec 长文档 Feishu Wiki Trellis task 保存链接和执行所需的摘要,不另建权威副本
当前 session 的 active task、本地 plan / check 上下文 Trellis 必要的节点摘要回写 Base
代码、测试、commit / PR 引用 repo Base 仅保存 代码引用 和 验证证据
对外工作状态 Feishu Base Trellis lifecycle 作为触发事件,不取代 Base

5.3 需要稳定的关联 ID,不能靠标题回猜

[推荐] 用 Feishu Base record_id 作为 Spec / Ticket 的稳定关联键。标题只用于展示和启动前查重,不用于收口时反向查找。

Trellis 官方架构文档说 task.json 支持“扩展元数据”。[本机验证] Trellis 0.6.8 的 task 初始结构实际包含 meta: {},archive 后 after_archive 收到的 TASK_JSON_PATH 指向已移入 archive 的 task.json。因此初步推荐用 task.json.meta.feishuTracker保存关联,但实现时仍要在目标项目回读 schema 并跑 archive POC。

候选合约(方案定义,非 Trellis 内置字段):

{
  "meta": {
    "feishuTracker": {
      "schemaVersion": 1,
      "specRecordId": "rec_xxx",
      "ticketRecordIds": ["rec_aaa", "rec_bbb"],
      "selectedRecordIds": ["rec_aaa"],
      "specWikiUrl": "https://...",
      "trackerContractPath": "docs/agents/issue-tracker.md",
      "boundAt": "2026-07-26T00:00:00+08:00",
      "lastRefreshAt": "2026-07-26T00:00:00+08:00"
    }
  }
}

不将 Base token、API token、密钥或固定个人 open ID 写入 task 元数据。Base / table 坐标继续由 repo tracker contract 提供;当次人类用户每次通过 lark-cli auth status --json --verify 重新验证。

关联基数保持为:

Trellis task
  ↔ 1 个 Feishu Spec record_id
  ↔ 0..N 个 Feishu Ticket record_id
  ↔ Spec Wiki URL

Inline 路径不为了保存 mapping 而初始化 Trellis。同会话收口时使用用户已选的 record IDs;若跨会话恢复,收口 skill 重新完整查询“负责人 = 当前用户 且 状态 = 进行中 / 待评审 / 阻塞”的记录,让用户按 record ID 重选,不用标题猜测。

5.4 “任务归档”只是 Spec 最终完成的必要条件,不是充分条件

[已确认] Ticket 可在 task 进行中通过部分收口逐张完成;after_archive 只解决“何时允许尝试 Spec 最终收口”。它不能单独证明每张 Ticket 均已验收。Spec 完成回写仍必须同时满足:

  • 对应验收标准已核对。
  • 真实验证命令 / 结果已采集;未运行项已明示。
  • 需要的 check 已通过,且人类已完成最终 review。
  • 要更新的每个 Ticket 都有对应证据,不因父 Spec 任务归档而批量猜测“全部完成”。

5.5 Inline 和 Trellis 应共用收口协议

[推荐] Inline 和 Trellis 的区别只是“是否需要持久的本地任务容器”,不应导致两套飞书状态规则。

flowchart TD
    Queue["当前用户的 Spec / Ticket 队列"] --> Select["用户选择工作项"]
    Select --> Route{"是否需要持久的复杂任务上下文?"}
    Route -->|"No"| Inline["Inline 实现"]
    Route -->|"Yes"| Task["1 Spec ↔ 1 Trellis task\nTickets 作为计划 / 验收单元"]
    Inline --> Verify["共用验证与 Base 回写协议"]
    Task --> Archive["Trellis 最终验证 + 归档"]
    Archive --> Verify
    Verify --> Readback["Base 回读 + 收口回执"]

6. 初步方案

6.1 总体架构

[推荐] 把新能力分成三层:

层 职责 不应负责的事
Skill 编排层 身份门禁、列表、用户选择、路由、收口规则、结果汇报 不把 API 返回的 ok:true 当最终证据
CLI 读写层 调用已验证的 lark-cli,查询 / patch / record-get 不负责决定应将哪张 Ticket 置为完成
Trellis lifecycle 集成层 提供 task 关联、start / archive 事件和归档上下文 不替代 Base 作为业务状态事实源

[本机验证] lark-cli 1.0.76 已提供 V1 所需的基础原语:

  • auth status --json --verify:验证 bot / user 身份。
  • base +record-list:结构化 filter、sort、字段投影、offset 和单页最大 limit=200;skill 必须自行循环到完整结果。
  • base +record-batch-update:单次最多 200 条的差异化 patch,响应不保证 record ID 存在。
  • base +record-get:按稳定 record ID 回读,所以 batch update 后仍需逐条或分批验证。

V1 可直接由 skill 编排这些 lark-cli 命令;先不为了包装而新建 CLI。只有当分页、frontier 计算、幂等 patch 在两个 skill 中形成重复且已经 POC 验证时,再提取 repo-local helper。

6.2 Skill A:工作入队与路由

[V1 已实现] 全局显式 skill 名为 start-work-feishu,source of truth 位于 ~/.agents/skills/start-work-feishu/;它不是 Trellis 内置命令。

触发条件:

  • 用户表示“开始开发、看我的待办、选一个 Spec / Ticket 实现”。
  • 当前无 active Trellis task,或用户明确要恢复已认领工作。

建议流程:

  1. 运行已验证的 Feishu 身份检查,冻结当前人类用户 open ID;不把 bot 当用户。
  2. 分别完整分页查询两类记录:
    • Spec 队列:产物类型 = PRD/Spec 且 Spec 自身 负责人 = 当前用户。不因“它的子 Ticket 由当前用户负责”而把该 Spec 追加到 Spec 队列。
    • Ticket 队列:产物类型 = 实现 Ticket 且 Ticket 自身 负责人 = 当前用户。展示时可附带父 Spec 上下文,但不改变 Spec 队列口径。
  3. 分组展示:
    • 恢复执行:进行中 / 阻塞。
    • 现在可开始:ready-for-agent 且 blocker 都已完成的 Ticket,以及符合条件的 Spec。
    • 尚未解锁:存在未完成 blocker 的 Ticket,只展示原因,不默认推荐开工。
  4. 每行至少展示:标题、产物类型、Base record ID、状态、优先级、父 Spec、阻塞项、更新时间和建议路由。
  5. 用户选择后,用 record ID 重新取得最新记录,防止列表与实际状态之间竞态。
  6. 如选 Ticket,沿 所属父项 取父 Spec 和 Wiki;如选 Spec,同时取子 Tickets 和依赖图。
  7. 根据既有约定路由:
    • 范围小、根因 / 方案已知、当前上下文可以完成:Inline。
    • 跨模块、需持久计划、多会话、多人 / 多 Agent 或验收链较长:Trellis task。
  8. 列表本身只读。用户选择后,skill 一次性展示“工作项 + Inline / Trellis 路由 + 拟写 Base patch”;用户确认“开始”后,同时构成任务路由决定和这一次外部写入授权,不再追加一个纯流程性的“是否创建 Trellis task”问题。
  9. 官方 native no_task breadcrumb 要求任务创建同意,但本地 Trellis × Matt workflow 明确覆盖为“满足 durable 条件时直接创建,不问 task-consent”。本方案用上一步的“选择并开始”统一两者,不改 Trellis CLI 语义。
  10. 当 record ID 关联已成功保存且用户确认开始时,将选中的聚合工作项更新为 进行中。选 Spec 时先只写 Spec,其他 Tickets 保持原状态;选 Ticket 时写该 Ticket,并将其父 Spec 写为 进行中(如尚未进入),其他 Tickets 不动。这里的语义是“已认领并开始规划 / 执行”,不声称代码已写。
  11. 每次写入都带 最后更新人 = 当前人类用户,并立即回读核对。

建议列表形式:

序号 可执行性 类型 标题 状态 优先级 父 Spec 阻塞 建议路由
1 可恢复 Spec … 进行中 P1 — — Trellis
2 可开始 Ticket … ready-for-agent P2 Spec A 无 Inline
3 被阻塞 Ticket … ready-for-agent P2 Spec B Ticket X 暂不开工

6.3 复杂开发的映射规则

[推荐]

Feishu Spec record_id
  ↔ Trellis task
      ├── prd.md:Spec 链接、必要摘要、验收边界
      ├── implement.md:按 Ticket frontier 生成 / 刷新的执行计划
      ├── implement.jsonl / check.jsonl:只收录必要的本地 spec / research
      └── task.json.meta.feishuTracker:Spec record_id + Ticket record_ids

约束:

  • 同一 Spec 同时最多对应一个 active Trellis task。创建前先扫描 active task 的 meta.feishuTracker.specRecordId;已存在时恢复原 task,不按标题再建一个。
  • Feishu Wiki Spec 仍是长规格事实源;Trellis prd.md 是本地执行上下文,应显式记录来源 record ID / URL 和取得时间。
  • Ticket 状态和依赖仍以 Base 为准;implement.md 是可执行快照,恢复开发时先检查 Base 是否已变化。
  • 每次恢复 Trellis task 时,按 specRecordId 重取 Spec、子 Tickets、依赖与 更新时间,与 lastRefreshAt 快照比较。新增 Ticket 可追加为新计划项;验收、范围或依赖发生实质变化时,先向用户展示 diff,不静默改写已 review 的 task artifacts。
  • implement.md 保存本地 checkpoint,Base Ticket 保存对外状态。二者的重合内容是可重建快照,不形成双向最后写入覆盖。
  • Ticket 不映射成 Trellis child task;所有 Tickets 都通过同一 Spec task 的 implement.md / checkpoint 管理。
  • 不把完整业务文档塞进 JSONL;Trellis 官方建议 JSONL 只列当前任务需要的 spec / research。官方:架构全景

6.4 Skill B:验证与飞书收口

[V1 已实现] 全局显式 skill 名为 close-work-feishu,source of truth 位于 ~/.agents/skills/close-work-feishu/;它不是 Trellis 内置命令。

这个 skill 支持三个 routing,而不是只能在整个 Spec 完成后运行:

Routing 何时调用 允许写入的终态
部分收口 Inline 或 Trellis task 还在进行中,用户希望先结算已完成切片 只能关闭经人类 review 确认的 Tickets;Spec 继续保持 进行中
最终收口 全部 Ticket 已结算,Spec 验收已完成;Trellis 路径的 task 还必须已 archive 先确认漏网 Tickets,最后才允许关闭 Spec
对账重放 上次写入部分成功、回读失败或记录已处于目标终态 只补齐仍有差异的记录;证据完整时返回“已同步”,不重复追加

Inline 不等待 Trellis 事件。Trellis 的部分收口可在 active task 期间运行;最终收口才要求 archive。after_archive 仍只负责提醒或标记“待对账”,不直接代表 Base 已写回。

共享步骤:

  1. 先确定唯一父 Spec。Trellis 从 active / archived task 的 meta.feishuTracker.specRecordId 取得;Inline 从当会话选择或一次用户重选取得。不用标题反查。
  2. 按 Spec 回读所有未完成 Tickets,不只分析当前 mapping 快照中的 Ticket IDs。同时重取验收标准、负责人、状态、前置依赖和更新时间,避免漏掉开发中新增或变更的 Tickets。
  3. 汇总 repo diff、真实验证命令与结果、未运行项及原因、review 证据、代码引用和 Trellis checkpoint,并逐张映射 Ticket 验收标准。
  4. 对未完成 Tickets 分类:
    • 建议可收口:验收条件和直接证据充分,可交给人类 review。
    • 待补证 / 待验证:实现看似已有,但证据或验收映射不足,不建议完成。
    • 明确未完成 / 阻塞:仍有实现项、未满足 blocker 或需要新决策。
  5. 向用户展示逐 Ticket 分析:标题、record ID、验收结论、证据、风险、建议动作和拟写 patch。Agent 只推荐,不自行选择终态。
  6. 人类 review 是每张 Ticket 写入 已完成 的必要条件。用户可确认全部建议项,也可只选其中一部分;未被确认的 Ticket 不写终态。
  7. 对用户确认的 Tickets 构造最小 patch,写入状态、完成度、Ticket 专属的验证证据、代码引用和 最后更新人,清理终态不应保留的阻塞字段。不覆盖无关新写入。
  8. 先更新 Tickets 并逐条回读。部分收口在此结束:父 Spec 保持 进行中,未完成 Tickets 保持原状态,回执中列出最小下一步。
  9. 最终收口在 Ticket 回读后重新查询全部子 Tickets。只有当全部 Tickets 已完成、Spec 级验收充分、Trellis task 已 archive(若适用)且人类完成最终 review,才展示 Spec 终态 patch 并再取得一次确认。
  10. 更新 Spec 后回读,最终输出收口回执:已更新记录、未收口记录及原因、失败记录、人类 review 结论和回读证据。
flowchart TD
    Invoke["用户执行收口 skill"] --> Spec["定位 Spec record ID"]
    Spec --> Fetch["取全部未完成 Tickets"]
    Fetch --> Analyze["逐 Ticket 分析验收与证据"]
    Analyze --> Review["人类 review 并选择可收口 Tickets"]
    Review --> CloseTickets["更新 Tickets + 逐条回读"]
    CloseTickets --> Remaining{"仍有未完成 Ticket?"}
    Remaining -->|"Yes"| Partial["部分收口完成\nSpec 保持进行中"]
    Remaining -->|"No"| FinalGate{"Spec 验收 + 人类最终 review\n+ Trellis archive 如适用?"}
    FinalGate -->|"No"| Wait["保持 Spec 进行中 / 待评审"]
    FinalGate -->|"Yes"| CloseSpec["用户确认 Spec patch"]
    CloseSpec --> Done["更新 Spec + 回读"]

推荐的完成 patch 语义,不是未验证的 CLI 命令:

字段 目标值 / 规则
工作流阶段 已完成实现和验收后进入交付,或按团队最终确定的阶段映射
状态 已完成
完成度 100
验证证据 真实命令 + 结果摘要 + 未运行项
代码引用 任务路径、分支、commit、PR 或关键文件,只写真实存在的引用
阻塞原因 清空
下一步 清空,或按团队终态规则写明后续交付动作
最后更新人 当前已验证 CLI 人类用户

6.5 Trellis 与 Base 状态映射

[推荐]

Trellis / 本地事件 Base 候选状态 备注
已列表、用户未选择 不写 只读查询不应该改状态
用户确认“选择并开始”,mapping 保存成功 进行中 表示已认领并进入 planning / execution;不猜测完成度
Trellis planning / after_start 通常不再重复写 由入队 skill 完成开始回写;hook 可做对账,不必二次 patch
外部 blocker 出现 阻塞 阻塞原因 + 下一步 必填
Agent 分析 Ticket “建议可收口”,尚未人类 review 保持原状态,或经确认写 待评审 绝不自动写 已完成
部分收口:人类 review 并确认部分 Tickets 被选 Tickets → 已完成 其他 Tickets 不动,Spec 保持 进行中
after_finish 不写 只是 session detach
after_archive 不直接写 done 只生成收口提醒 / 待对账信号
全部 Tickets 完成 + Spec 验收 + 人类最终 review + archive(如适用) Spec → 已完成 最终收口的聚合门禁;任一条不满足都不关 Spec
同步失败 保留原状态 本地报告“代码 / Trellis 已完成,Base 待对账”,不伪报闭环

该映射要在 POC 后才能固化进 skill;特别是 工作流阶段 和 Spec 聚合完成语义,需再确认业务预期。

6.6 Hook 怎么用:事件触发,不是唯一保障

[推荐] 分三阶段导入:

V1:skill 显式闭环

  • 由工作入队 skill 负责选择、路由和开始状态回写。
  • Inline / Trellis 进行中都可显式执行收口 skill 的“部分收口”routing,只关闭经人类 review 确认的 Tickets。
  • Inline 整体验收完成,或 Trellis 最终验证和归档后,显式执行“最终收口”routing,才可能关闭 Spec。
  • 先证明字段映射、回读和幂等性,不先扩大到全自动 hook。

V1.5:Workflow routing 固化入口

  • 在 .trellis/workflow.md 的 Skill Routing 中加入“开始飞书工作”与“实现完成后闭环飞书”的意图路由。
  • 在 Finish 阶段明确“archive 成功后运行飞书收口 / 对账”。
  • 保持 Trellis 解析器依赖的 block 标签、Phase / step 标题层级和真实命令名不变。官方:定制 Workflow

V2:lifecycle hook + 可重放对账

  • after_start 可选用于检查绑定工作项是否已是 进行中,不与入队 skill 重复 patch。
  • after_archive 只输出明确提醒,或写一个不含凭证的本地待对账标记;后续仍由用户显式运行收口 skill。
  • after_finish 不更新 Base 完成态。
  • Hook 里不放 Base token、user open ID 或机器绝对路径;.trellis/config.yaml 只保存团队共享的相对命令。官方:config.yaml 配置
  • 收口 skill 扫描已 archive 任务的 meta.feishuTracker,并回读 Base 判断是否待同步;不需要依赖 hook 的“成功标记”。
  • 由于 hook 失败不阻断 archive,同一收口核心必须支持手动重放 / 对账;skill 作为唯一声称“Base 已闭环”的入口。

6.7 幂等、竞态和失败处理

[推荐] 收口设计必须包含:

  1. 稳定键:只按 record ID 更新。
  2. 写前回读:责任人、状态或父子关系已变更时停止并报告,不强制覆盖。
  3. 最小 patch:只写当前状态转移需要的字段。
  4. 幂等重放:目标已是相同终态且证据一致时,结果为“已同步”,不再创建新记录或重复附加证据。
  5. 部分成功可见:返回逐条成功 / 失败列表,不用一个总体 ok 遮蔽部分失败。
  6. 回读才是成功:只有回读字段符合预期才报告“Base 已闭环”。
  7. 外部失败不篡改本地事实:代码 / Trellis 已完成与 Base 同步失败必须分开汇报。

6.8 为什么暂不需要新 sub-agent

[推荐] Spec / Ticket 选择、外部写入确认和收口回执都依赖当前主会话,并不需要隔离的编码角色。Trellis 支持由主会话通过 skill 读取任务上下文,而本地 Trellis × Matt 覆盖已把 lifecycle、最终验收和用户沟通明确交给主会话。官方:定制 Sub-agent

可以继续使用 Trellis 原生 implement / check / research 角色处理各自的执行职责,但不应该让它们各自直接决定 Base 终态。

7. 建议的端到端时序

7.1 Inline 路径

sequenceDiagram
    participant U as 用户
    participant S as 工作入队 skill
    participant F as Feishu Base / Wiki
    participant C as Coding Agent
    participant X as 工作收口 skill

    U->>S: 显示我的可实现工作
    S->>F: 验证身份 + 完整查询
    F-->>S: Spec / Ticket + 关系 + 状态
    S-->>U: 可恢复 / 可开始 / 被阻塞列表
    U->>S: 选择工作项
    S-->>U: 展示 Inline 路由 + Base 开始 patch
    U->>S: 确认选择并开始
    S->>F: 重读后写进行中,再回读
    S->>C: record IDs + Spec + Tickets + 验收边界
    C->>C: Inline 实现与验证
    C->>X: 完成证据 + 代码引用
    X-->>U: 展示逐 Ticket / Spec patch
    U->>X: 确认外部写入
    X->>F: 按 record ID 最小 patch
    X->>F: 逐条回读
    X-->>U: 收口回执

7.2 Trellis 路径

sequenceDiagram
    participant U as 用户
    participant S as 工作入队 skill
    participant F as Feishu Base / Wiki
    participant T as Trellis
    participant X as 工作收口 / 对账

    U->>S: 选择复杂 Spec / Ticket
    S->>F: 取最新 Spec、Tickets、依赖
    S-->>U: 展示 1 Spec ↔ 1 task 路由 + Base 开始 patch
    U->>S: 确认选择并开始
    S->>T: 建立 task 与 Base record IDs 的稳定关联
    S->>F: 写进行中 + 最后更新人,再回读
    T->>T: planning
    T->>T: start → in_progress
    T->>T: implement → check → update-spec → 最终验证
    U->>T: 按目标项目合约执行 finish-work / archive
    T->>T: archive + journal
    T-->>X: after_archive 提醒 + archived TASK_JSON_PATH
    U->>X: 显式运行收口 skill
    X-->>U: 展示逐 Ticket / Spec patch
    U->>X: 确认外部写入
    X->>F: 按逐 Ticket 证据幂等收口,Spec 最后写
    X->>F: 回读
    X-->>U: 收口成功,或 Base 待对账

图中 after_archive 和 TASK_JSON_PATH 是 Trellis 官方已有事实;它们只触发提醒,不绕过用户确认直接写飞书。具体收口 skill 和 Feishu CLI payload 是本方案待实现部分。官方:架构全景 官方:config.yaml 配置

8. 建议的最小 POC

本文推荐先不改完整 Trellis workflow,用一个真实但可回收的 Spec + 两张 Ticket 验证下列最小闭环:

  1. 当前 Feishu CLI 人类用户可被准确解析。
  2. 能完整列出“Spec 自身负责人 = 当前用户”的 Spec,不因子 Ticket 归属扩张 Spec 列表;同时独立列出当前用户负责的 Tickets,并正确计算依赖 frontier。
  3. 用户选定后,Trellis 路径能把 Spec / Ticket record IDs 保存到 task.json.meta.feishuTracker,且 archive 后仍可读取。
  4. 同一个候选工作能分别跑通 Inline 和 Trellis 两条路径。
  5. Trellis 的 after_finish 不触发 done;after_archive 只触发收口提醒,显式 skill 才尝试写 done。
  6. 在 task 未 archive 时执行部分收口,skill 能按 Spec 取得全部未完成 Tickets,给出“建议可收口 / 待补证 / 未完成”分析,并只关闭用户 review 后确认的 Tickets。
  7. 部分收口后 Spec 仍为 进行中;未被用户确认的 Tickets 不被误关闭。
  8. 最终收口只在全部 Tickets 完成、Spec 验收通过、人类最终 review 通过且 Trellis task 已 archive(如适用)时关闭 Spec。
  9. 重复执行部分 / 最终收口不会创建重复记录、重复证据或错误状态。
  10. 刻意让一次 hook 失败,archive 仍成功,收口 skill 仍能通过 archive task mapping + Base 回读发现待同步工作。
  11. 刻意让一次 Base batch update 部分失败,skill 能保留逐条成功 / 失败证据并幂等重放,不误关父 Spec。
  12. 所有 Base 更新都显示 最后更新人 = 当前真实用户,且已逐条回读。
  13. POC 验收后将测试记录标记为 已取代,保留审计证据,不删除。

POC 前先仅定义读取和预演模式,展示将修改的 record IDs 和字段;真实写飞书应在用户确认后进行。

9. 导入顺序建议

阶段 A:只读队列

  • 实现身份验证、完整分页、负责人过滤、状态分组和 frontier 计算。
  • 不改 Base、不建 Trellis task。
  • 验收:列表与 Base UI 人工核对一致。

阶段 B:选择与开始同步

  • 用户选择后重读 record。
  • 实现 Inline / Trellis 路由和稳定 ID 绑定。
  • 用户一次确认“选择并开始”后,写 进行中并回读;Trellis after_start 只做可选对账。

阶段 C:显式收口

  • Inline 和 Trellis 共用一个收口核心。
  • 先做“部分收口”:按 Spec 分析所有未完成 Tickets,人类 review 后选择收口集合。
  • 再做“最终收口”:验证全 Ticket 完成、Spec 聚合验收、人类最终 review 和幂等重放。

阶段 D:Workflow 与 hook 集成

  • 把 skill 意图写入 .trellis/workflow.md Skill Routing。
  • 再接 after_start / after_archive 的对账 / 提醒能力,不在 hook 中无确认写飞书。
  • 保留手动对账入口,并演练 hook 失败。

10. 已确认的设计决策

# 已确认决策 对实现的直接约束
1 使用两个 skill:入队 skill + 收口 skill 对账重放是收口 skill 的 routing,不新增第三个 skill
2 严格 1 Spec = 1 Trellis task Ticket 不建 Trellis task / child task,只作为同一 task 内的动态计划和验收单元
3 用户确认“选择并开始”且 mapping 保存后,立即写 进行中 不新增“规划中”状态;after_start 不重复 patch
4 必须人类 review 才能完成 Agent check、测试通过和 archive 都只是证据,不能单独产生 Ticket / Spec 终态
5 收口 skill 支持部分收口 每次按 Spec 重取所有未完成 Tickets,分析可收口集合,用户 review / 选择后只关闭被确认 Tickets;Spec 保持进行中,直到最终聚合门禁通过
6 采用本文推荐的 mapping 使用 task.json.meta.feishuTracker,不写 token、密钥或固定个人 open ID
7 Hook 按本文推荐边界 after_archive 只提醒 / 待对账,不直接写 Feishu;显式收口 skill 才能声称 Base 闭环
8 Spec 队列只列 Spec 自身负责人 = 当前用户 不因子 Ticket 归属扩张 Spec 队列;当前用户负责的 Tickets 仍作为独立 Ticket 队列展示

11. 风险与非目标

当前风险

  • 状态双写风险:若 Base 和 Trellis 都被当成业务状态权威源,会出现覆盖与逆向跳转。
  • 误用 after_finish:会在其他 session 仍工作时提前完成 Base。
  • hook 假成功:archive 成功不代表 hook 成功,必须有重放 / 对账。
  • Spec 批量误关闭:父 task 归档不能无证据地把所有 Ticket 置为已完成。
  • 用标题做关联:改名、重名和模糊查询会导致更新错记录。
  • 身份混淆:bot、负责人、最后更新人 和 Trellis developer 是不同概念。
  • 敏感信息进仓:不能把 token / API key / 个人 open ID 硬编码进 .trellis/config.yaml。

非目标

  • 本文不设计新的 coding / TDD / review 规则。
  • V1 已实现两个显式 skill,但不实现 hook、CLI wrapper、helper script 或 Trellis workflow 定制。
  • 本文不修改飞书 Base schema 或真实业务记录。
  • 本文不把本地结构 / fixture 验证等同于真实 Base POC。

12. 资料索引

Trellis 官方一手资料

  1. 架构全景
  2. 定制 Workflow
  3. 定制 Skill
  4. 定制 Sub-agent
  5. 配置 .trellis/config.yaml

本地已验证资料

13. V1 实现状态与下一步

13.1 已实现

  • ~/.agents/skills/start-work-feishu/:SKILL.md、references/feishu.md、agents/openai.yaml。
  • ~/.agents/skills/close-work-feishu/:SKILL.md、references/feishu.md、agents/openai.yaml。
  • 两个 skill 均设置 policy.allow_implicit_invocation: false,只允许用户显式调用。
  • V1 直接编排项目内 Trellis 脚本与 lark-cli,没有新增 helper、hook、workflow 修改或 Base schema 写入。

13.2 已完成的本地验证

  • 两个目录均通过 skill-creator/scripts/quick_validate.py。
  • agents/openai.yaml 已解析并确认显式调用策略及 $skill-name 默认提示。
  • 暂存目录与全局安装目录逐字节一致,无 TODO / 模板占位残留。
  • 契约 fixture 覆盖 11 类场景:负责人过滤、父 Spec 上下文、完整 frontier、非完成终态、待评审分流、重复 task mapping、部分收口、缺失证据、finish 非 archive、Spec 最终门禁和幂等回读规则。
  • 独立前向测试只使用脱敏 fixture,未调用 lark-cli、未写 Base;验证结果见本次实施回执。

13.3 尚未运行与后续顺序

当前机器没有发现任何项目级 docs/agents/issue-tracker.md,因此不能安全定位真实 Base,真实只读 POC 标记为 未运行。后续按以下顺序继续:

  1. 用户指定一个已配置飞书 tracker contract 的 Trellis 项目。
  2. 运行 start-work-feishu 只读队列 POC,与 Base UI 人工核对负责人、分页和 frontier。
  3. 单独展示 record IDs 与开始 patch,经确认后验证 mapping、进行中 写入和回读。
  4. 依次验证部分收口、最终收口和对账重放;每批真实写入仍单独确认。
  5. V1 真实 POC 稳定后,再讨论是否抽取 helper,以及是否进入 workflow / hook 提醒集成。