mcpField
A
add-feature

add-feature

github.com/plainlang开发8042 次安装2 天前更新
代码仓库

关于 add-feature

用于逐项向现有 `.plain` 规格添加功能的工作流技能。它引导编写者确认意图、逐次提出聚焦问题、增量修改,并处理冲突及最终一致性检查。

主要功能

  1. 01编辑前确认功能意图
  2. 02每轮提出一个聚焦问题
  3. 03将修改交由专用编写技能处理
  4. 04通过明确选项解决冲突
  5. 05执行最终规格健康检查

适用场景

  1. 01向现有 `.plain` 项目添加功能
  2. 02通过增量提问细化行为
  3. 03在意图变化时保持相关规格一致

安装

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

$npx skills add https://github.com/plainlang/plain-forge --skill add-feature

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

详细介绍

添加功能

请先加载规则。 在读取、编辑或编写任何 .plain 文件之前,调用 load-plain-reference 技能,并阅读它指引你查看的规则文件。只有在本次对话中已运行 load-plain-reference 时,才可跳过此步骤。

add-feature 是 forge-plain 的持续循环版本。forge-plain 从头开始搭建整个项目,而 add-feature 则为一组现有的 .plain 规格添加单个功能。它从简短的意图阶段开始,然后针对单个功能运行编写循环。

核心循环:一个问题 → 一个回答 → 写入磁盘

此循环在阶段 0 之后开始。每次迭代只包含一个问题,随后立即写入:

  1. 提问:通过 AskUserQuestion 提出一个重点明确的问题——绝不捆绑两个问题。问题应确保任何合理的回答都能直接对应一个可写入的片段:单一行为、概念、属性、边缘情况或约束,而不是开放式设计问题。不好的问法:“这个功能应该如何运行?”好的问法:“用户提交空标题时,是否应以 HTTP 400 拒绝请求、接受请求并使用默认标题,还是采用其他方式?”只要答案范围可预测,就提供具体选项,并附上自由回答选项。
  2. 立即编写:用户一回答,就将片段写入磁盘(应路由到哪个技能,见 2b)。不要等到“上下文足够”才写;尽早写入正是此流程的目的。第一次尝试写出的片段有误是预期之内的——下一个问题会进行修正,而且用户每一步都能准确查看当前进展。
  3. 在下一个问题中完善:下一个问题通常会扩展或修正刚刚写入的内容。

每次调用只问一个问题,但要根据主题需要深入追问。“一个问题”限制的是 AskUserQuestion 调用,而不是主题。如果回答含糊不清或仍留有实际选择空间,下一个问题就应针对同一主题深入追问——这是循环中的又一次迭代——直到答案具体到可以写入为止。过早停止并基于含糊的回答写入,比多问一个重点明确的后续问题更糟。

就地修正矛盾。 如果后续回答完善或否定了磁盘上已有的片段,请立即编辑该片段。绝不要让过时的意图留在磁盘上;如有实质性变更,应在下一个问题中说明。

输入

用户提出的功能请求——可以是一句话(“添加深色模式”),也可以是详细描述。阶段 0 会将其整理为经确认的功能意图摘要;阶段 2 则会在编写过程中进一步明确行为。

阶段 0 — 功能意图

阅读 references/phase-0-intent.md。逐个提出其中的五个核心问题,不要写入磁盘;将回答整理成功能意图摘要,并获得用户明确确认。如果回答过于含糊,最多提出一个重点明确的澄清问题。

在之后的每个阶段中都要保留已确认的摘要。继续之前,内联检查 references/checklist.md 中的阶段 0 部分。

阶段 1 — 范围

保持简短。目标只是掌握足够的信息,以便提出第一个可写入的问题,而不是先在纸面上设计整个功能。

  1. 阅读已确认的功能意图摘要。 确定该功能最可能归属的现有 .plain 文件。
  2. 阅读目标 .plain 文件,沿着其 import 和 requires 链,以及模块的测试 plain 文件,了解现有定义、实现要求、功能规格、测试要求和场景。这样阶段 2 在发现影响时才能识别出来。
  3. 仅当要修改哪个文件确实存在歧义时,用一个问题选定目标模块。否则跳过此步骤并立即开始编写。

一旦目标文件和一个具体的起始问题明确,就立即结束阶段 1。此处不要提出确定方向、界定范围或包含多个部分的设计问题。

阶段 2 — 单问题循环

这是一个不断重复的周期:恰好提出一个问题,然后立即写入。用户表示功能已涵盖完整时,循环结束。

2a. 提出一个问题

每次调用 AskUserQuestion 时,只提出一个可写入的问题,且只针对以下其中一项:

  • 行为 — 一个触发条件及其结果。
  • 一个概念 — 一个新概念,或现有概念的一个属性。
  • 一个边界情况 — 一个无效输入、空状态或边界值。
  • 一个约束 — 一条业务规则、权限、顺序要求或大小限制。
  • 实现指导 — 影响功能构建方式的策略(重试、错误处理、数据格式),或文件及其导入项中尚未出现的技术、库或模式。
  • 验证 — 仅当满足下方的 符合性门槛 时:一个能证明此功能正常工作的具体结果。

绝不在提示中捆绑第二个问题;绝不提出答案无法单独转化为可写入片段的问题。

2b. 立即写入

将每个答案交由相应的编辑技能处理 — 绝不手动编写 ***plain 部分:

  • 新概念 → add-concept(写入 ***definitions***;先定义,再引用)。
  • 新功能规范 → add-functional-spec。它会为你运行 analyze-if-func-spec-too-complex 和 analyze-func-specs — 交由它处理。绝不手动编写功能规范。 如果它报告规范过于复杂,就提出后续问题让用户拆分(在下一轮中提出)— 不要自行拆分。
  • 已更改的功能规范 → 在原处编辑其陈述行或 - 项,然后调用 add-test-scenarios,使其测试 plain 文件与新文本一致。
  • 新的实现要求 → add-implementation-requirement。当答案说明了功能的构建方式 — 重试或错误处理策略、数据格式、库、架构模式 — 且文件及其导入项中尚未包含这些内容时使用。
  • 新的测试场景 → 对该功能的测试 plain 文件调用 add-test-scenarios。仅当满足 符合性门槛 且答案描述了具体验证时使用。
  • 新的测试要求 → add-test-requirement。仅当已配置符合性测试,且答案会改变符合性测试的运行方式时使用。

如果答案与先前片段矛盾或对其作出细化,立即在原处修正该片段(参见上文的 就地修正矛盾)。

2c. 及时处理冲突

如果 add-functional-spec(通过其分析器)报告冲突,或者刚写入的片段会破坏(与之矛盾、使之失效)或扩展(改变其含义、增加行为)现有概念/功能规范/实现要求/测试要求/测试场景,那么下一个问题必须针对该冲突。将现有片段原文放入问题,并提供以下选项:

  • (a)保留现有规范 — 撤销或缩小刚写入内容的范围,
  • (b)扩展现有规范 — 将提议的新措辞纳入问题,
  • (c)替换现有规范。

用户一回答就立即应用其选择。如果用户扩展了某个概念,则遍历所有引用该概念的规范,并在原处逐一更新,且仅限于已批准的范围。绝不悄悄改写先前的意图。

2d. 决定下一步

询问用户该功能是否已全面覆盖。是 → 进入阶段 3。否 → 返回 2a,提出下一个单独的问题。

符合性门槛

只有当项目的 config.yaml 中有有效的 conformance-tests-script 条目,且该条目指向 test_scripts/ 中现有脚本时,才编写 ***test reqs*** 和测试 plain 文件。检查涵盖此模块的 config.yaml(多部分项目可能有多个),并确认引用的脚本确实存在。如果未配置符合性测试,则完全跳过这两种编写路径 — 概念、功能规范和实现要求仍照常编写。

阶段 3 — 最终审查

大多数检查已在循环中完成;这是一轮精简的一致性检查,最后一个自动化步骤始终是 plain-healthcheck。

  1. 完整阅读修改过的 .plain 文件。
  2. 验证:
    • 每个新概念都在使用前定义,且没有循环引用。
    • 全程的时间顺序正确——任何规范都不依赖于后续内容。
    • 功能规范与语言无关。
    • 每个外部接口都明确说明(端点路径、方法、CLI 参数、格式)。
    • 每项新增或变更的功能都有对应的测试 plain 文件,且其中的场景应源自其规范;启用一致性测试时,该文件必须存在,并且至少包含一个一致性测试场景。
  3. 展示修改文件的最终差异,并征得用户批准。
  4. 如果用户要求修改,立即直接回到单问题循环——一次提一个问题、写一项内容、修复一处问题。不要从头重启循环。
  5. 运行 plain-healthcheck——这是此技能运行的最后一项检查。它会验证每个 config.yaml,对每个顶层模块运行 plain-parser check,并根据规则检查每个模块,确保项目始终能够成功渲染。如果返回 FAIL,请按编号逐项处理(只修改 .plain 文件、config.yaml 或脚本,绝不修改生成的代码),然后回到循环中;修复后重新运行。重复此过程,直到返回 PASS。只有此时才能告知用户功能已准备好渲染为 <module>.plain。
  6. 默认渲染器:pyro。 询问用户是否现在要使用 pyro 的 render-spec 技能重新渲染 <module>(/render-spec <module>.plain;如果 pyro 作为 Claude Code 插件安装,则使用 /pyro:render-spec <module>.plain),并且只有在用户同意后才调用。如果当前会话没有可用的 render-spec 技能,请告知用户未安装 pyro,并提供安装说明:https://github.com/plainlang/pyro#installation。用户也可以使用任何其他 ***plain 渲染器进行渲染。

下一个功能

完成一项功能后,用户可以描述下一项功能。从阶段 0 重新开始——持续循环:意图 → 范围 → 单问题循环 → 最终审查 → 意图 → …

错误处理

  • 用户的回答与先前的规范相矛盾 → 立即在原处编辑受影响的片段;如果改动并非微不足道,请在下一个问题中说明。
  • add-functional-spec 报告“too complex” → 在下一轮循环中向用户提一个后续问题,以拆分该规范;绝不要自行拆分。
  • 出现冲突、破坏性变更或扩展需求 → 将其作为下一个问题(2c),并在继续之前解决。
  • plain-healthcheck 返回 FAIL → 不要宣布功能已完成;通过循环修复列出的 .plain、config.yaml 或脚本问题,并重新运行,直到返回 PASS。

验证清单

每轮都运行 references/checklist.md 中的循环部分,并在阶段 3 完成整份清单后再宣布功能完成。这是对工作流程的自我审查,绝不能替代工作流程本身。只有当规范已写入磁盘并获得明确批准时,才算完成相应项;完成前请处理所有未完成的步骤。

提问风格

  • 优先使用简短、直接的句子,避免复合或嵌套从句。
  • 如果普通词语和术语表达的含义相同,优先使用普通词语。
  • 每句话只表达一个意思;将用逗号串联的从句拆成独立句子。
  • 简化时绝不能省略细节——保留用户所需的每项约束、边界情况和选项,必要时拆成更多句子。

评论

支持 Markdown