get-shit-done 的 gsd:phase 命令:ROADMAP.md 阶段全生命周期管理实战指南
2026/9/8 19:14:36 网站建设 项目流程

get-shit-done 的 gsd:phase 命令:ROADMAP.md 阶段全生命周期管理实战指南

【免费下载链接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.项目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done

导读

gsd:phase是 get-shit-done(简称 GSD)中用于管理ROADMAP.md阶段(Phase)的单一整合命令,覆盖阶段的新增、插入、删除、编辑四种 CRUD 操作。本文围绕 commands/gsd/phase.md 展开,结合仓库中 get-shit-done/workflows/ 四个配套工作流与 SDK 查询层源码,讲解四种模式各自的路由规则、参数格式、校验门禁、对.planning/目录结构与状态文件的副作用,并给出可直接复制的命令用法。读完后你将掌握如何在里程碑执行过程中安全地增删改阶段、用十进制编号插入紧急任务而不重排既有阶段,以及这些操作底层经由gsd-sdk query的调用链路。

一、命令定位与模式路由

在 GSD 中,ROADMAP.md 以"里程碑(Milestone)→ 阶段(Phase)"的层级组织工作,每个阶段通常对应一个整数编号(如 72)。开发过程中阶段的调整非常频繁:里程碑末尾追加规划工作、执行中插入紧急修复、清理已取消的远期阶段、修订阶段描述等。gsd:phase把这些散落在不同命令中的操作收敛为一个入口,通过首个参数旗标自动路由到对应工作流:

旗标动作路由工作流用途
(无旗标)在里程碑末尾追加新整数阶段add-phase常规规划
--insert在指定阶段后插入十进制阶段(如 72.1)insert-phase紧急插单
--remove移除未来阶段并重排其后续阶段remove-phase清理/取消
--edit就地修改既有阶段的任意字段edit-phase修订描述

命令参数提示为[--insert | --remove | --edit] <phase-name-or-number>。解析逻辑(见 commands/gsd/phase.md 的<context>段)非常简单:

  • 首个 token 是--insert:剥离旗标,将剩余参数(格式<after-phase-number> <description>)交给 insert-phase 工作流;
  • 首个 token 是--remove:剥离旗标,将阶段编号交给 remove-phase 工作流;
  • 首个 token 是--edit:剥离旗标,将phase-number [--force]交给 edit-phase 工作流;
  • 其余情况:全部参数视为阶段描述,交给 add-phase 工作流。

需要强调的是:命令本身不直接读写文件。其<execution_context>声明了四个待加载的工作流文件(在本仓库中对应 add-phase、insert-phase、remove-phase、edit-phase),而 ROADMAP 与项目状态都在工作流内部通过init.phase-op查询和定向读取解析,命令层面的要求是"保留目标工作流的全部校验门禁"。

二、默认模式:在里程碑末尾新增阶段

2.1 用法与参数

不带旗标调用即进入 add-phase 模式,所有参数拼成阶段描述:

/gsd:phase Add authentication # 描述 = "Add authentication" /gsd:phase Fix critical performance issues

若未提供任何参数,add-phase 工作流会输出错误与用法说明并退出:

ERROR: Phase description required Usage: /gsd-add-phase <description> Example: /gsd-add-phase Add authentication system

2.2 初始化与底层委托

工作流先加载阶段操作上下文(与--insert/--remove/--edit共用同一初始化路径):

INIT=$(gsd-sdk query init.phase-op "0") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi

检查initJSON 中的roadmap_exists,若为 false 则报错并提示先执行/gsd:new-project初始化:

ERROR: No roadmap found (.planning/ROADMAP.md) Run /gsd:new-project to initialize.

随后将添加操作整体委托给 SDK:

RESULT=$(gsd-sdk query phase.add "${description}")

SDK 查询处理器承担了全部脏活(见 sdk/src/query/phase-lifecycle.ts 中phase.add处理器及注释"Query handler for phase.add"):查找当前最高整数阶段号、计算下一编号(max + 1)、由描述生成 slug、创建阶段目录.planning/phases/{NN}-{slug}/、向 ROADMAP.md 插入含 Goal / Depends on / Plans 小节的新阶段条目。调用方从结果中提取phase_numberpaddednameslugdirectory

源码实现中还提到并发安全设计:注释明确说明phase.add需处理"两次并发调用同时观察到同一最大编号"的竞态场景(见 sdk/src/query/phase-lifecycle.ts),这是直接把原 JS 工具phase.cjs移植为 TypeScript 查询处理器时保留的行为。

2.3 状态同步与收尾

新阶段落盘后还需把演变记录写进.planning/STATE.md:在## Accumulated Context → ### Roadmap Evolution下追加- Phase {N} added: {description},若该小节不存在则创建。完成时向用户呈现摘要:

Phase {N} added to current milestone: - Description: {description} - Directory: .planning/phases/{phase-num}-{slug}/ - Status: Not planned yet Roadmap updated: .planning/ROADMAP.md

并提示下一步/clear后执行/gsd:plan-phase {N}开始规划该阶段。注意:add-phase 的验证清单(success_criteria)要求phase.add执行成功、目录已建、ROADMAP 已更新、STATE.md 已记录,且不自动提交——何时 commit 由用户决定。

三、--insert:十进制编号插入紧急阶段

3.1 设计动机

里程碑进行到一半发现必须立刻处理的紧急工作时,若直接追加到末尾会打乱规划的依赖顺序,若整体重排又会造成大规模改写。insert-phase 采用十进制编号(72.1、72.2)方案:紧跟在目标整数阶段之后插入,既保持既有整数阶段的逻辑顺序,又无需重排整份路线图。

/gsd:phase --insert 72 Fix critical auth bug # after = 72 # description = "Fix critical auth bug"

缺参或首参非整数时给出明确报错:

ERROR: Both phase number and description required Usage: /gsd:phase --insert <after> <description> Example: /gsd:phase --insert 72 Fix critical auth bug

3.2 插入逻辑与 (INSERTED) 标记

初始化仍走gsd-sdk query init.phase-op "${after_phase}"并检查roadmap_exists。随后委托:

RESULT=$(gsd-sdk query phase.insert "${after_phase}" "${description}")

SDK 处理器负责:校验目标阶段存在于 ROADMAP.md、在磁盘上检查已有十进制编号并计算下一个编号、生成 slug、创建.planning/phases/{N.M}-{slug}/目录、在 ROADMAP.md 目标阶段之后插入条目并加(INSERTED)标记以标识这是紧急插单(区别于计划性阶段)。

3.3 状态指针更新:不可裸写 STATE.md

与 add-phase 不同,插单会改变"当前执行指针",因此需要更新 STATE.md 的 next-phase 指向。关键在于工作流明确规定:必须经由 SDK handler,绝不可直接使用Edit/Write裸写——项目可能内置protect-files.shPreToolUse 钩子拦截对 STATE.md 的直接写入。正确做法是:

gsd-sdk query state.patch '{"Current Phase":"{decimal_phase}","Next recommended run":"/gsd:plan-phase {decimal_phase}"}'

(字段名需按 STATE.md 实际暴露的指针字段调整,handler 会回报其实际匹配到的字段。)

再经由专门的演进记录 handler 追加条目——它会在## Accumulated Context下自动创建### Roadmap Evolution小节并对相同条目去重:

gsd-sdk query state.add-roadmap-evolution \ --phase {decimal_phase} \ --action inserted \ --after {after_phase} \ --note "{description}" \ --urgent

预期响应形如{ added: true, entry: "- Phase ... (URGENT)" },重放时则返回{ added: false, reason: "duplicate", entry: ... }。验收条件(见 insert-phase)明确覆盖了这两种响应形状与state.patch的字段匹配结果。

3.4 反模式红线

insert-phase 的<anti_patterns>列出一组硬性约束,值得在此完整保留:

  • 不要用它做里程碑末尾的计划性工作(那应走/gsd-add-phase);
  • 不要在 Phase 1 之前插入(十进制 0.1 无意义);
  • 不要重排既有阶段;
  • 不要改动目标阶段自身的内容;
  • 不要在此阶段就创建计划(那是/gsd:plan-phase的职责);
  • 不要自动提交(由用户决定提交时机)。

插入完成提示用户检查"Phase {next_integer} 的依赖是否仍然成立",并建议先/gsd:plan-phase {decimal_phase}规划该紧急阶段。

四、--remove:移除未来阶段并自动重排

4.1 只允许移除"未来阶段"

remove-phase 仅允许删除尚未开始的远期阶段,同时支持整数与十进制编号:

/gsd:phase --remove 17 # 移除 Phase 17 /gsd:phase --remove 16.1 # 移除 Phase 16.1

初始化通过gsd-sdk query init.phase-op "${target}"返回phase_foundphase_dirphase_numbercommit_docsroadmap_exists等字段。随后用 STATE.md 中的当前阶段号做护栏:目标必须大于当前阶段号,否则报错并建议:

ERROR: Cannot remove Phase {target} Only future phases can be removed: - Current phase: {current} - Phase {target} is current or completed To abandon current work, use /gsd:pause-work instead.

4.2 确认与委托删除

删除影响范围大,因此先展示摘要并要求 y/n 确认:

Removing Phase {target}: {Name} This will: - Delete: .planning/phases/{target}-{slug}/ - Renumber all subsequent phases - Update: ROADMAP.md, STATE.md Proceed? (y/n)

确认后整体委托给 SDK:

RESULT=$(gsd-sdk query phase.remove "${target}")

SDK 处理器一次性完成全部联动:删除阶段目录;按逆序重排后续所有目录以避免冲突;重命名被重排目录内的全部文件(PLAN.md、SUMMARY.md 等);更新 ROADMAP.md(移除对应小节、重排所有阶段引用、修正依赖);更新 STATE.md(递减阶段计数)。调用方从结果提取removeddirectory_deletedrenamed_directoriesrenamed_filesroadmap_updatedstate_updated

若目标阶段已产生执行过的计划(存在 SUMMARY.md 文件),SDK 会直接报错;只有在用户明确确认后,才可追加--force

RESULT=$(gsd-sdk query phase.remove "${target}" --force)

4.3 git 提交即历史记录

与其他模式"不自动提交"不同,remove-phase 会主动提交,因为 git 提交就是删除行为的唯一历史凭证:

gsd-sdk query commit "chore: remove phase {target} ({original-phase-name})" --files .planning/

同时其反模式强调:不要往 STATE.md 里补写"已移除阶段"的备注(git 提交即记录);不要手工重排——phase.remove处理器已处理全部重排;不要动已完成的阶段目录。只有--force才能越过"含 SUMMARY.md 的已执行阶段"守卫。

五、--edit:就地编辑阶段字段

5.1 用法、守卫与状态映射

编辑模式的口号是"编号与位置永远不变,只改字段":

/gsd:phase --edit 5 # 编辑 Phase 5 /gsd:phase --edit 5 --force # 允许编辑 in-progress/completed 阶段 /gsd:phase --edit 12.1

流程先以init.phase-op加载上下文并检查 ROADMAP 存在性,再用roadmap get-phase读取目标阶段:

PHASE_DATA=$(gsd-sdk query roadmap get-phase "${target}")

found为 false 则报错并建议用/gsd:progress查看可用阶段。从结果中提取phase_namegoalsuccess_criteriasection(保留 depends_on、requirements、plans 等的完整原文段),并需从原文段额外解析depends_on(兼容**Depends on:****Depends on**:两种写法)与requirements

关键安全门禁在状态检查:通过gsd-sdk query roadmap analyze获取每个阶段的磁盘状态disk_status,再映射为友好状态:

  • completecompleted
  • planned/partialin_progress
  • emptyno_directorydiscussedresearchedfuture

若阶段处于in_progresscompleted且未传--force,直接拦截——因为编辑进行中或已完成的阶段可能使已执行的计划失效;传了--force则打印 WARNING 继续。

5.2 两种编辑路径

先展示当前值(Title / Goal / Depends on / Requirements / Success Criteria 列表),再让用户在三种选项中抉择:

[1] Edit specific fields (title, goal, depends_on, requirements, success_criteria) [2] Regenerate all fields from a clarified intent [3] Cancel
  • 路径 [1] 逐字段编辑:选择字段后逐项提问,只有显式作答的字段才进入更新集合,空答案保持原值
  • 路径 [2] 由澄清意图整体重写:让用户描述修订后的意图,据此重新生成简明标题、完整 Goal、更新后的 requirements(原有用到才生成)、3~5 条可度量的 success_criteria;depends_on除非用户明确提及,否则保留不动

5.3 depends_on 校验与 diff 确认

任何depends_on更新(或保留非空值)都要校验:先roadmap analyze拿到全部合法阶段号集合,对每个引用做规范化(去空白、去 "Phase" 前缀),再检查它存在于合法集合且不等于自身。任一引用非法即拒绝写入:

ERROR: depends_on references invalid phase(s): {bad_refs} Valid phase numbers: {valid_list} Fix the depends_on field and try again.

随后构建更新后的阶段小节,按字段类型精确替换(标题替换Phase {N}:后的文本、Goal 替换**Goal:**行值、depends_on/requirements 替换或补建对应行/块、success_criteria 替换编号列表、整体重写则重建整个小节),并展示 unified 风格 diff:

Proposed changes to Phase {target}: --- current +++ updated @@ ... - **Goal:** {old_goal} + **Goal:** {new_goal} ... Apply these changes? (y/n):

用户确认后才写回。写回要求精确定位阶段小节## Phase {N}:### Phase {N}:标题),只替换该段原文,前后内容(其他阶段、里程碑标题、汇总清单)一律不动;不允许未先读取就对 ROADMAP.md 裸写。写回后同样通过state.add-roadmap-evolution --action edited --note "edited fields: ..."记录演变。

编辑模式的反模式强调:绝不改编号与位置;只编辑一个阶段时不动其他阶段;不跳过 depends_on 校验;不展示 diff 并获得确认前绝不写盘;不--force编辑进行中/已完成阶段;不修改阶段目录结构;不自动提交。

六、源码级原理:init.phase-op 与查询处理器

命令之所以能"四合一"还保持每种操作的校验完整性,底层依赖 SDK 查询层的两大机制:

  1. 统一初始化init.phase-op:四个工作流第一步都执行gsd-sdk query init.phase-op "<phase>",在 sdk/src/query/init.ts 中对应initPhaseOp处理器(从原init.cjs移植)。它复用findPhase查找目录(带归档降级:若唯一匹配来自已归档里程碑,则优先以当前 ROADMAP 为准,见shouldDropArchivedPhaseMatch逻辑),并通过roadmapGetPhase对比路线图条目。roadmap_exists字段在多个初始化点都由existsSync(join(planningDir, 'ROADMAP.md'))计算(见 sdk/src/query/init.ts),是各工作流"没有路线图先建项目"守卫的数据来源。

  2. 集中式查询处理器注册:按 sdk/src/query/QUERY-HANDLERS.md 的查询族清单,phase族注册了phase.addphase.add-batchphase.insert等多个 handler;phase.add等具体实现集中在 sdk/src/query/phase-lifecycle.ts,并继承了原get-shit-done/bin/lib/phase.cjs的语义(该文件头部注释即写明"Ported from ...")。因此从架构上可以推断:gsd:phase系列命令与phase族查询形成了"瘦命令(只做路由)→ 厚工作流(编排与校验)→ 查询处理器(原子化落盘)"三层结构,任何单点逻辑(编号计算、slug 生成、目录/文件重排、ROADMAP/STATE 联动更新)都被收敛在处理器内复用,保证四个入口行为一致。

七、使用建议与边界提醒

  • 编号即语义:整数编号是规划性阶段的稳定标识,十进制编号专门留给里程碑中途的紧急插单;不要试图用--insert做常规追加,也不要为了清理而让十进制阶段长期滞留路线图——对确已无用的插单阶段,用--remove(支持十进制编号)在规划前移除即可。
  • --force是最后手段:无论编辑还是删除,--force只在用户明确确认对"进行中/已完成"阶段动刀时才使用,因为那可能使已执行计划失配。
  • 自动提交范围:仅 remove-phase 会主动 commit(其删除动作本身就是历史记录);add/insert/edit 均把提交决定留给用户。
  • 依赖一致性:插单和编辑都可能影响既有阶段依赖(depends_on),删除则自动重排后续编号并修正依赖;编辑模式内置了引用合法性校验,手动改 ROADMAP 时请参照同一约束。

本文涉及的四种工作流文档位于 get-shit-done/workflows/,命令路由规则见 commands/gsd/phase.md,相关测试可参考 sdk/src/query/phase.test.ts 与 sdk/src/query/phase-lifecycle.test.ts,可据此进一步验证各模式在仓库中的实际行为契约。

【免费下载链接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.项目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询