- 桌面应用
- 开发工具
【免费下载链接】EcoPaste
🎉跨平台的剪贴板管理工具 | Cross-platform clipboard management tool
本篇以 Trellis 工作流系统中的
trellis-finish-work技能文档为主体,结合 EcoPaste 仓库.trellis/下的真实脚本实现(get_context.py、task.py、add_session.py、workflow.md、config.yaml),系统讲解会话收尾阶段的标准操作:如何核查质量门禁与工作区状态、如何对脏路径做归属分类、如何归档任务并自动生成 commit,以及如何记录会话日志并维护 Git 提交顺序。读完本文,你将能独立完成一次符合 Trellis 规范的安全收尾流程,理解每一步背后的脚本实现原理。
一、收尾流程的定位与整体结构
在 Trellis 工作流中,一个完整任务的执行分为三个阶段:Phase 1: Plan(规划)、Phase 2: Execute(执行)、Phase 3: Finish(收尾)。收尾阶段(Phase 3)由3.2 调试复盘、3.3 规范更新、3.4 提交变更、3.5 收尾提醒四个步骤组成(步骤 3.1 已并入 2.2 与 3.4,编号保留以避免破坏外部引用)。
trellis-finish-work技能负责的是3.4 之后、3.5 之前的收尾动作:归档已完成的任务(archive)、记录本次会话日志(add_session)。它被设计为一个流程终点的"收束器"——前提是工作代码已经通过workflow.md中 Phase 3.4 的批量提交流程完成git commit,收尾阶段绝不执行代码提交,代码提交发生在$finish-work被调用之前。
整个收尾流程分四步:
| 步骤 | 动作 | 对应命令 | 产物 |
|---|---|---|---|
| Step 1 | 盘点当前状态 | python3 ./.trellis/scripts/get_context.py --mode record | 活动任务、Git 状态、近期提交哈希 |
| Step 2 | 分类脏路径 | git status --porcelain | 当前任务 / 并行工作 / 不确定三类 |
| Step 3 | 归档任务 | python3 ./.trellis/scripts/task.py archive <task-name> | 任务移入archive/{年-月}/,产生chore(task): archive ...commit |
| Step 4 | 记录会话日志 | python3 ./.trellis/scripts/add_session.py --title ... --commit ... --summary ... | 追加会话到journal-N.md,产生chore: record journalcommit |
最终期望的 Git 提交顺序为:<Phase 3.4 产生的工作提交>→chore(task): archive ...(一个或多个)→chore: record journal。即工作提交在前、簿记提交在后,绝不交错。
二、Step 1:使用get_context.py --mode record盘点会话状态
收尾的第一步不是凭记忆猜测,而是运行脚本盘点当前工作区:
python3 ./.trellis/scripts/get_context.py --mode record该命令输出三类关键信息:
- My active tasks(我的活动任务):需要逐一判断除当前任务外,是否还有其他已经完成(代码已合并、验收标准已满足)的任务应当在本轮一并归档。
- Git status(Git 状态):快速可视化工作区有哪些未提交变更。
- Recent commits(近期提交):Step 4 中
--commit参数需要的提交哈希就来自这里。
脚本实现:get_context.py的 record 模式
get_context.py本体是一个薄入口,真正的逻辑在 common/git_context.py 中,其--mode参数支持default / record / packages / phase四种取值,当args.mode == "record"时输出 record 模式内容(JSON 或文本两种形态)。
record 模式的实现位于 common/session_context.py 的get_context_record_json:它单次遍历活动任务列表,按assignee过滤出当前开发者的任务(myTasks),逐任务统计子任务完成数(childrenDone,子任务状态为completed或done即计为完成),并通过get_current_task解析出当前活动任务的路径、状态、来源类型(source)与会话上下文键(contextKey)。返回结构如下:
{ "developer": "ayangweb", "git": { "isRepo": true, "branch": "...", "isClean": false, "uncommittedChanges": ["..."], "recentCommits": ["..."] }, "myTasks": [{"dir": "...", "title": "...", "status": "...", "childrenDone": 0}], "currentTask": {"path": "...", "name": "...", "status": "in_progress", "source": "..."} }从实现可以看出:record 模式聚焦于"我的任务 + Git 状态 + 当前任务"三件事,这正是收尾决策所需的最小信息集。
其他常用模式
get_context.py不只在收尾时有用,workflow.md 中记载了完整用法:
python3 ./.trellis/scripts/get_context.py # 完整会话运行时上下文 python3 ./.trellis/scripts/get_context.py --mode packages # 列出可用 package 与 spec 层 python3 ./.trellis/scripts/get_context.py --mode phase --step 1.1 # 获取某个工作流步骤的详细指引三、Step 2:脏路径归属分类——收尾前最重要的安全门禁
如果--mode record的输出暴露了其他已完成任务,需要向用户做一次性确认:"These N tasks look done — archive them too in this round? [y/N]"(这些 N 个任务看起来已完成——本轮一并归档吗?)。默认回答为否;但无论用户是否确认额外归档,Step 3 中当前活动任务都会被归档。
随后运行:
git status --porcelain过滤 Trellis 自身管理的路径
输出中的以下两类路径会被过滤掉,因为它们是本技能自身工作的正常产物,由脚本自动提交管理:
.trellis/workspace/下的文件 —— 由add_session.py管理.trellis/tasks/下的文件 —— 由task.py archive自动提交管理
三条启发式规则
对剩余每条脏路径,按以下启发式判断其归属:
- 当前任务的工作:路径出现在当前任务的
prd.md/implement.jsonl/check.jsonl中; - 当前任务的工作:路径位于与任务声明范围相符的代码区域,或本会话确实编辑过;
- 并行窗口的工作:路径位于无关区域且本会话从未触碰(例如另一个终端窗口正在编辑同一仓库)。
三类结果的分流处理
| 判定结果 | 处理方式 |
|---|---|
| 有路径像当前任务的工作 | 立即中止收尾,输出提示:"Working tree has uncommitted code changes from this task:<list>. Return to workflow Phase 3.4 to commit them before running$finish-work." 此处不得执行git commit,也不得提示用户提交——用户应返回 Phase 3.4,由 AI 在那里驱动批量提交 |
| 剩余路径均无关 | 报告一次后继续 Step 3:"FYI, dirty files outside this task's scope — leaving them for the other window:<list>."(提示:范围外脏文件,留给另一个窗口处理) |
| 确实无法确定 | 询问用户一次:"Are<list>this task's work I forgot to commit, or another window's? (commit / ignore)"(这些是本任务忘了提交的工作,还是另一个窗口的?),按回答分流 |
这一步骤是整个收尾流程的安全门禁:它阻止了"未提交代码被收尾流程吞掉"的最常见事故。workflow.md的 Phase 3.4 明确要求:工作提交(git add <files>+git commit -m "<msg>",按逻辑提交单元分批)必须先于簿记提交,且禁止git commit --amend、禁止推送到远程。
四、Step 3:归档任务——task.py archive及其自动提交
确认工作树干净后,执行任务归档:
python3 ./.trellis/scripts/task.py archive <task-name>至少归档:当前活动任务(如有)。再加上 Step 1 中用户确认的其他任务。每个归档动作都会由脚本自动生成一个chore(task): archive ...提交。如果既没有活动任务、用户也未确认任何清理归档,则跳过本步骤。
脚本实现:task.py archive做什么
从 task.py 的帮助文档与命令注册可以看到完整的任务生命周期命令集:
python3 task.py create "<title>" [--slug <name>] [--assignee <dev>] [--priority P0|P1|P2|P3] [--parent <dir>] [--package <pkg>] python3 task.py add-context <dir> <file> <path> [reason] python3 task.py validate <dir> # 校验 jsonl 文件 python3 task.py list-context <dir> python3 task.py start <dir> # 设置活动任务 python3 task.py current [--source] # 显示活动任务 python3 task.py finish # 清除活动任务 python3 task.py set-branch <dir> <branch> # 设置 Git 分支 python3 task.py set-base-branch <dir> <branch> python3 task.py set-scope <dir> <scope> python3 task.py archive <task-dir> # 归档已完成任务 python3 task.py list # 列出活动任务 python3 task.py list-archive [month] # 按月份列出已归档任务 python3 task.py add-subtask <parent-dir> <child-dir> python3 task.py remove-subtask <parent-dir> <child-dir>按 workflow.md 的记载,task.py archive <task>的底层行为是:将task.json的状态写为completed,把任务目录移动到archive/(按月组织,如.trellis/tasks/archive/2026-06/),并删除仍指向该任务的运行时会话文件。archive支持--no-commit参数以跳过自动提交。任务目录的标准结构为:task.json(状态机、分支、包归属、钩子配置)、prd.md(需求与验收标准)、可选design.md(复杂任务的技术设计)、可选implement.md(执行计划与验证清单)、implement.jsonl/check.jsonl(子代理上下文清单)。
仓库中已有真实的归档示例,例如 .trellis/tasks/archive/2026-06/06-12-auto-updater/ 目录下包含prd.md、check.jsonl、implement.jsonl、task.json;.trellis/tasks/archive/2026-07/07-03-onboarding-admin-launch/ 还保留了design.md与implement.md。以 implement.md 为例,可以直观看到复杂任务执行计划的标准形态:按功能域分组的勾选清单(如 Rust admin 模块、general.run_as_admin设置、命令边界、启动接线、Onboarding UI、发布说明)、验证命令清单(cargo fmt/cargo test/cargo clippy -- -D warnings/pnpm lint/pnpm tsc)、风险文件清单与回滚方案。
状态机视角:为什么 archive 是状态翻转点
workflow.md中注释明确了一个关键机制:任务状态从planning到in_progress再到completed,全程由task.py命令驱动。task.py create将状态写为planning;task.py start将其翻转为in_progress(同时写入会话级活动任务指针);task.py archive才写入completed并移动目录。也就是说,只有 archive 才是状态翻转动作,task.py finish仅清除活动任务指针而不改状态。因此当前活动任务的指针在 archive 后即失效,[workflow-state:completed]面包屑在当前实现中处于"DEAD"状态——归档调用同时移动了目录,解析器会丢失指针。
五、Step 4:记录会话日志——add_session.py的完整参数说明
会话日志记录的完整命令形式:
python3 ./.trellis/scripts/add_session.py \ --title "Session Title" \ --commit "hash1,hash2" \ --summary "Brief summary"--commit应使用 Phase 3.4 产生的工作提交哈希(可从 Step 1 的Recent commits或git log --oneline获取),不要包含 Step 3 产生的归档提交哈希。该命令执行后产生一个chore: record journal提交。
完整参数清单
从 add_session.py 的 argparse 定义可以整理出全部可选参数:
| 参数 | 说明 | 默认值 |
|---|---|---|
--title | 会话标题(必填) | 无 |
--commit | 逗号分隔的提交哈希列表 | -(表示无提交,规划类会话) |
--summary | 简要总结 | (Add summary) |
--content-file | 从文件读取详细内容 | 无 |
--package | 包名标签(如cli、docs-site),仅 monorepo 生效 | 从活动任务task.json.package推断 |
--branch | 分支名,省略时自动检测 | 自动检测 |
--no-commit | 跳过工作区变更的自动提交 | false |
--stdin | 显式启用从 stdin 读取详细内容 | false |
分支的解析优先级为:--branch命令行参数 → 活动任务task.json的branch字段 →git branch --show-current自动检测 → 省略。--package在单仓库项目中会被忽略并给出警告,在 monorepo 中则会用config.yaml的packages配置做校验。
日志文件的生成逻辑
add_session.py的写入逻辑(add_session.py)会先定位开发者的工作区目录.trellis/workspace/<developer>/,读取当前最新日志文件journal-N.md的路径与行数,并解析index.md中Total Sessions: N的当前会话编号(get_current_session用正则:\s*(\d+)匹配)。
关键行为:当日志文件超过max_journal_lines行(默认 2000)时,自动创建新文件journal-(N+1).md,并在新文件头部写入续接说明("Continuation from journal-N.md (archived at ~2000 lines)")。生成的新会话内容包含标准模板:
## Session {N}: {title} **Date**: {YYYY-MM-DD} **Task**: {title} ### Summary ### Main Changes ### Git Commits | Hash | Message | |------|---------| ### Testing ### Status ### Next Steps随后调用update_index更新index.md的三个自动化标记区块(@@@auto:current-status、@@@auto:active-documents、@@@auto:session-history),并自动将提交哈希格式化为反引号包裹的短哈希形式。
自动提交的范围控制
脚本的_auto_commit_workspace(add_session.py)体现了精心的范围隔离设计:它只 stage 当前开发者的日志文件 +index.md,以及仅当前活动任务目录(通过get_current_task解析),绝不git add整个.trellis/树,也绝不遍历所有活动任务目录——这是为了防止把并行窗口的脏任务目录混进本次会话提交(对应 issue #303)。当没有当前任务时,退化为只 stage 日志与 index,跳过所有任务目录。staging 完成后用git diff --cached --quiet检查是否真有变更,无变更则跳过提交。
自动提交行为受.trellis/config.yaml控制:
session_commit_message: "chore: record journal" # 会话自动提交信息 max_journal_lines: 2000 # 日志文件轮转阈值 # session_auto_commit: true # false 时只写文件、不碰 git当session_auto_commit为false时,脚本仍会把日志与 index 写入磁盘,但跳过所有 git 操作——适用于.gitignore排除.trellis/想保持本地的项目,或希望手动审查暂存内容的场景。
六、与整体工作流的衔接:收尾之前发生了什么
trellis-finish-work不是孤立命令,它位于完整工作流链条的末端。Phase 2/3 的标准流程为:trellis-implement(实现)→trellis-check(质量检查)→trellis-update-spec(规范更新)→ Phase 3.4 提交 →/trellis:finish-work。在 Codex inline 模式下则是:trellis-before-dev→ 编辑 →trellis-check→ 校验 →trellis-update-spec→ 提交 →/trellis:finish-work。
收尾前必须满足的质量门禁(来自 workflow.md Phase 1.5 完成标准):
prd.md存在;- 用户确认任务进入实现阶段;
task.py start已执行(状态为in_progress);- 复杂任务必须有
design.md与implement.md; - 子代理分发平台要求
implement.jsonl与check.jsonl各自至少有一条真实条目(种子_example行不计)。
此外,Phase 3.3 的规范更新(trellis-update-spec)必须在提交前完成——workflow.mdPhase 3.4 的"规范同步前言"要求:如果本次任务修复了 bug 或产生了非显而易见的知识,应当先回到 3.3 写进.trellis/spec/,让规范写入与任务代码落在同一次提交批次中,而不是事后补记。
七、收尾流程的边界与注意事项
综合技能文档与仓库实现,有几点需要特别留意:
finish-work不负责代码提交。代码提交必须已在 Phase 3.4 完成,收尾流程只做归档与日志记录;发现未提交的当前任务代码时,正确动作是中止收尾并引导回到 Phase 3.4,而不是在收尾时补提交。--commit只用工作提交哈希。Step 3 产生的归档提交哈希不应混入会话日志的--commit参数,否则最终提交顺序会被破坏。- 归档提交与日志提交有明确的前后顺序:
<工作提交>→chore(task): archive ...→chore: record journal,这是workflow.md强调的三段式提交纪律。 - 并行窗口保护:
add_session.py的自动提交只覆盖当前开发者日志与当前任务目录,get_context.py --mode record的输出也足以让 AI 区分当前任务与并行工作,收尾流程应始终尊重这一边界。 - 配置文件的开关效果:
session_auto_commit: false会关闭归档/日志的自动 git 提交(文件照写、git 不碰),适合.trellis/本地化管理的项目;需要手动 review 暂存内容的项目也可开启。
掌握上述四步流程与底层脚本机制后,你就能在 EcoPaste 这类由 Trellis 管理的仓库中,安全、一致地完成每一次会话收尾——先盘状态、再查脏路径、后归档、终记录,让任务状态机与 Git 历史始终保持清晰可控。
- 桌面应用
- 开发工具
【免费下载链接】EcoPaste
🎉跨平台的剪贴板管理工具 | Cross-platform clipboard management tool
相关推荐
EcoPaste 仓库 Trellis 工作流收尾命令(finish-work)实战指南:任务归档与会话日志记录的完整流程
EcoPaste 仓库 Trellis 工作流收尾命令(finish work)实战指南:任务归档与会话日志记录的完整流程 导读 Trellis 是一套面向 A
桌面应用EcoPaste 代码质量检查工作流:从 Trellis-check Skill 到仓库级规范落地
EcoPaste 代码质量检查工作流:从 Trellis check Skill 到仓库级规范落地 在 EcoPaste 仓库中, .cursor/skills
桌面应用开发工具Home Manager 发布说明编写指南:rl-*.md 文档规范与迁移影响评估
Home Manager 发布说明编写指南:rl .md 文档规范与迁移影响评估 发布说明(Release Notes)是 Home Manager 面向用户在
桌面应用开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考