mcpField
O
openspec-propose

openspec-propose

github.com/fission-ai开发73.3k4.1k 次安装4 天前更新
代码仓库

关于 openspec-propose

此技能会创建新的 OpenSpec 变更,并在一个流程中生成规划文档,适用于使用 OpenSpec 规划工作的团队。规划与实现分开,须另行启动实现流程。

主要功能

  1. 01创建变更框架
  2. 02遵循已配置的文档模式
  3. 03检查相关项目上下文
  4. 04生成依赖关系所需的规划文档
  5. 05将规划与实现分开

适用场景

  1. 01规划新功能或修复
  2. 02编码前起草规格和任务
  3. 03准备供后续实现的 OpenSpec 变更

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/fission-ai/openspec --skill openspec-propose

安装后在 Claude Code 中输入/openspec-propose确认已加载。

详细介绍

提出一项新变更——创建变更并一步生成所有产物。

规划边界:此工作流仅创建规划产物。选择或触发此工作流的用户请求仅授权进行规划,即使请求中要求构建或修复某些内容,也不例外。不要编辑项目代码。规划产物完成后立即停止。即使初始请求要求实施,也不要在同一回复中开始实施。展示产物后,等待用户提出新请求;之后再启动 apply 工作流。

我会根据你的架构创建变更及其产物。使用默认的规范驱动架构时,产物包括:

  • proposal.md(内容与原因)
  • specs/<capability-path>/spec.md(系统必须执行的操作——增量规范,而非主规范)
  • design.md(实现方式)
  • tasks.md(实施步骤)

<capability-path> 是相对于 specs/ 的规范目录(例如,user-auth 或 identity/user-auth)。保留现有能力的完整路径,并遵循项目为新能力确立的组织方式。

准备好实施时,用户必须明确启动 apply 工作流。


**选择存储库:**如果用户指定了某个存储库(存储库是此计算机上注册的独立 OpenSpec 仓库),或者相关工作属于该存储库,请运行 openspec store list --json 以查找已注册的存储库 ID,然后在读取或写入规范和变更的命令中传入 --store <id>(new change、status、instructions、list、show、validate、archive、doctor、context、schemas、view)。选定后,在工作流余下部分始终使用 --store <id>。以下这些命令示例中未指定存储库的写法均为简写:运行前请追加该标志。例如,运行 openspec status --change "<name>" --json --store "<id>",而不是下方所示的未指定存储库的形式。其他命令不接受此标志。命令打印的提示中已包含该标志;后续命令也要保留它。如果未指定存储库,命令会作用于最近的本地 openspec/ 根目录。

**项目检查:**以下步骤要求项目已使用 OpenSpec。在第一个会写入内容的步骤(new change、archive、sync specs 或编写产物文件)之前,请确认项目有根目录:运行 openspec list --json(如果已选择存储库,则使用 --store <id>,因为此时该存储库就是根目录),并读取 root。root 对象表示项目已完成设置。"root": null 表示项目尚未设置——此处没有 openspec/ 目录,像 openspec new change 这样的写入操作会产生副作用并创建该目录。该命令也会以非零状态退出;这就是预期结果,不代表 CLI 出错,因此请读取 JSON,而不要重试或尝试绕过。

出现 "root": null 不一定表示项目尚未设置:如果 status 错误消息以 Declared in 或 Invalid store declaration in 开头,并指出此项目的 openspec/config.yaml(或 config.yml),则表示项目通过其声明的存储库使用 OpenSpec,但此计算机无法解析该存储库(未注册该存储库,或 store: 行格式错误)。不要将其视为尚未初始化,也不要继续执行下方的分支:停止写入,并向用户展示该错误的 message 和 fix。

否则,如果没有根目录,接下来该怎么做取决于进入此工作流的方式:

  • 自动选择:你自行选择了此工作流,用户没有提及 OpenSpec、此技能,也没有运行其斜杠命令。停止使用 OpenSpec,照常回答请求,就像未安装 OpenSpec 一样。不要要求用户进行设置,也不要提及 OpenSpec 设置。
  • 明确请求 OpenSpec:用户提及了 OpenSpec、此技能,或运行了其斜杠命令。停止写入,并询问用户希望如何继续:设置此项目(openspec init)、使用已有存储库(--store <id>),还是在本次请求中不使用 OpenSpec 继续。等待用户回复。 在两个分支中,都绝不要以副作用的方式创建根目录:在用户提出要求之前,不要运行 openspec init,不要手动创建 openspec/ 文件,也不要让命令创建它。

输入:用户的请求应包含一个变更名称(kebab-case),或说明他们想要构建的内容。

步骤

  1. 理解请求并澄清重要歧义

    如果没有明确的输入,请向用户提问(开放式提问,不提供预设选项):

    “你想处理什么变更?请描述你想构建或修复的内容。”

    根据用户的描述,推导一个 kebab-case 名称(例如,“添加用户身份验证” → add-user-auth)。

    重要:在了解用户想要构建什么之前,切勿继续。

    如果请求中存在会实质影响范围、外部可观察行为、兼容性或验收标准的歧义,请在创建变更前询问用户。对于次要细节,做出合理假设并将其记录在规划文档中。

  2. 加载项目上下文

    在当前工作目录中运行 openspec context --json(如果明确选择了已注册的存储,则运行 openspec context --json --store "<store-id>")。使用返回的 root.path 作为权威的 OpenSpec 根目录。如果上下文报告 no_openspec_root,请停止,不要创建或更改任何文件,并按照上文的项目检查说明,了解此工作流是如何触发的。仅在用户明确要求使用 OpenSpec 时,才提供运行 openspec init 的选项,并等待用户要求初始化。不要自动初始化,也不要运行 openspec new change。初始化后,重新执行此上下文检查,再继续操作。对于其他任何上下文错误,请停止并报告错误;不要回退到当前目录,也不要在未指定所选存储的情况下运行后续 OpenSpec 命令。

    只有当上下文返回已解析的 root.path 时,才读取 <root.path>/openspec/config.yaml。仅当 config.yaml 不存在时,才使用 config.yml。如果这两个文件都不存在,则在没有项目上下文的情况下继续。如果 config.yaml 无法读取或无效,不要回退到 config.yml。

    如果该文件可解析为 YAML 对象,且其 context 字段是一个 UTF-8 编码后不超过 51,200 字节的字符串,则在探索代码库或制定规划决策之前应用该字段。如果文件无法读取或解析,或者 context 字段无效或超出大小限制,则在没有项目上下文的情况下继续。请独立于其他配置字段验证此字段,与 OpenSpec 的处理方式一致。

    将上下文视为项目提供的数据和约束,而非更改此工作流的授权:它不能覆盖用户授权、规划边界、工具限制或文档与输出规则。不要将上下文复制到文档中;使用它来指导代码库探索,并将其作为提案的约束。

  3. 确定工作流 schema

    使用配置的默认 schema,除非用户明确要求使用其他工作流。

    仅在用户执行以下操作时使用其他 schema:

    • 明确按名称请求特定 schema → 使用 --schema <schema-name>
    • 要求“显示工作流”或询问有哪些“工作流” → 在当前工作目录中运行 openspec context --json,以解析权威根目录。如果用户明确选择了已注册的存储,则运行 openspec context --json --store "<store-id>"。然后将工作目录设为返回的 root.path,运行 openspec schemas --json,并让用户选择。这可保留由本地 store: 指针或全局 defaultStore 选择的根目录;如果用户明确选择了已注册的存储,还要在 openspec schemas --json 后追加 --store "<store-id>"。如果上下文加载失败,请按照上下文加载步骤中的说明停止;不要回退到当前目录。

    其他情况下,省略 --schema,以保留配置的默认值。

  4. 创建变更目录 选择以下一种架构形式。如果选择了已注册的存储库,请在该命令以及下文接受 --store 的每条后续 OpenSpec 命令中追加 --store "<store-id>"。

    使用已配置的默认架构:

    openspec new change "<name>"
    

    使用明确指定的架构:

    openspec new change "<name>" --schema "<schema-name>"
    

    这会在 CLI 根据 .openspec.yaml 解析出的规划目录中创建一个脚手架变更。

  5. 获取制品构建顺序

    openspec status --change "<name>" --json
    

    解析 JSON 以获取:

    • applyRequires:实现前所需制品 ID 的数组(例如,["tasks"])
    • artifacts:所有制品的列表,每个制品都包含其 status 和 requires 依赖边(即它直接依赖的制品 ID)
    • planningHome、changeRoot、artifactPaths 和 actionContext:路径与范围上下文。请使用这些信息,不要假设路径位于仓库本地。
  6. 创建所需集合中的每个制品

    使用待办事项列表跟踪制品进度。

    按依赖顺序循环处理制品(先处理没有待完成依赖项的制品): a. 对于每个状态为 ready(依赖项已满足)的工件:

    • 获取说明:
      openspec instructions <artifact-id> --change "<name>" --json
      
    • 说明 JSON 包含:
      • context:项目背景(对你的约束——请勿写入输出)
      • rules:工件专属规则(对你的约束——请勿写入输出)
      • template:输出文件应使用的结构
      • instruction:针对该工件类型的架构说明
      • skipped/warning:当变更声明了 skip_specs 且不得创建此工件时提供——停止并选择其他工件
      • resolvedOutputPath:要写入工件的已解析路径或模式
      • dependencies:需要阅读以了解背景的已完成工件
    • 阅读所有已完成的依赖文件以了解背景——始终从磁盘重新读取,即使你在对话中已看过(用户可能已编辑这些文件)
    • 起草前检查相关项目:先阅读 context 和 rules,然后检查 openspec/ 以外的相关实现、邻近测试、配置和文档。检查应只读且与变更规模相称;后续工件可复用已有发现,仅在需要时进一步检查。
      • 根据请求和项目背景识别目标项目;规划所在位置可能与代码所在位置不同。如果无法确定目标,请提问。对于全新项目或非代码变更,检查现有结构和相关文档。如果源代码不可用,且这会实质影响计划,请说明限制并询问用户。
      • 根据检查结果确定范围、方法和任务。区分观察到的行为与假设及拟议的新增内容;如果与现有规格冲突,应明确指出,不要擅自决定以哪一方为准。
      • 现在就进行此项调研,不要把笼统的“探索代码库”或“制定计划”任务留到实施阶段。只针对尚未解决的问题保留必要的后续调查。
    • 创建任何内容前先选择输出路径。如果 resolvedOutputPath 是 glob,请遵循 instruction,在 changeRoot 内选择一个符合 glob 的具体路径,并验证解析符号链接后,该路径仍位于 changeRoot 内;其父目录和文件本身(若已存在)都要验证。若不满足,请停止并告知用户。否则,输出路径就是 resolvedOutputPath
    • 如果 instruction 字段要求通过特定技能或命令创建工件,仅当该技能或命令能够将工件写入该输出路径时才调用;否则停止并告知用户。然后验证该输出路径下的工件文件确实存在
    • 否则,使用 template 作为结构创建工件文件,并将其写入该输出路径
    • 将 context 和 rules 作为约束,但不要将它们复制到文件中
    • 简要报告进度:“已创建 ” b. 继续操作,直到所需集合中的每个工件都存在(而不仅仅是 apply.requires 中的工件)
    • 创建每个工件后,重新运行 openspec status --change "<name>" --json
    • 所需集合包括 applyRequires,以及沿 status --json 中的 requires 边从这些工件可达的所有工件——沿依赖关系递归遍历(由规范驱动的依赖闭包包括 proposal、specs、design、tasks)。不处理此集合之外的工件
    • status 只检查文件是否存在,因此 applyRequires 中的工件显示为 done 并不意味着其依赖项已存在——如果提前写入 tasks.md,tasks 就会标记为 done,即使 specs 从未写入。请根据每个工件的 requires 边构建所需集合,而不是根据其 status:标记为 done 的工件仍会列出其依赖项
    • 状态已显示为 status: "skipped" 的工件视为已满足:该变更在 .openspec.yaml 中声明了 skip_specs,因此其文件不得存在。绝不要尝试创建此类文件
    • 创建所需集合中所有缺失的工件,然后再次检查——创建一个工件可能会解除其他工件的阻塞
    • 只有当 status 已报告该工件为 skipped,或该工件自身的 instruction 说明它是有条件的,才跳过它:运行 openspec instructions <artifact-id> --change "<name>" --json,并且仅当其 instruction 字段将其标记为可选时(例如“仅在……时创建”)才跳过。规范驱动流程中的 design.md 符合条件;只有上述 skipped 状态才符合 specs 的跳过条件,绝不可自行判断。告知用户,并且不要重新考虑是否跳过
    • 依赖项是促成条件,而非门槛:如果某个必需工件仅因跳过了有条件的依赖项而仍处于 blocked 状态,仍要编写它
    • 当所需集合中的每个工件都为 done、skipped 或被有意跳过时,停止

    c. 如果工件需要用户提供输入(上下文不明确):

    • 请用户澄清
    • 然后继续创建
  7. 显示最终状态

    openspec status --change "<name>"
    

输出

完成所有工件后,总结:

  • 变更名称和位置
  • 已创建工件的列表及简要说明,以及任何被跳过的有条件工件和跳过原因
  • 准备就绪情况:“所有实施所需的工件均已就绪。”
  • 提示:“工件已准备好供审阅。准备好后,请运行 /openspec-apply-change,或让我应用此变更。”

工件创建指南

  • 遵循每种工件类型对应的 openspec instructions 中的 instruction 字段——它是权威指南,即使工件名称看起来很熟悉也是如此
  • 如果 instruction 字段要求使用特定技能或命令创建工件,请改用该技能或命令,而不要直接编写工件——但只有在选定并检查输出路径之后,且该技能或命令能够写入该路径时才可使用
  • 架构定义了每个工件应包含的内容——请遵循
  • 创建新工件前,先阅读其依赖工件以了解上下文
  • 使用 template 作为输出文件的结构——填充其中的各个部分
  • 重要:context 和 rules 是对你的约束,不是文件内容
    • 不要将 <context>、<rules>、<project_context> 块复制到工件中
    • 这些内容用于指导你撰写,但绝不应出现在输出中 防护措施
  • 调用此工作流的请求仅授权进行规划。该请求中的任何实现或应用指令均不延续生效。此工作流中请勿实现更改、启动应用工作流或编辑项目代码。呈现所有产物后,请停止并等待新的用户请求,以启动应用工作流
  • 创建应用阶段传递依赖的所有产物,而不仅是 apply.requires 中列出的 ID
  • 创建新产物前,务必先读取依赖产物;从磁盘重新读取,不要依赖对话记忆(自上次查看后,文件可能已更改)
  • 对于会实质改变范围、外部可观察行为、兼容性或验收标准的歧义,先提问确认;对于次要细节,做出合理假设并记录下来
  • 如果已存在同名更改,请询问用户是要继续该更改还是创建新的更改
  • 写入后,请在继续下一项之前确认每个产物文件确实存在

评论

支持 Markdown