46 KiB
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. 结论先行
目前已确认把实现侧闭环定义为:
- 飞书 Base 管“待做什么、由谁做、依赖谁、当前业务状态”,是 Spec / Ticket 队列和对外状态的事实源。
- Trellis 管复杂工作的本地执行上下文:任务、PRD、技术设计、实施计划、检查上下文、归档和 journal。
- repo 管实现与验证事实:代码、测试、ADR、差异和可回放的验证结果。
- 普通小功能继续 Inline,不为了状态同步强行创建 Trellis 任务;复杂功能严格使用“1 Spec = 1 Trellis task”,Ticket 只作为该 task 内可刷新的实施计划和验收单元,不再映射为 Trellis child task。
- 已实现两个职责分离的全局显式 skill:
start-work-feishu:识别当前飞书用户,列出其负责的 Spec / Ticket,让用户选择,然后路由到 Inline 或 Trellis。close-work-feishu:承担“部分收口、最终收口、对账重放”。它按 Spec 查找全部子 Tickets,分析可收口项并交给用户 review / 确认;只有被确认的 Tickets 或 Spec 才写入已完成。
- Trellis 路径的 Spec 最终收口必须以归档事件为准,不能以
finish事件为准。官方明确:after_finish只表示当前 session 解除任务指针,任务可能仍在其他 session 继续;外部系统 done 应接after_archive。Ticket 的部分收口可提前进行,但不得因此关闭 Spec。官方:架构全景 - 不把 lifecycle hook 当成唯一保障。官方规定 hook 失败只警告、不阻断主任务操作;因此必须由显式 close skill 完成飞书写入与回读。本方案中 hook 至多记录可重放的 pending / outbox 事件。官方:
config.yaml配置 - 所有完成态都以人类 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 和收尾记账分开:
- implement / check 产出通过检查的 diff。
- 主会话做最终验证并更新 spec。
- 工作 commit 先发生。
/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 生效。
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 并遵守相同读取顺序。
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。
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。
所以当前真正的缺口不是“再建一套开发规范”,而是:
- 实现前如何从 Base 得到当前用户可执行的工作。
- 如何将选中的 Spec / Ticket 和 Inline 会话或 Trellis task 稳定关联。
- 实现结束后如何把实际验证证据、代码引用和终态回写 Base。
- 外部回写失败时如何可见、可重试,而不是把任务误报为已闭环。
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,或用户明确要恢复已认领工作。
建议流程:
- 运行已验证的 Feishu 身份检查,冻结当前人类用户 open ID;不把 bot 当用户。
- 分别完整分页查询两类记录:
- Spec 队列:
产物类型 = PRD/Spec且 Spec 自身负责人 = 当前用户。不因“它的子 Ticket 由当前用户负责”而把该 Spec 追加到 Spec 队列。 - Ticket 队列:
产物类型 = 实现 Ticket且 Ticket 自身负责人 = 当前用户。展示时可附带父 Spec 上下文,但不改变 Spec 队列口径。
- Spec 队列:
- 分组展示:
- 恢复执行:
进行中/阻塞。 - 现在可开始:
ready-for-agent且 blocker 都已完成的 Ticket,以及符合条件的 Spec。 - 尚未解锁:存在未完成 blocker 的 Ticket,只展示原因,不默认推荐开工。
- 恢复执行:
- 每行至少展示:标题、产物类型、Base record ID、状态、优先级、父 Spec、阻塞项、更新时间和建议路由。
- 用户选择后,用 record ID 重新取得最新记录,防止列表与实际状态之间竞态。
- 如选 Ticket,沿
所属父项取父 Spec 和 Wiki;如选 Spec,同时取子 Tickets 和依赖图。 - 根据既有约定路由:
- 范围小、根因 / 方案已知、当前上下文可以完成:Inline。
- 跨模块、需持久计划、多会话、多人 / 多 Agent 或验收链较长:Trellis task。
- 列表本身只读。用户选择后,skill 一次性展示“工作项 + Inline / Trellis 路由 + 拟写 Base patch”;用户确认“开始”后,同时构成任务路由决定和这一次外部写入授权,不再追加一个纯流程性的“是否创建 Trellis task”问题。
- 官方 native
no_taskbreadcrumb 要求任务创建同意,但本地 Trellis × Matt workflow 明确覆盖为“满足 durable 条件时直接创建,不问 task-consent”。本方案用上一步的“选择并开始”统一两者,不改 Trellis CLI 语义。 - 当 record ID 关联已成功保存且用户确认开始时,将选中的聚合工作项更新为
进行中。选 Spec 时先只写 Spec,其他 Tickets 保持原状态;选 Ticket 时写该 Ticket,并将其父 Spec 写为进行中(如尚未进入),其他 Tickets 不动。这里的语义是“已认领并开始规划 / 执行”,不声称代码已写。 - 每次写入都带
最后更新人 = 当前人类用户,并立即回读核对。
建议列表形式:
| 序号 | 可执行性 | 类型 | 标题 | 状态 | 优先级 | 父 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 已写回。
共享步骤:
- 先确定唯一父 Spec。Trellis 从 active / archived task 的
meta.feishuTracker.specRecordId取得;Inline 从当会话选择或一次用户重选取得。不用标题反查。 - 按 Spec 回读所有未完成 Tickets,不只分析当前 mapping 快照中的 Ticket IDs。同时重取验收标准、负责人、状态、前置依赖和更新时间,避免漏掉开发中新增或变更的 Tickets。
- 汇总 repo diff、真实验证命令与结果、未运行项及原因、review 证据、代码引用和 Trellis checkpoint,并逐张映射 Ticket 验收标准。
- 对未完成 Tickets 分类:
- 建议可收口:验收条件和直接证据充分,可交给人类 review。
- 待补证 / 待验证:实现看似已有,但证据或验收映射不足,不建议完成。
- 明确未完成 / 阻塞:仍有实现项、未满足 blocker 或需要新决策。
- 向用户展示逐 Ticket 分析:标题、record ID、验收结论、证据、风险、建议动作和拟写 patch。Agent 只推荐,不自行选择终态。
- 人类 review 是每张 Ticket 写入
已完成的必要条件。用户可确认全部建议项,也可只选其中一部分;未被确认的 Ticket 不写终态。 - 对用户确认的 Tickets 构造最小 patch,写入状态、完成度、Ticket 专属的验证证据、代码引用和
最后更新人,清理终态不应保留的阻塞字段。不覆盖无关新写入。 - 先更新 Tickets 并逐条回读。部分收口在此结束:父 Spec 保持
进行中,未完成 Tickets 保持原状态,回执中列出最小下一步。 - 最终收口在 Ticket 回读后重新查询全部子 Tickets。只有当全部 Tickets 已完成、Spec 级验收充分、Trellis task 已 archive(若适用)且人类完成最终 review,才展示 Spec 终态 patch 并再取得一次确认。
- 更新 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 幂等、竞态和失败处理
[推荐] 收口设计必须包含:
- 稳定键:只按 record ID 更新。
- 写前回读:责任人、状态或父子关系已变更时停止并报告,不强制覆盖。
- 最小 patch:只写当前状态转移需要的字段。
- 幂等重放:目标已是相同终态且证据一致时,结果为“已同步”,不再创建新记录或重复附加证据。
- 部分成功可见:返回逐条成功 / 失败列表,不用一个总体
ok遮蔽部分失败。 - 回读才是成功:只有回读字段符合预期才报告“Base 已闭环”。
- 外部失败不篡改本地事实:代码 / 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 验证下列最小闭环:
- 当前 Feishu CLI 人类用户可被准确解析。
- 能完整列出“Spec 自身负责人 = 当前用户”的 Spec,不因子 Ticket 归属扩张 Spec 列表;同时独立列出当前用户负责的 Tickets,并正确计算依赖 frontier。
- 用户选定后,Trellis 路径能把 Spec / Ticket record IDs 保存到
task.json.meta.feishuTracker,且 archive 后仍可读取。 - 同一个候选工作能分别跑通 Inline 和 Trellis 两条路径。
- Trellis 的
after_finish不触发 done;after_archive只触发收口提醒,显式 skill 才尝试写 done。 - 在 task 未 archive 时执行部分收口,skill 能按 Spec 取得全部未完成 Tickets,给出“建议可收口 / 待补证 / 未完成”分析,并只关闭用户 review 后确认的 Tickets。
- 部分收口后 Spec 仍为
进行中;未被用户确认的 Tickets 不被误关闭。 - 最终收口只在全部 Tickets 完成、Spec 验收通过、人类最终 review 通过且 Trellis task 已 archive(如适用)时关闭 Spec。
- 重复执行部分 / 最终收口不会创建重复记录、重复证据或错误状态。
- 刻意让一次 hook 失败,archive 仍成功,收口 skill 仍能通过 archive task mapping + Base 回读发现待同步工作。
- 刻意让一次 Base batch update 部分失败,skill 能保留逐条成功 / 失败证据并幂等重放,不误关父 Spec。
- 所有 Base 更新都显示
最后更新人 = 当前真实用户,且已逐条回读。 - POC 验收后将测试记录标记为
已取代,保留审计证据,不删除。
POC 前先仅定义读取和预演模式,展示将修改的 record IDs 和字段;真实写飞书应在用户确认后进行。
9. 导入顺序建议
阶段 A:只读队列
- 实现身份验证、完整分页、负责人过滤、状态分组和 frontier 计算。
- 不改 Base、不建 Trellis task。
- 验收:列表与 Base UI 人工核对一致。
阶段 B:选择与开始同步
- 用户选择后重读 record。
- 实现 Inline / Trellis 路由和稳定 ID 绑定。
- 用户一次确认“选择并开始”后,写
进行中并回读;Trellisafter_start只做可选对账。
阶段 C:显式收口
- Inline 和 Trellis 共用一个收口核心。
- 先做“部分收口”:按 Spec 分析所有未完成 Tickets,人类 review 后选择收口集合。
- 再做“最终收口”:验证全 Ticket 完成、Spec 聚合验收、人类最终 review 和幂等重放。
阶段 D:Workflow 与 hook 集成
- 把 skill 意图写入
.trellis/workflow.mdSkill 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 官方一手资料
本地已验证资料
- Matt 工作流 × 飞书 CLI 全流程总结
- Trellis × Matt 全局 Agent 规则
- Trellis × Matt 项目 Workflow
- 本机命令验证:
trellis 0.6.8、lark-cli 1.0.76、本机 Trellis 0.6.8 已安装 task / config 模板。
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 标记为 未运行。后续按以下顺序继续:
- 用户指定一个已配置飞书 tracker contract 的 Trellis 项目。
- 运行
start-work-feishu只读队列 POC,与 Base UI 人工核对负责人、分页和 frontier。 - 单独展示 record IDs 与开始 patch,经确认后验证 mapping、
进行中写入和回读。 - 依次验证部分收口、最终收口和对账重放;每批真实写入仍单独确认。
- V1 真实 POC 稳定后,再讨论是否抽取 helper,以及是否进入 workflow / hook 提醒集成。