- Added new documentation for the Feishu user authorization flow, detailing the backend protocol, authorization initiation, callback handling, and token management. - Updated frontend index to link to the new authorization flow documentation for better accessibility and guidance on UI design consistency.
40 KiB
Matt 工作流 × 飞书 Skills × Trellis Coding 闭环总结
状态:六个 Feishu workflow skills 已落地;Coding 入队、Trellis 映射、Ticket 部分收口和 Spec 最终收口已通过真实 Base POC。
更新时间:2026-07-27
实际验证项目:/Users/yuxuanhui/Documents/ai-workflow/project/经销商政策
范围:工作进入、需求澄清、Spec、Tickets、Triage、Inline/Trellis Coding 路由、实现证据、部分收口、归档和最终对账。具体编码规范仍由目标项目自己的 Trellis specs 和 coding skills 决定。
1. 最终结论
这次工作补齐了 Matt 工作流在飞书上的实现侧闭环。现在不只是把需求和计划放进 Base/Wiki,还可以从 Base 选择当前用户负责的工作,路由到 Inline 或 Trellis,实现后按 Ticket 逐步验收,最后在严格门禁下关闭父 Spec。
当前完整模型是:
- Feishu Base 管业务状态、责任人、父子关系、依赖、进度和可查询队列。
- Feishu Wiki / Docs 管 Spec、Triage Notes、Agent Brief、Human Brief 等长文档。
- Trellis 管复杂开发的本地任务生命周期、规划产物、执行快照、checkpoint、归档和 journal。
- repo 管代码、测试、commit、ADR、领域知识和可回放的实现证据。
- 用户 决定开始哪项工作,并对每张 Ticket 和最终 Spec 分别执行人类 review。
- Agent 负责查询、分析、路由、组织证据和提出精确 patch,但不能绕过人类 review 决定终态。
- lark-cli bot 执行 API;当前已验证人类用户写入
最后更新人;负责人始终表示工作责任,不被 bot 或操作归因覆盖。
flowchart LR
U["用户<br/>选择、review、确认外部写入"] --> Skills["六个 Feishu workflow skills<br/>流程编排与门禁"]
Skills --> Auth["lark-cli 身份门禁<br/>bot + user verified"]
Auth -->|"--as bot"| Base["Feishu Base<br/>状态、关系、队列、责任"]
Auth -->|"--as bot"| Wiki["Feishu Wiki / Docs<br/>Spec 与长叙述"]
Skills --> Trellis["Trellis<br/>复杂任务生命周期与本地上下文"]
Skills --> Repo["Repository<br/>代码、测试、commit、ADR"]
Wiki -->|"产物文档"| Base
Base -->|"record IDs + 验收边界"| Trellis
Base -->|"Tickets / frontier"| Trellis
Trellis -->|"checkpoint / archive"| Skills
Repo -->|"验证证据 / 代码引用"| Skills
Skills -->|"最小 patch + 回读"| Base
2. 六个 Feishu workflow skills
六个 skills 都是全局 skill,source of truth 位于 ~/.agents/skills/<skill-name>/。它们都配置了 policy.allow_implicit_invocation: false,因此涉及真实飞书读写时要求显式调用,不靠模糊意图静默修改外部系统。
| Skill | 负责的阶段 | 主要输入 | 主要产物 | 明确不负责 |
|---|---|---|---|---|
setup-workflow-skills-feishu |
仓库接入 | Base URL、Wiki 根 URL、Reuse/Bootstrap 选择 | repo tracker 合约;Bootstrap 时创建 schema、setup Wiki 文档和 POC 记录 | 不在 Reuse 模式修 schema;不猜资源地址 |
to-spec-feishu |
对话 → 可执行规格 | 已澄清对话、代码库、领域词汇、测试 seam | 一份 Wiki Spec + 一条 Base PRD/Spec |
不采访式重新澄清;不在 Wiki 未回读前创建 Base Spec |
to-tickets-feishu |
Spec → 垂直切片 | 已批准 Spec、Ticket 粒度、依赖边 | 每个切片一条 Base 实现 Ticket |
V1 不为 Ticket 创建 Wiki;不关闭或修改父 Spec |
triage-feishu |
Issue/PR 分诊 | 外部请求、代码验证、维护者决定、报告人反馈 | Base Issue 状态 + 可选 Wiki Triage dossier | 不在推荐阶段写状态;不重复创建 dossier |
start-work-feishu |
Coding 入队 | 当前用户、Spec/Ticket 队列、用户选择、路由确认 | Inline 会话绑定,或 1 Spec = 1 task 的 Trellis mapping;Base 进行中回写 |
不实现代码;不初始化 Trellis;不启动 sibling Tickets |
close-work-feishu |
Coding 收口 | Spec/Tickets、repo/Trellis 证据、人类 review、确认 patch | Ticket 部分收口、Spec 最终收口、失败后的幂等对账 | 不根据测试或 archive 自动完成;不替用户选择完成项 |
2.1 Skill 之间的调用关系
flowchart TD
Setup["setup-workflow-skills-feishu<br/>建立项目级 tracker 合约"] --> Intake{"工作从哪里进入?"}
Intake -->|"已澄清想法 / 对话"| Spec["to-spec-feishu<br/>Wiki Spec + Base Spec"]
Intake -->|"Issue / PR / 表单"| Triage["triage-feishu<br/>分类、验证、澄清、Brief"]
Triage -->|"needs-info"| Feedback["等待报告人反馈"]
Feedback -->|"最后反馈时间 > 最后分诊时间"| Triage
Triage -->|"ready-for-agent 且需要正式规格"| Spec
Triage -->|"ready-for-agent 且已足够明确"| Start
Triage -->|"ready-for-human"| Human["人类处理"]
Triage -->|"wontfix / out-of-scope"| Stop["保留关闭原因与审计记录"]
Spec --> Tickets["to-tickets-feishu<br/>Base Ticket 依赖图"]
Spec --> Start["start-work-feishu<br/>选择并开始"]
Tickets --> Start
Start --> Coding["Inline 或 Trellis Coding"]
Coding --> Close["close-work-feishu<br/>部分 / 最终 / 对账"]
Close -->|"仍有未完成 Ticket"| Coding
Close -->|"全部门禁满足"| Done["Base Spec 已完成<br/>工作流闭环"]
3. 端到端工作流总图
下面这张图把需求侧、规划侧、实现侧和收口侧放在同一条链路中。
flowchart TD
A["仓库首次接入"] --> B["Setup:验证 Base/Wiki、生成 docs/agents 合约"]
B --> C{"请求入口"}
C -->|"外部 Issue / PR / 表单"| D["Triage:验证事实与分类"]
D --> D1{"维护者 outcome"}
D1 -->|"needs-info"| D2["Wiki Triage Notes<br/>等待反馈"]
D2 --> D
D1 -->|"ready-for-human"| D3["Human Brief / 人类处理"]
D1 -->|"wontfix"| D4["关闭说明<br/>必要时 repo .out-of-scope"]
D1 -->|"ready-for-agent"| E{"是否需要正式 Spec?"}
C -->|"已澄清对话"| F["to-spec:确认测试 seam"]
E -->|"是"| F
E -->|"否,范围足够小"| J
F --> G["Wiki Spec 写入并 fetch 回读"]
G --> H["Base Spec:ready-for-agent"]
H --> I{"是否需要拆 Ticket?"}
I -->|"是"| I1["to-tickets:垂直切片 + blocker 图"]
I -->|"否,简单 Spec"| J["start-work:工作队列"]
I1 --> J
J --> K["用户选择 record ID"]
K --> L["写前重读:负责人、状态、父项、依赖、更新时间"]
L --> M{"Inline 还是 Trellis?"}
M -->|"Inline"| N["冻结当前会话 record IDs"]
M -->|"Trellis"| O["查找/创建唯一 task<br/>持久化 mapping 与 artifacts"]
N --> P["用户确认选择、路由和开始 patch"]
O --> P
P --> Q["Base 写进行中 + 实现 + 最后更新人"]
Q --> R["record-get 回读"]
R -->|"Trellis 新任务"| S["task.py start → in_progress"]
R -->|"Inline"| T["Coding 与验证"]
S --> T
T --> U["收集 diff、测试、浏览器验收、未运行项、代码引用"]
U --> V["close-work:逐 Ticket 验收映射"]
V --> W["人类 review 并选择可关闭 Ticket IDs"]
W --> X["Ticket 最小 patch + 逐条回读"]
X --> Y{"所有子 Tickets 已完成?"}
Y -->|"否"| T
Y -->|"是"| Z{"最终 Spec 门禁"}
Z -->|"Inline:Spec 证据 + 人类最终 review"| Z1["展示 Spec-only patch"]
Z -->|"Trellis:再加 archive + status=completed"| Z1
Z1 --> Z2["用户第二次确认 Spec patch"]
Z2 --> Z3["更新 Spec + record-get 回读"]
Z3 --> End["最终闭环完成"]
4. 四类事实源与产物关系
4.1 产物关系总图
flowchart LR
External["外部 Issue / PR / 表单"] -->|"来源链接 / 外部编号 / 报告人"| Issue["Base:需求/Issue"]
Issue -->|"产物文档"| TriageDoc["Wiki:Triage — 标题"]
Spec["Base:PRD/Spec"] -->|"所属父项"| Issue
Spec -->|"产物文档"| SpecDoc["Wiki:Spec — 标题"]
Ticket1["Base:实现 Ticket A"] -->|"所属父项"| Spec
Ticket2["Base:实现 Ticket B"] -->|"所属父项"| Spec
Ticket2 -->|"前置依赖"| Ticket1
Spec -->|"specRecordId,一对一"| Task["Trellis task"]
Ticket1 -.->|"ticketRecordIds / snapshot"| Task
Ticket2 -.->|"ticketRecordIds / snapshot"| Task
Task --> PRD["prd.md<br/>Spec 来源与验收边界"]
Task --> Design["design.md<br/>复杂任务技术设计"]
Task --> Impl["implement.md<br/>Ticket frontier + checkpoint"]
Task --> JSONL["implement.jsonl / check.jsonl<br/>必要 spec / research 清单"]
Task --> Archive["archive task.json<br/>status=completed"]
Repo["repo:代码 / 测试 / ADR / commits"] -->|"验证证据 / 代码引用"| Ticket1
Repo -->|"验证证据 / 代码引用"| Ticket2
Archive -->|"最终生命周期门禁"| Spec
Ticket1 -->|"全部严格已完成"| Spec
Ticket2 -->|"全部严格已完成"| Spec
4.2 哪个系统保存什么
| 信息 | 事实来源 | 说明 |
|---|---|---|
| 当前业务状态、负责人、完成度、优先级、时间 | Base | 面向队列、筛选、自动化和团队可见性 |
| 父子层级和 blocker 边 | Base 所属父项、前置依赖 |
使用真实 record ID;用于计算 frontier |
| Spec 与 Triage 长叙述 | Wiki / Docs | 可读、可追加、可审计 |
| 复杂任务的本地生命周期 | Trellis | planning、in_progress、archive、journal |
| 当前复杂任务的执行快照 | Trellis prd.md、implement.md |
可从 Base/Wiki 刷新,不反向覆盖 Base 业务事实 |
| 代码、测试、commit、ADR、领域知识 | repo | 版本控制事实来源 |
| 完成证明 | Base 验证证据 + 代码引用 |
内容来自 repo、真实命令、浏览器验收和 Trellis checkpoint |
| 被拒绝 enhancement 的持久决定 | repo .out-of-scope/ |
Wiki 只记录 outcome/link,不复制第二份 canonical decision |
5. Setup、Spec、Tickets 与 Triage 的逻辑
5.1 Setup:建立可执行 tracker 合约
flowchart TD
A["读取仓库现状"] --> B["用户提供 Base URL + Wiki 根 URL"]
B --> C{"Setup 模式"}
C -->|"Reuse,推荐"| D["只读验证身份、资源和完整 schema"]
C -->|"Bootstrap"| E["展示缺失字段、Wiki setup 标题、POC 标题"]
D --> F{"29 字段兼容?"}
F -->|"否"| G["停止;询问切换 Bootstrap 或单独 repair 授权"]
F -->|"是"| H["展示 repo-local 合约草案"]
E --> I["用户确认外部写入"]
I --> J["只创建缺失字段"]
J --> K["创建 Wiki setup 文档并 fetch"]
K --> L["创建 POC Base 记录并 record-get"]
L --> H
H --> M["生成 AGENTS/CLAUDE Agent skills 区块"]
M --> N["生成 docs/agents/issue-tracker.md"]
N --> O["生成 domain / triage 合约"]
Setup 的关键产物是项目级 docs/agents/issue-tracker.md。后续所有 Feishu skills 必须先读它,从中取得真实 Base、table、view、主字段、Wiki root、字段取值、身份和完成门禁,不能从别的项目或相似标题推断资源。
5.2 to-spec:一份长规格 + 一条可查询记录
sequenceDiagram
participant U as 用户
participant S as to-spec-feishu
participant W as Wiki / Docs
participant B as Base
S->>S: 读取对话、代码库、领域词汇和 ADR
S-->>U: 提议最高可用测试 seam
U->>S: 确认 seam
S->>B: 按真实主字段精确查重
S->>W: 创建 Spec — 标题
S->>W: append 完整 Spec XML
S->>W: docs +fetch
alt Wiki 内容完整
S->>B: 创建 PRD/Spec 记录
S->>B: record-get 回读全部字段
else Wiki 写入或 fetch 不完整
S-->>U: 停止,不创建 Base Spec
end
Wiki Spec 包含 Problem Statement、Solution、User Stories、Implementation Decisions、Testing Decisions、Out of Scope 和 Further Notes。Base Spec 保存 ready-for-agent、Wiki 链接、摘要、验收标准和可选来源 Issue。
5.3 to-tickets:两遍发布依赖图
flowchart TD
Spec["已批准 Spec"] --> Slice["拆成单上下文可验证的 tracer-bullet"]
Slice --> Edge["声明真实 blocker"]
Edge --> Quiz["用户确认粒度、拆分、合并和依赖"]
Quiz -->|"调整"| Slice
Quiz -->|"批准"| Parent["解析父 Spec record ID"]
Parent --> Search["逐标题查重"]
Search --> Pass1["Pass 1:按依赖顺序创建 Ticket<br/>暂不写 blocker"]
Pass1 --> IDs["冻结返回的 record IDs"]
IDs --> Pass2["Pass 2:写所属父项 + 前置依赖"]
Pass2 --> Verify["逐条回读父项、blocker 集、验收和最后更新人"]
Verify --> Frontier["frontier = 状态可开始<br/>且每个 blocker 恰好为已完成"]
Ticket V1 不创建 Wiki 文档,产物文档留空。实现者通过 所属父项找到父 Spec,再从父 Spec 的 产物文档取得完整规格。
5.4 triage:请求进入工程流程的 on-ramp
stateDiagram-v2
[*] --> 待分诊
待分诊 --> NeedsTriage: 维护者开始评估
state "needs-triage" as NeedsTriage
state "needs-info" as NeedsInfo
state "ready-for-agent" as ReadyAgent
state "ready-for-human" as ReadyHuman
NeedsTriage --> NeedsInfo: 信息不足,写 Triage Notes
NeedsInfo --> NeedsTriage: 最后反馈时间晚于最后分诊时间
NeedsTriage --> ReadyAgent: 事实与验收足够,可委派
NeedsTriage --> ReadyHuman: 需要判断、权限或手工工作
NeedsTriage --> wontfix: 不实施
ReadyAgent --> 进行中: 被 start-work 认领
ReadyHuman --> 进行中: 人类认领
wontfix --> [*]
Triage 的推荐与验证阶段只读。维护者确认 outcome 后,才写唯一 类别、唯一 canonical 状态、最后分诊时间、摘要、证据、下一步和 最后更新人。需要长叙述时,一个 Issue 只创建并持续 append 一份 Triage — <标题> Wiki dossier。
6. start-work-feishu:Coding 入队与路由
6.1 队列口径
Skill 会冻结当前已验证用户的 open ID,然后分别完整分页查询:
- Spec:
产物类型=PRD/Spec,且 Spec 自身负责人=当前用户。 - Ticket:
产物类型=实现 Ticket,且 Ticket 自身负责人=当前用户。
子 Ticket 归当前用户不会让父 Spec 自动进入 Spec 队列。父 Spec 只作为 Ticket 的上下文展示。
| 分组 | 条件 | 是否可选择 |
|---|---|---|
| 可恢复 | 进行中或阻塞 |
可以,但阻塞项必须展示原因,不暗示已解除 |
| 可开始 | ready-for-agent;Ticket 无 blocker 或所有 blocker 都恰好为已完成 |
可以 |
| 待收口 | 待评审 |
不重新开始,转 close-work-feishu |
| 被阻塞 | ready-for-agent,但任一 blocker 不是已完成 |
不可开始 |
| 排除 | 草拟、triage、人类专属和终态记录 | 不进入 coding queue |
wontfix、out-of-scope、已取代虽然是终态,但不能自动证明依赖要求已交付,因此不算满足 blocker。
6.2 Start skill 内部逻辑
flowchart TD
A["显式调用 start-work-feishu"] --> B["读取项目 tracker 合约与 Trellis workflow"]
B --> C["验证 bot + user,冻结当前 user open ID"]
C --> D["field-list 验证 29 字段和枚举"]
D --> E["完整分页查询 Spec 队列"]
E --> F["完整分页查询 Ticket 队列"]
F --> G["按 record ID 读取父项与 blocker"]
G --> H["计算可恢复 / 可开始 / 待收口 / 被阻塞"]
H --> I["用户选择 number 或 record ID"]
I --> J["重读选中项、父 Spec、全部子 Tickets、blockers"]
J --> K{"负责人、状态、关系或更新时间漂移?"}
K -->|"是"| H
K -->|"否"| L{"建议路由"}
L -->|"小、明确、单上下文"| M["Inline:冻结本会话 IDs 与快照"]
L -->|"跨模块、多会话、长验收链"| N["Trellis:扫描现有 mapping"]
N --> O{"匹配 task 数量"}
O -->|"多个"| Stop["停止,报告冲突"]
O -->|"一个"| Resume["恢复已有 task"]
O -->|"零个"| Create["task.py create --no-start"]
Resume --> Persist["刷新 prd / implement / mapping"]
Create --> Persist
Persist --> ReadMap["回读完整 meta.feishuTracker"]
M --> Confirm["一次确认:工作项 + 路由 + Base patch"]
ReadMap --> Confirm
Confirm --> Patch["按 record ID 写进行中 / 实现 / 最后更新人"]
Patch --> ReadBase["逐条 record-get 回读"]
ReadBase --> Route{"路由"}
Route -->|"Inline"| Coding["交给当前会话实现"]
Route -->|"新建或 planning task"| Start["task.py start"]
Start --> VerifyTask["回读 task.json status=in_progress"]
6.3 Inline 与 Trellis 的判断
| 路由 | 适用情况 | 本地持久化 |
|---|---|---|
| Inline | 范围窄、方案已知、一个健康上下文可完成、最低验证可在当前会话完成 | 只在当前对话冻结 record IDs,不创建 mapping 文件 |
| Trellis | 跨模块、多阶段、多个稳定决策、durable research、多会话或验收链较长 | 创建或恢复唯一 task,持久化 Spec mapping、规划产物和 Ticket snapshot |
这里的 Inline 是“完全不创建 Trellis task”。它和 Trellis 内部 Codex dispatch_mode=inline不是同一概念;后者仍然已经处在 Trellis task 内。
6.4 1 Spec = 1 Trellis task mapping
{
"meta": {
"feishuTracker": {
"schemaVersion": 1,
"specRecordId": "rec_xxx",
"ticketRecordIds": ["rec_aaa", "rec_bbb"],
"selectedRecordIds": ["rec_aaa"],
"specWikiUrl": "https://...",
"trackerContractPath": "docs/agents/issue-tracker.md",
"boundAt": "ISO-8601",
"lastRefreshAt": "ISO-8601"
}
}
}
specRecordId是一对一绑定的稳定键。ticketRecordIds是刷新时全部子 Tickets 的排序去重快照,不是 Base 的替代事实源。selectedRecordIds是这次用户直接选择的 Spec 或 Ticket。boundAt首次绑定后不变;lastRefreshAt随成功刷新更新。- mapping 不保存 Base token、凭证或固定个人 open ID。
- 只更新
meta.feishuTracker,保留task.json其他字段和未知未来键。
6.5 开始 patch
{
"状态": "进行中",
"工作流阶段": "实现",
"最后更新人": [{"id": "<CURRENT_USER_OPEN_ID>"}]
}
- 选择 Spec:只写 Spec。
- 选择 Ticket:写选中的 Ticket 和它的父 Spec。
- 不修改
负责人、完成度、sibling Tickets、证据、blocker 或下一步。 - Trellis 新任务只有在 mapping 持久化成功、Base 写入成功且回读一致后才执行
task.py start。
7. Trellis Coding 生命周期
stateDiagram-v2
[*] --> planning: task.py create --no-start
planning --> in_progress: task.py start
in_progress --> in_progress: implement / check / update-spec / commit
in_progress --> Detached: task.py finish
state "session detached\n任务未完成" as Detached
Detached --> in_progress: 其他 session 可继续
in_progress --> completed: task.py archive
completed --> Archived: 移入 archive tree
state "archive/task.json\nstatus=completed" as Archived
关键边界:
task.py finish只清除当前 session 的任务指针,不能作为 Base 完成信号。- 复杂任务通常经历
implement → check → update-spec → 工作 commit → finish-work/archive → journal。 after_archive最多作为提醒或待对账信号;显式close-work-feishu才有资格在回读后声称 Base 已闭环。- Ticket 部分收口不要求 archive;父 Spec 最终收口才要求归档 task 且
status=completed。
8. close-work-feishu:部分收口、最终收口与对账
8.1 三个内部 routing
| Routing | 进入条件 | 结果 |
|---|---|---|
| 部分收口 | 有一个或多个 Ticket 已有直接证据,并完成对应人类 review | 只关闭用户选中的 Ticket;Spec 保持进行中 |
| 最终收口 | 全部 Ticket 已完成,Spec 验收有证据,人类完成最终 review;Trellis 路径还必须 archive | 用户再次确认 Spec-only patch 后关闭 Spec |
| 对账重放 | 上次写入部分成功、回读失败或记录已在目标终态 | 只补差异;证据完整时返回already synchronized,不重复追加 |
8.2 Close skill 完整逻辑
flowchart TD
A["显式调用 close-work-feishu"] --> B["用 active/archived mapping 或 Inline 会话定位 Spec ID"]
B --> C["验证身份、schema、Spec 类型"]
C --> D["按父 Spec 完整分页查询全部子 Tickets"]
D --> E["比较 live Ticket 集与 Trellis snapshot"]
E --> F["汇总验收标准、repo diff、测试、浏览器验收、未运行项、代码引用、checkpoint"]
F --> G["逐 Ticket 映射验收证据"]
G --> H{"分类"}
H --> H1["建议可收口"]
H --> H2["待补证 / 待验证"]
H --> H3["明确未完成 / 阻塞"]
H1 --> I["展示精确 Ticket patch"]
H2 --> Wait["保持原状态,说明最小下一步"]
H3 --> Wait
I --> J["用户声明已完成人类 review<br/>并选择允许关闭的 record IDs"]
J --> K["写前逐条重读,检查 owner、状态、父项、依赖、验收、证据、更新时间"]
K --> L{"是否漂移?"}
L -->|"是"| I
L -->|"否"| M["批量最小 patch,最多 200 条且串行"]
M --> N["逐条 record-get 回读"]
N --> O{"失败 / ignored / mismatch?"}
O -->|"是"| Reconcile["输出成功、失败、待对账清单<br/>禁止关闭 Spec"]
O -->|"否"| P["重新完整查询所有子 Tickets"]
P --> Q{"是否全部严格为已完成?"}
Q -->|"否"| Partial["部分收口完成<br/>Spec 保持进行中"]
Q -->|"是"| R{"Spec 级最终门禁"}
R -->|"未满足"| Hold["Spec 不变,报告缺失门禁"]
R -->|"满足"| S["展示独立 Spec-only patch"]
S --> T["用户第二次确认"]
T --> U["立即重读 Spec;漂移则确认失效"]
U --> V["写 Spec + record-get 回读"]
V --> Done["最终收口回执"]
8.3 Ticket 完成 patch
{
"状态": "已完成",
"工作流阶段": "交付",
"完成度": 1,
"验证证据": "<保留旧内容并追加一次 Ticket 专属 closure section>",
"代码引用": "<保留并去重的真实引用>",
"阻塞原因": null,
"下一步": null,
"最后更新人": [{"id": "<CURRENT_USER_OPEN_ID>"}]
}
每个 closure section 至少记录:人类 review、验收到证据的映射、真实验证命令和结果、明确未运行项及原因。不能用 Agent review、测试通过、Trellis finish或 archive 单独替代人类 review。
8.4 Spec 最终门禁
flowchart LR
A["全部子 Tickets<br/>状态恰好为已完成"] --> Gate{"Spec 最终门禁"}
B["Spec 每条验收标准<br/>都有直接证据"] --> Gate
C["用户完成 Spec<br/>最终代码/功能 review"] --> Gate
D["Trellis 路径:task 位于 archive<br/>且 status=completed"] --> Gate
E["不存在 Ticket write/read-back 失败"] --> Gate
Gate -->|"全部满足"| Patch["展示 Spec-only patch"]
Patch --> Confirm["用户单独确认"]
Confirm --> Done["写入 + 回读后才算闭环"]
wontfix、out-of-scope、已取代不自动算作“全部 Ticket 已完成”。无 Ticket 的简单 Spec 可以跳过 Ticket 门禁,但仍需 Spec 验收证据、人类最终 review,以及适用的 Trellis archive 门禁。
9. 身份、确认与写后回读协议
sequenceDiagram
participant U as 用户
participant S as Feishu skill
participant A as lark-cli auth
participant B as Feishu Base
U->>S: 显式调用 skill
S->>A: auth status --json --verify
A-->>S: bot verified + user verified + user.openId
S->>S: 冻结 CURRENT_USER_OPEN_ID
S->>B: --as bot 读取 schema / records
B-->>S: 当前快照
S-->>U: 展示稳定 record IDs 与精确 patch
U->>S: 明确确认外部写入
S->>B: 写前按 record ID 重读
B-->>S: 无漂移
S->>B: --as bot 最小 patch<br/>最后更新人=user.openId
B-->>S: ok:true
S->>B: record-get / 完整分页回读
B-->>S: 字段与关系符合预期
S-->>U: 完成回执
统一规则:
- 每条 Base read/write 都使用
--as bot --format json,失败后不降级为 user。 负责人是 assignee;最后更新人是最近一次通过 CLI 推进记录的真实人类;bot 只是 API caller。- 标题是展示文本,record ID 才是更新键。
- 写前展示目标记录和精确 patch;写后必须回读。
ok:true不证明 record 存在或字段已生效;ignored_fields和 read-back mismatch 都算失败。- schema、视图和只读操作没有行级归因目标,不写
最后更新人。
10. Base 主状态机与 Trellis 映射
10.1 Base 主状态机
stateDiagram-v2
[*] --> 草拟中
草拟中 --> 待确认
待确认 --> ReadyAgent: 可由 Agent 执行
待确认 --> ReadyHuman: 需要人类执行
state "ready-for-agent" as ReadyAgent
state "ready-for-human" as ReadyHuman
ReadyAgent --> 进行中: start-work 确认并回写
ReadyHuman --> 进行中: 人类认领
进行中 --> 阻塞: 发生 blocker
阻塞 --> 进行中: blocker 解除
进行中 --> 待评审: 进入 review
待评审 --> 进行中: review 要求修改
待评审 --> 已完成: 人类 review + 直接证据
草拟中 --> 已取代
待确认 --> 已取代
ReadyAgent --> 已取代
进行中 --> 已取代
ReadyAgent --> OutOfScope: 范围外
state "out-of-scope" as OutOfScope
已完成 --> [*]
已取代 --> [*]
OutOfScope --> [*]
10.2 Trellis 事件到 Base 的业务含义
| Trellis / 本地事件 | Base 动作 | 原因 |
|---|---|---|
| 只读列队、用户未选择 | 不写 | 浏览队列不是认领 |
| mapping 保存成功,用户确认“选择并开始” | Spec 或 Ticket/父 Spec → 进行中、实现 |
表示进入规划/执行,不猜完成度 |
planning / after_start |
通常不重复写 | Start skill 已完成开始回写 |
| 发生外部 blocker | 阻塞,并填写阻塞原因和下一步 |
状态与解释必须一致 |
| Agent 建议可收口但无人类 review | 保持原状态 | Agent 只能推荐 |
| 部分收口 | 仅用户选中的 Tickets → 已完成 |
父 Spec 保持进行中 |
task.py finish / after_finish |
不写完成态 | 只代表 session detach |
archive / after_archive |
不自动写完成态 | 只满足 Spec 生命周期门禁之一 |
| 全 Ticket 完成 + Spec 验收 + 人类最终 review + archive | Spec → 已完成、交付、完成度=1 |
最终聚合收口 |
| Base 同步失败 | 保留真实现状并输出待对账 | 代码/Trellis 完成与外部同步分开报告 |
11. Base 完整字段字典(29 个)
以下字段来自“经销商政策”项目配置的真实 Base field-list回读。文本是当前表的主字段。
| # | 字段 | Field ID | 类型 / 当前取值 | 含义与规则 |
|---|---|---|---|---|
| 1 | 文本 | fldzLHLTca |
text,主字段 | 记录的业务标题。标题可用于创建前精确查重,但更新必须使用 record ID。 |
| 2 | 产物类型 | fldlwQ46Ks |
single select:需求/Issue、PRD/Spec、实现 Ticket、Wayfinder Map、决策 Ticket、原型、研究、Handoff、ADR、领域词汇、Bug 诊断、代码评审、架构候选、教学资产 | 说明该记录代表哪类工作流产物。 |
| 3 | 来源技能 | fldUMyVtoS |
multi-select:setup-matt-pocock-skills、setup-workflow-skills-feishu、grill-with-docs、grill-me、triage、diagnosing-bugs、wayfinder、to-spec、to-tickets、implement、tdd、code-review、improve-codebase-architecture、domain-modeling、prototype、research、handoff、teach | 记录创建或推进产物的逻辑流程。业务记录通常写逻辑 skill 名;当前表也保留 setup 的 Feishu 适配器选项。 |
| 4 | 工作流阶段 | fldjAkNPqD |
single select:探索/澄清、决策、规格、拆票/规划、实现、验证/评审、交付、维护/学习、分诊 | 表示产物处于端到端流程哪一阶段;与状态是不同维度。 |
| 5 | 状态 | fldHjFrlwJ |
single select:草拟中、待确认、待分诊、needs-triage、needs-info、ready-for-agent、ready-for-human、进行中、阻塞、待评审、已完成、wontfix、out-of-scope、已取代 | 统一业务状态机。英文值保留 Matt triage canonical role。 |
| 6 | 类别 | fldQWuceDX |
single select:bug、enhancement | Triage 分类;每个已分诊项必须恰好一个。 |
| 7 | 决策票类型 | fldFpkeDkj |
single select:research、prototype、grilling、task | Wayfinder 子决策票的解决方式;非决策票通常留空。 |
| 8 | 协作模式 | fldVwgWNRU |
single select:HITL、AFK | HITL 需要人类实时参与;AFK 表示 Agent 可以独立推进到下一个门禁。 |
| 9 | 优先级 | fldJv2ts2l |
single select:P0、P1、P2、P3 | 业务/执行优先级;不替代 blocker frontier。 |
| 10 | 负责人 | fldGlPa1B1 |
user,单值 | 当前直接执行责任人。必须是真实飞书用户;Start/Close skills 不覆盖它。 |
| 11 | 最后更新人 | fld6nvDu18 |
user,单值 | 最近一次通过 lark-cli 创建或更新记录的真实人类用户;不是 bot,也不是飞书系统更新时间。 |
| 12 | 完成度 | fldqNJjr0g |
number/progress,0–1 | 业务进度。Base 显示为百分比;最终完成写 JSON number 1。 |
| 13 | 产物文档 | fldorpkrbf |
text/plain | canonical Wiki 或长文档链接。Spec/Triage 使用;V1 Ticket 留空并沿父 Spec 取文档。 |
| 14 | 验收标准 | fldwbSY2pq |
text | 可验证的完成条件。实现 Ticket 必填;Spec 保存聚合验收边界。 |
| 15 | 验证证据 | fldIQ0NQPO |
text | 真实命令、测试结果、浏览器验收、review、read-back 事实和未运行原因。没有具体证据不能完成。 |
| 16 | 结论/摘要 | fldmdDUJHh |
text | Problem/Solution 摘要、决策结论、诊断根因、研究摘要或交付结果;长分析放 Wiki。 |
| 17 | 阻塞原因 | fldUsFDsTS |
text | 仅阻塞或needs-info等无法继续的状态使用;说明为什么不能推进。 |
| 18 | 下一步 | fldMY6XATm |
text | 解除阻塞或进入下一阶段的最小动作;完成态清空。 |
| 19 | 代码引用 | fldNylIQ5y |
text | 分支、commit、PR、文件:行号、Trellis checkpoint、review fixed point 或.out-of-scope/路径。只写真实存在的引用。 |
| 20 | 截止时间 | fldZP6Cm30 |
datetime,yyyy-MM-dd HH:mm |
人工承诺的截止时间,不由 Agent 自动推算。 |
| 21 | 创建时间 | fldnPF52hP |
created_at,只读 | Base 自动记录的创建时间;Triage 关注队列按它从旧到新排序。 |
| 22 | 更新时间 | fldd3rTk0I |
updated_at,只读 | Base 自动记录的行更新时间;用于竞态检测,不等于最后更新人。 |
| 23 | 所属父项 | flduS0iiPy |
self-link,双向 | Spec 指向来源 Issue;Ticket 指向父 Spec;决策 Ticket 指向 Wayfinder Map。写真实 record ID。 |
| 24 | 前置依赖 | fldYkwZVu1 |
self-link,双向 | 指向阻塞当前项的记录。只有所有 blocker 都恰好为已完成时 Ticket 才进入 frontier。 |
| 25 | 来源链接 | fldp4F1S6m |
text/url | 原始 Issue、PR、表单或外部系统 URL。 |
| 26 | 外部编号 | fldpv8O5OW |
text | 外部系统编号。它不是 Base record ID,不能用作更新键或 link CellValue。 |
| 27 | 报告人 | fld37AxlZf |
text | 报告人的显示名或外部标识;兼容报告人不是飞书用户。 |
| 28 | 最后反馈时间 | fldTwNj5Uz |
datetime,yyyy-MM-dd HH:mm |
报告人或外部来源最近一次新增反馈时间。只更新时间,不自动改状态。 |
| 29 | 最后分诊时间 | fldNy9eAgM |
datetime,yyyy-MM-dd HH:mm |
维护者最近一次确认并写回分诊结果的时间。最后反馈时间 > 最后分诊时间时,needs-info 重新进入关注队列。 |
11.1 Link 字段边界
所属父项和前置依赖的正向字段是自动化 source of truth。lark-cli 1.0.76可能返回同表双向关系的 reverse field ID,但 reverse 字段不一定独立出现在field-list,因此当前实现不依赖反向字段寻址。
12. 真实 POC:经销商政策项目
12.1 POC 对象
| 产物 | Record ID / 路径 | 最终状态 |
|---|---|---|
| Spec:历史报告多条件检索 | recvquNpDDOafu |
已完成 / 交付 / 1 |
| Ticket A:按事业部和分析类型筛选历史报告 | recvquNtBMcQ2V |
已完成 / 交付 / 1 |
| Ticket B:按关键词搜索并完善筛选反馈 | recvquNxjmWwth |
已完成 / 交付 / 1 |
| Trellis task | .trellis/tasks/archive/2026-07/07-27-feishu-recvqunpddoafu |
archive 中,task.json.status=completed |
| 工作 commit | e7270cf |
feat: 支持历史报告多条件检索 |
| 规范 commit | 1f00f51 |
docs: 沉淀报告检索状态同步契约 |
| 归档 commit | 30b9c8f |
chore(task): archive 07-27-feishu-recvqunpddoafu |
| journal commit | 3e91199 |
chore: record journal |
12.2 真实执行时序
sequenceDiagram
participant U as 于选辉
participant S as start-work-feishu
participant B as Feishu Base
participant T as Trellis
participant C as Coding / Check
participant X as close-work-feishu
U->>S: 选择历史报告多条件检索工作
S->>B: 查询 Spec、Tickets、父项和 blocker
S->>T: 创建并保存 1 Spec = 1 task mapping
S->>B: 写 Spec/Ticket 进行中并回读
S->>T: task.py start
T->>C: 实现 Ticket A
C-->>U: 代码、测试和构建证据
U->>X: 已完成 Ticket A 人类 review
X->>B: 关闭 recvquNtBMcQ2V 并回读
B-->>X: Ticket A 已完成,Ticket B blocker 解锁
T->>C: 实现 Ticket B
C-->>U: API、前端、构建、真实浏览器与竞态证据
U->>X: 已完成 Ticket B 人类 review
X->>B: 关闭 recvquNxjmWwth 并回读
B-->>X: 两张 Ticket 全部已完成
C->>T: update-spec + commits
U->>T: 授权 finish-work
T->>T: archive task + journal
U->>X: 已完成 Spec 最终 review
X->>B: 重新查询全部 Tickets 与 Spec
X-->>U: 展示 Spec-only 精确 patch
U->>X: 第二次确认最终 patch
X->>B: 更新 Spec 已完成并 record-get
B-->>X: 已完成 / 交付 / 1,负责人和验收保持不变
12.3 实现与验证结果
本次 Spec 实现了:事业部、分析类型、标题/文件名关键词组合检索;条件使用 AND 语义;关键词去除首尾空白并对拉丁字符大小写不敏感;无筛选兼容旧行为;筛选后详情与列表保持一致;区分空仓库和筛选无结果;支持一键清空;旧请求不能覆盖新筛选结果。
真实验证证据:
pytest -q tests/test_api.py -k reports:9 passed, 11 deselected。- 可执行后端回归:
37 passed, 1 deselected。 - 前端
npm test:4 passed。 - 前端
npm run build:通过,仅保留既有 large-chunk advisory。 - Trellis task validation:通过。
git diff --check:通过。- 真实浏览器验收:文件名关键词、大小写不敏感三条件组合、当前条件/结果数反馈、筛选无结果、详情清空与恢复、一键清空全部通过。
- 受控请求竞态:较早的延迟响应未覆盖较新的筛选结果。
- 浏览器 console 仅出现与本功能无关的
favicon.ico404。 - 完整 pytest 未运行成功的原因被明确保留:既有缺失模块/import collection errors,以及本次 diff 外的
policy_data404;没有把未运行项伪报为通过。
12.4 POC 证明了什么
flowchart LR
A["当前用户负责人过滤"] --> Proof["真实 POC 通过"]
B["Ticket blocker frontier"] --> Proof
C["稳定 record ID 与 Trellis mapping"] --> Proof
D["1 Spec = 1 task"] --> Proof
E["Ticket 逐张人类 review"] --> Proof
F["部分收口不关闭 Spec"] --> Proof
G["archive 不是自动完成授权"] --> Proof
H["Spec 第二次确认"] --> Proof
I["写前重读 + 写后回读"] --> Proof
J["最后更新人归因"] --> Proof
K["未运行项显式记录"] --> Proof
本次 demo POC 仅对“planning artifacts 必须经人类 review 后才能 task.py start”放宽了一次;Ticket review、Spec 最终 review、外部写入确认和回读门禁均未放宽。最终 Spec 的 Base 回读时间为 2026-07-27 10:04:12,负责人和最后更新人均为于选辉,验收标准和关联字段保持不变。未执行 push。
13. 失败处理与幂等对账
flowchart TD
A["任一步失败"] --> B{"失败位置"}
B -->|"身份 / schema / 查询"| C["不做任何本地或外部写入"]
B -->|"选择后发生漂移"| D["旧确认失效,重新展示队列或 patch"]
B -->|"task / artifact / mapping"| E["不写 Base,保留明确失败原因"]
B -->|"Base 开始写失败"| F["task 保持 planning<br/>报告 mapping 已保存但未同步"]
B -->|"Base 成功,Trellis start 失败"| G["Base 已认领<br/>Trellis 待启动,不自动回滚"]
B -->|"Ticket batch 部分失败"| H["保留逐条成功/失败<br/>禁止关闭 Spec"]
B -->|"write ok 但回读 mismatch"| I["标记 mismatched,不宣称完成"]
B -->|"记录已完整同步"| J["already synchronized<br/>不重复追加证据"]
H --> K["下次对账只补仍有差异的记录"]
I --> K
核心原则:外部系统的部分成功不能被一个总体ok:true遮蔽;也不能因为 Base 同步失败就篡改已经完成的代码/Trellis事实。回执必须把“代码完成”“Trellis lifecycle 完成”“Base 同步完成”分开报告。
14. 当前边界与后续演进
V1 当前边界:
- 两个 Coding 闭环 skills 已实现并通过真实 POC。
- 直接编排项目内
.trellis/scripts/task.py和lark-cli,没有新增 helper CLI。 - 没有修改 Trellis workflow、hooks 或 Base schema。
- 不自动 commit、push 或创建 PR;Git 写操作继续遵守用户授权边界。
- 不把 coding sub-agent 设为 Base 状态决策者;外部选择、review、确认和回读都留在主会话。
建议的后续顺序:
- 在第二个真实项目重放一次 Inline 路径,验证跨会话时按 record ID 重选的体验。
- 演练一次故意的 Base batch 部分失败,验证对账 routing 的逐条补偿。
- 演练一次 mapping 冲突和记录竞态,验证确认失效路径。
- 稳定后再考虑抽取共享分页/frontier/helper;在两个 skills 尚未形成稳定重复前不提前封装。
- 如果接入 lifecycle hook,
after_archive只提醒或生成不含凭证的 pending 标记,不直接写 Base 完成态。
15. 一句话心智模型
flowchart LR
Issue["Issue<br/>要解决什么"] --> Spec["Spec<br/>为什么做、验收边界"]
Spec --> Tickets["Tickets<br/>可独立交付的垂直切片与依赖"]
Tickets --> Start["Start<br/>选择、路由、认领"]
Start --> Coding["Coding<br/>Inline 或 1 Spec = 1 Trellis task"]
Coding --> Evidence["Evidence<br/>代码、测试、浏览器、review"]
Evidence --> Close["Close<br/>Ticket 部分收口 → Spec 最终收口"]
Close --> Done["Done<br/>写后回读的 Base 闭环"]
Base 回答“现在是什么状态、由谁负责、依赖谁”;Wiki 回答“为什么做、具体要求是什么”;Trellis 回答“复杂工作如何规划、执行和归档”;repo 回答“到底实现了什么、验证过什么”;六个 Feishu skills 负责把这些事实源连接成一条可确认、可回读、可重放的工作流。
16. 相关资料
- Matt 工作流 × 飞书 CLI 全流程总结
- Trellis × 飞书实现闭环初步方案
- 经销商政策项目 tracker 合约:
/Users/yuxuanhui/Documents/ai-workflow/project/经销商政策/docs/agents/issue-tracker.md - 真实 POC 归档任务:
/Users/yuxuanhui/Documents/ai-workflow/project/经销商政策/.trellis/tasks/archive/2026-07/07-27-feishu-recvqunpddoafu - Trellis 官方文档:架构、自定义 Workflow、自定义 Skills、自定义 Agents、配置