get-shit-done 阶段管理实战:用 /gsd-add-phase 为当前里程碑新增 Phase 的完整指南

发布时间:2026/9/10 15:43:40
get-shit-done 阶段管理实战:用 /gsd-add-phase 为当前里程碑新增 Phase 的完整指南 get-shit-done 阶段管理实战用 /gsd-add-phase 为当前里程碑新增 Phase 的完整指南【免费下载链接】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在 get-shit-doneGSD这套面向 Claude Code 的轻量级元提示与规格驱动开发系统中add-phase工作流负责在当前里程碑末尾追加一个整数编号的新阶段Phase它自动计算下一个阶段编号、创建阶段目录并把新阶段条目写入 ROADMAP.md。本文以 add-phase.md 为骨架逐段拆解参数解析、上下文初始化、SDK 委托执行、状态回写与完成摘要的完整链路并结合 phase-lifecycle.ts、phase-lifecycle-policy.ts 等源码讲清编号计算、slug 生成、命名模式与并发加锁的底层原理让读者既能直接上手使用该命令也能理解其内部实现机制。一、工作流定位向里程碑追加阶段的标准入口在 get-shit-done 的规划模型里项目Project→ 里程碑Milestone→ 阶段Phase是三层递进结构ROADMAP.md中按整数编号Phase 1、Phase 2……记录每个阶段的目标、依赖与计划。add-phase是“给当前里程碑补一段计划”的标准入口与insert-phase在既有编号之间插入、add-batch批量追加、remove删除、complete标记完成共同构成 command-manifest.phase.ts 中声明的phase.*命令族。从 add-phase.md 的 purpose 定义可以提炼出它的三个职责自动计算下一个阶段编号当前最大编号 1创建阶段目录.planning/phases/{NN}-{slug}/更新 ROADMAP.md 结构插入带 Goal、Depends on、Plans 的新阶段条目。工作流整体包含五个步骤parse_arguments→init_context→add_phase→update_project_state→completion每一步都有明确的退出条件与产物。下面逐段深入。二、第一步解析命令参数parse_argumentsadd-phase的参数模型非常简单所有位置参数拼接起来就是阶段描述命令本身不携带任何位置无关的开关。原文档给出两个示例/gsd-add-phase Add authentication→ description Add authentication/gsd-add-phase Fix critical performance issues→ description Fix critical performance issues也就是说多词描述会被自动以单个空格连接无需引号包裹。如果未提供任何参数工作流必须输出以下错误并立即退出ERROR: Phase description required Usage: /gsd-add-phase description Example: /gsd-add-phase Add authentication system在 SDK 侧这个“多词拼接”与“开关剥离”的规则由 phase-lifecycle.ts 的 flag 解析循环严格落地--raw被静默跳过CJS 路由层在调用 handler 前已剥离--raw这里保留是为了奇偶一致性避免误入描述--dry-run被识别为只计算不落盘的预览模式--id value被识别为自定义阶段 ID用于phase_naming: custom模式任何其他--flag都会抛出phase add does not support flag的校验错误剩余位置参数用positional.join( ).trim()拼成 description空描述纯空格或仅含被剥离的 flag会触发description required for phase add。值得注意的细节是自定义 ID 只能来自--id标志绝不能来自位置参数——注释明确写了customId comes from the --id flag, never from positional[1]这是为了防止“第二个词被误当成 ID”的歧义。三、第二步初始化阶段操作上下文init_context在真正写盘之前工作流先通过gsd-sdk的init.phase-op查询获取“阶段操作上下文”并特别检查roadmap_exists标志INIT$(gsd-sdk query init.phase-op 0) if [[ $INIT file:* ]]; then INIT$(cat ${INIT#file:}); fifile:前缀是 GSD SDK 处理超长 JSON 结果的机制当查询结果超过内联阈值时SDK 会把结果写入临时文件并以file:路径的形式返回调用方需要cat展开。这一步保证了即使上下文 JSON 很大也能可靠传递。如果roadmap_exists为false说明项目尚未初始化规划结构工作流输出ERROR: No roadmap found (.planning/ROADMAP.md) Run /gsd:new-project to initialize.随后退出。这是add-phase的前提校验——没有 ROADMAP.md就没有“当前里程碑”可言。在 SDK 实现中init.phase-op对应 init.ts 的initPhaseOphandler端口为 init.cjs 中的cmdInitPhaseOp。它接收一个 phase 参数这里的0表示不针对具体阶段加载项目配置并通过findPhase与roadmapGetPhase联合定位阶段信息其中还包含一个精妙逻辑如果唯一匹配到的阶段来自已归档里程碑则优先使用当前 ROADMAP 中的同名阶段shouldDropArchivedPhaseMatch避免归档内容误导当前上下文。返回结果携带phase_found、phase_dir、phase_number、phase_name、has_verification等字段供后续步骤使用。四、第三步委托 gsd-sdk 执行 phase.add核心这是整个工作流的枢纽。工作流把“找最大编号、算新编号、生成 slug、建目录、写 ROADMAP”这些脏活全部委托给 SDKRESULT$(gsd-sdk query phase.add ${description})原文档明确列出phase.add的 CLI 侧职责清单查找当前最高的整数阶段编号计算下一个编号max 1根据描述生成 slug创建阶段目录.planning/phases/{NN}-{slug}/向 ROADMAP.md 插入带 Goal、Depends on、Plans 的新阶段条目。调用成功后从结果中提取phase_number、padded、name、slug、directory五个字段供完成摘要展示。4.1 编号计算max 1 与 999.x 例外phase.add的 handler 是 phase-lifecycle.ts 中的phaseAdd其编号与目录计算逻辑集中在computePhaseFieldsL152-L176底层由 phase-lifecycle-policy.ts 的一组纯函数支撑scanSequentialMaxPhaseFromMilestoneL65-L75用正则Phase\s(\d)[A-Z]?(?:\.\d)*:扫描当前里程碑内容中的最高编号num 999直接跳过scanSequentialMaxPhaseFromDirsL81-L92扫描.planning/phases/目录名支持可选的项目代码前缀与小数后缀同样跳过 999.xcomputeNextSequentialPhaseIdL94-L99取里程碑内容与目录两者的最大值 1。这里有两个容易踩坑的设计要点999.x 是“积压通道backlog lane”保留区。编号 ≥ 999 的阶段被视为暂存/积压任务绝不能被计入“下一个编号”。phase.test.cjs 与 L989-L1009 都有对应测试即使磁盘上存在999-backlog-stuff之类的孤儿目录新阶段的编号也不会被抬高backlog 999.x orphan must not inflate phase count。目录与 ROADMAP 双源取最大。因为阶段目录可能先于 ROADMAP 条目创建或反之只取单一来源会漏算所以必须两边都扫。4.2 slug 生成确定性、小写、60 字符截断generatePhaseSlugphase-lifecycle-policy.ts把描述转成目录友好的 kebab-casetext.toLowerCase() .replace(/[^a-z0-9]/g, -) // 非字母数字连续段 → 单个连字符 .replace(/^-|-$/g, ) // 去掉首尾连字符 .substring(0, 60); // 截断到 60 字符例如Add authentication→add-authenticationFix critical performance issues→fix-critical-performance-issues。60 字符上限保证目录名不会因过长描述而失控。4.3 命名模式sequential 与 custom以及 project_code 前缀computePhaseDirectoryphase-lifecycle-policy.ts根据配置决定目录名支持两种模式sequential默认目录名为{prefix}{NN}-{slug}其中NN是String(phaseId).padStart(2, 0)补零后的两位数例如01-setup、02-auth-servicecustom配置phase_naming: custom或传入--id阶段 ID 取自--id值未提供时用 slug 的大写下划线形式目录名为{prefix}{ID}-{slug}例如feature-01-setup。注意custom 模式未提供--id时直接抛--id required when phase_naming is custom。此外若项目配置了project_code如XR目录名会带上该前缀产生XR-02-auth-service这种形式。CONFIGURATION.md 明确记载project_code自 v1.31 起作为“阶段目录名前缀”存在ABC产生ABC-01-setup/而phase_naming则是“自定义阶段目录前缀”设置后会覆盖自动生成的 slugfeature产生feature-01-setup/CONFIGURATION.md。前缀与 ID 都会经过assertSafePhaseDirName/assertSafeProjectCode校验杜绝非法字符注入。测试 phase.test.cjsbug-3287验证了完整链路当project_code为XR时phase add auth service必须产出phase_number: 2并创建XR-02-auth-service目录——这正是phase.add与init.phase-op的expected_phase_dir字段保持前缀一致性的回归防线。4.4 生成 ROADMAP 条目Goal / Depends on / PlansbuildPhaseRoadmapEntryphase-lifecycle-policy.ts生成插入 ROADMAP.md 的 Markdown 条目### Phase {N}: {description} **Goal:** [To be planned] **Requirements**: TBD **Depends on:** Phase {N-1} **Plans:** 0 plans Plans: - [ ] TBD (run /gsd-plan-phase {N} to break down)要点自动继承依赖只要当前是整数编号且 1Depends on自动指向Phase {N-1}custom 模式或编号 1 时不生成依赖行占位符齐全Goal、Requirements、Plans 计数均为待规划的占位等待后续/gsd-plan-phase {N}填充插入位置新条目被插入到最后一个---分隔符之前phase-lifecycle.ts 的lastIndexOf(\n---)逻辑找不到分隔符时追加到文件末尾——这样能保持“当前活跃里程碑块在最前、历史里程碑在后”的版式。4.5 并发安全跨整个读改写周期的锁阶段编号的“max 1”计算存在经典的并发竞态两个并发的phase.add若同时读到同一个 max就会生成重复编号。为此真实写路径非 dry-run把读取 ROADMAP → 计算 → 写入整体包进readModifyWriteRoadmapMd的锁内phase-lifecycle.ts该函数在 phase-roadmap-mutation.ts 中通过acquireStateLock获取锁文件跨越整个 read → transform → write 周期后释放——这正是源码注释所强调的two concurrent phase.add calls cannot both observe the same maxPhase and produce duplicate phase IDs。dry-run 模式则刻意不加锁因为不写盘不存在竞态在锁外计算并在结果中附带dry_run: true与完整的roadmap_entry预览方便 Agent 先确认再落盘。目录创建使用ensureDirectoryWithGitkeep写入.gitkeep让 Git 能跟踪空目录。4.6 结果结构无论哪种模式handler 都会返回统一的 JSON 结构phase-lifecycle.ts字段含义phase_number新阶段编号整数转字符串padded补零后的编号如02name原始描述slugkebab-case 目录 slugdirectory相对项目根的阶段目录路径POSIX 风格naming_modesequential或customdry_run/roadmap_entry仅 dry-run 时出现用于预览在注册层面phase.add挂在 command-family-handlers.ts 的phase族下并由 command-manifest.phase.ts 声明为mutation: true写操作、outputMode: json、别名phase add——因此命令行里gsd-sdk query phase.add ...与gsd-sdk query phase add ...等价。五、第四步更新项目状态update_project_state写盘之后工作流还需把这次变更记录进项目状态文件.planning/STATE.md保持“规划结构”与“状态叙事”一致读取.planning/STATE.md在## Accumulated Context→### Roadmap Evolution小节下追加一行- Phase {N} added: {description}如果Roadmap Evolution小节不存在则先创建它。这一步的意义在于GSD 的 STATE.md 是“项目记忆”的权威载体Roadmap Evolution记录了里程碑下阶段的演进历史后续的上下文注入、进度展示、恢复会话都会读取这里。只有 ROADMAP.md 与 STATE.md 双双更新新增阶段才算完整落地。六、第五步完成摘要与下一步引导completion工作流最后向用户输出标准化的完成摘要格式如下Phase {N} added to current milestone: - Description: {description} - Directory: .planning/phases/{phase-num}-{slug}/ - Status: Not planned yet Roadmap updated: .planning/ROADMAP.md --- ## ▶ Next Up — [${PROJECT_CODE}] ${PROJECT_TITLE} **Phase {N}: {description}** /clear then: /gsd:plan-phase {N} --- **Also available:** - /gsd-add-phase description — add another phase - Review roadmap ---摘要的设计意图很明确告知变更结果阶段编号、目录、状态“Not planned yet”——新阶段尚未规划给出唯一下一步动作/clear清空上下文后执行/gsd:plan-phase {N}进入规划流程这也与buildPhaseRoadmapEntry中占位符提示的/gsd-plan-phase {N}相互印证提供快捷入口继续/gsd-add-phase追加更多阶段或浏览 roadmap。七、成功标准与测试验证原文档给出的success_criteria是衡量该工作流是否真正完成的金标准gsd-sdk query phase.add执行成功阶段目录已创建ROADMAP.md 已插入新阶段条目STATE.md 已追加 roadmap evolution 记录已告知用户下一步动作这五条与仓库测试覆盖一一对应目录创建与编号计算见 phase.test.cjs999.x 跳过、L989-L1009孤儿积压目录不抬高编号、L3559-L3586project_code 前缀锁语义在phase-lifecycle.test.ts与并发测试中均有断言。此外工作流层面的约束也在测试中被固化——例如 phase.test.cjs 检查plan-milestone-gaps.md必须通过phase.add或expected_phase_dir创建带 project_code 前缀的目录禁止裸写mkdir .planning/phases/{NN}-{name}从源头杜绝绕过 SDK 的目录创建。八、与相关命令的协同边界add-phase是“追加到里程碑末尾”的唯一正规入口项目中其他工作流对它的引用也划清了使用边界insert-phaseinsert-phase.md明确注明不要用它处理里程碑末尾的计划工作那应该用/gsd-add-phase——insert 专用于在既有编号之间插入check-todoscheck-todos.md在把待办项升级为阶段时会生成/gsd-add-phase调用mvp-phasemvp-phase.md在拆解用户故事时把超出当前切片的剩余部分以/gsd add-phase列表形式呈现给用户由用户决定是否逐个创建——保证编号始终在用户掌控之中也印证了“add-phase 一次只加一个阶段、编号由系统自动维护”的核心约定。结语/gsd-add-phase看似只是一个“加一个阶段”的小命令其背后却是一整套工程化约束双源ROADMAP 目录编号扫描、999.x 积压保留区、sequential/custom 双命名模式、project_code 前缀一致性、跨读写周期的文件锁、dry-run 预览以及 ROADMAP/STATE 双文件同步。理解 add-phase.md 这份工作流文档等于同时掌握了 GSD 规划模型的写入口径与“如何安全地变更规划数据”的边界纪律。当你需要为当前里程碑追加新阶段时只需一条/gsd-add-phase description剩下的编号、目录与结构更新都会自动完成。【免费下载链接】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),仅供参考