mcpField
F
frame-a-proposal

frame-a-proposal

github.com/inkeep开发14228 次安装1 天前更新
代码仓库

关于 frame-a-proposal

frame-a-proposal 是一项将问题整理为可评审 RFC 提案的技能。它引导作者检索既有方案、界定问题、撰写设计与替代方案并进行校验;在撰写解决方案前设有确认环节。

主要功能

  1. 01检索相关提案和决策
  2. 02界定受益者、可观察变化与待决事项
  3. 03撰写动机、设计、缺点和替代方案
  4. 04记录未决问题、证据与负责人
  5. 05校验链接、章节和提案状态

适用场景

  1. 01从已识别的问题着手编写 RFC
  2. 02新建提案前检查既有方案
  3. 03梳理真实替代方案与设计权衡
  4. 04准备可评审草案但不推进其状态

安装

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

$npx skills add https://github.com/inkeep/open-knowledge-skills --skill frame-a-proposal

安装后在 Claude Code 中输入/frame-a-proposal确认已加载。

详细介绍

制定提案——将问题转化为可审阅的 RFC

/open-knowledge 平台技能仍然管辖此处的所有 markdown 操作(通过 exec/search 读取,通过 write/edit 写入,链接使用普通相对 markdown,绝不对适用范围内的文件使用原生 Read/Edit/Grep/cat)。此技能在此基础上叠加提案撰写技巧:它决定一份好的提案应包含什么,以及如何按顺序逐步完成各个部分。

proposals/ 中的提案是一种设计论证,不是决策,也不是计划。它旨在促使大家在多个选项中做出选择,并为评审者提供充分依据以便提出异议。文件名为 0001-feature-name.md——由零填充的 4 位序号和 kebab 风格标题组成。状态流转为 draft → fcp → accepted/rejected(fcp = 最终评论期)。提案获批后,会晋升为 decisions/ 中的一条记录——这是一个独立的人工操作,也需要使用独立的技能。

此技能旨在防止以下失败情形:Agent 在大家尚未就问题达成一致前就跳到 ## Design,在 ## Alternatives 中塞满稻草人选项,并将 ## Drawbacks 留空。下面的每个步骤都有一道关卡来避免这种情况。


必须遵循的执行顺序

硬性关卡——切勿跳步。 如果你正准备起草 ## Design,但尚未通过步骤 1 的问题界定关卡,请停止——你跳过了一道关卡。提案的核心意义,就是先就问题达成一致,再撰写解决方案。

  1. 梳理先例——了解 proposals/ 和 decisions/ 中关于此子系统已有的内容。
  2. 界定问题——停止关卡。 明确受益者、可观察到的变化和必须做出的决策。在撰写任何解决方案内容前,先征求确认。
  3. 分配序号并基于 proposal 模板创建文件。
  4. 动机——问题、证据、当前受影响的人、什么都不做的代价,以及明确的非目标。
  5. 设计——将提案描述到足以让读者提出异议的程度。
  6. 备选方案——至少提出两个切实可行的方案,并分别说明不选它们的原因。
  7. 缺点——坦诚说明代价。
  8. 未决问题——一份持续更新的待办清单,每项都列明解决责任人和解决所需的证据。
  9. 添加链接并验证。
  10. 回顾总结,并说明推进到 fcp 需要满足什么条件。

如果宿主的任务系统支持,请为步骤 0–9 创建工作流任务——这样在会话中途就能发现被跳过的关卡。


步骤 0:梳理先例

在界定问题前,先查明知识库对这个子系统已经做过哪些决策或提案。悄悄重新讨论已获批决策的提案注定会被否决;引用该决策并解释为何应重新审视它的提案则是合理的。

  • search({ query: "<subsystem or problem keywords>" })——语义搜索,可匹配同义词。
  • exec("ls -A proposals/") 和 exec("ls -A decisions/")——查看序号分配情况和已落地的内容。
  • exec("grep -rln <keyword> proposals/ decisions/")——找出提及同一子系统的文件。
  • 对最相关的 1–3 条结果,使用 exec("cat proposals/0003-x.md") 阅读完整文档及其反向链接。

对发现的内容进行分类,并在草稿中体现:

发现应采取的行动
某项已获批的决策涵盖此领域新提案 MUST 引用该决策(使用指向 decisions/ 的 markdown 链接),并在“动机”中说明发生了什么变化,使该决策需要重新审视。如果没有任何变化,请告诉用户这可能根本不需要提案。
某项草稿/fcp 提案存在重叠提议扩展或取代该提案,而不是另开一份近似重复的提案。两份重叠提案会分散评审意见。
没有相关内容直接继续。

步骤 1:界定问题 — STOP 门槛

这是区分 RFC 与一堆解决方案文本的关键门槛。在用户确认问题界定之前,不要起草 ## Design,也不要创建文件。

生成并原样返回以下内容,然后停止并等待:

## Framing (confirm before I draft)

**Beneficiary:** who is worse off today and will be better off if this ships. A named role or user, not "the system" or "us".

**Observable change:** the concrete, checkable difference they will see. "X drops from N to M", "Y becomes possible", "Z stops happening". Not "improve", not "streamline".

**Forced decision:** the one question this proposal makes reviewers answer. If accepting it doesn't commit anyone to anything, it is a report, not a proposal.

**Rough shape:** one sentence on the direction — enough to know we're framing the right problem, not the design itself.

纪律:

  • 如果你无法说出一个不同于“团队”的受益者,就说明问题尚未界定清楚。起草前应提出异议。
  • “可观察的变化”必须可证伪,否则就不算完成。如果你说不清如何检查,那你描述的是一项活动,而不是一个结果。
  • 触发条件含糊(“我们应该为缓存准备一份提案”)?把范围缩小:为了谁、由什么决策推动、改变他们能观察到的什么。
  • 在明确的无头/非交互式运行中,说明问题界定并继续,但要将这三个字段逐字写入 Motivation,以便审阅者可以直接否决问题界定本身。

步骤 2:分配编号并从模板创建

列出顺序,不要猜。 exec("ls -A proposals/"),找出已存在的最大 NNNN,加一,并补零至四位。猜编号迟早会撞车,尤其是同一周起草两个提案时。

文件名:NNNN-kebab-title.md(0007-async-export-pipeline.md)。从模板创建文件——只有这样,## Motivation → ## Design → ## Drawbacks → ## Alternatives → ## Unresolved questions 骨架和 frontmatter 才能正确生成:

write({ document: { path: "proposals/0007-async-export-pipeline.md", template: "proposal" } })

模板会生成以下 frontmatter——填写它,不要手动重新输入:

type: proposal
description: "..."     # one line: the forced decision, not the feature name
status: draft          # stays draft until a human advances it — see Non-goals
authors: [<user>]
created: YYYY-MM-DD
tags: [proposal]

将 description 设为提案要促成的决策,用一行写明——读者在列表中看到的就是它。


步骤 3:Motivation

通过 edit 编辑已创建的文档,填写 ## Motivation。本节必须能够独立成立:在这里有异议的读者永远不会读你的 Design,而这正是应该的。

  • 问题,从受益者的体验出发来陈述,而不是描述缺少了什么解决方案。“超过 100MB 的导出会超时,用户会丢失任务”胜过“我们没有异步导出流水线”。
  • 证明问题真实存在的证据:指标、反复出现的报告或具体事件。仅以“这样会更好”为动机的提案,动机不足;应向用户说明这一点,并找到一个信号。
  • 当前受到影响的人,明确指出(即步骤 1 中的受益者),并说明影响发生的频率。
  • 不采取行动的代价——这是衡量所有替代方案(包括“拒绝此提案”)的现状基线。如果不采取行动确实没有问题,那么这份提案可能就没有存在的必要。
  • 明确列出非目标。 列出本提案有意不解决的问题。非目标能让提案便于审阅;范围无边界的提案无法被接受,因为没人能判断自己究竟同意了什么。在 Motivation 内用清晰的 ### Non-goals 行列出它们。

步骤 4:Design

在 ## Design 中填写实际提案,以读者能够提出异议的粒度来阐述。过于细致(每个函数签名)会让审阅者对未经评估的设计照单全收;过于笼统(“我们会让它更快”)则没有任何可接受的内容。目标是让有能力的读者读完本节后能说:“不,我会用另一种方式做,因为……”

  • 描述机制、变更的形态,以及引入或调整的关键接口或契约。
  • 明确说明起决定作用的选择。如果设计依赖某一项决策(数据模型、边界或顺序),就把它点明——这通常才是整份提案真正讨论的内容。
  • 说明如何实现步骤 1 中的可观察变化。将设计与受益者联系起来。
  • 以普通的相对 Markdown 格式链接相关规范、指南,以及你所依据或重新审视的决策:[the export boundary decision](./decisions/0004-export-boundary.md)。
  • 不要写实现层面的细枝末节——这种粒度属于规范的工作(一个配套的 skill),而非提案。

第 5 步:备选方案

在 ## Alternatives 中填写至少两个真实选项,并说明为什么没有选择。加入那些在另一天你可能会选择的诚恳选项;如果该决策已经生效,也要加入“不采取行动”。

每项的结构如下:

### Alternative: <name>
What it is — one honest paragraph, argued at its best.
Why not — the specific tradeoff that lost, versus the proposed design.

要求:

  • 稻草人方案是危险信号——要明确指出。 如果 Alternatives 部分中的每个选项都明显更差,说明作者没有考虑真正的方案,评审者会(正确地)不信任整个提案。如果你无法说清某个备选方案真正吸引人的地方,就说明你还没有充分理解它,不足以将其否决。
  • “不采取行动”是一个正式的备选方案。它的“为什么不选”就是第 3 步中不采取行动的代价。
  • 合适的数量通常是 2 到 4 个。只有一个,说明你不是在提出方案,而是在宣布决定。

第 6 步:缺点

在 ## Drawbacks 中填写所提设计本身的真实代价——而不是其他方案的代价。

  • 没有缺点的提案,说明审视得还不够充分,而不是完美无缺。 每个真正的设计都会有所取舍:复杂性、迁移工作、新的故障模式、维护负担,或一道关闭的门。请明确列出。
  • 具体说明由谁、在何时承担代价——付出代价的一方可能与受益方不同,评审者需要了解这种取舍。
  • 如果你确实认为某项缺点可以接受,请在这里说明原因,而不是将它隐藏起来。明确说明并接受的缺点,比评审者后来才发现的隐患更有说服力。

第 7 步:未解决的问题

将 ## Unresolved questions 填写为待处理事项清单,而不是免责声明。每项都应让一个真实的待解问题清晰可见,而不是将它埋在自信满满的文字里。

每个问题的结构如下:

- **<question>** — What would resolve it: <the evidence, experiment, or measurement>. Who decides: <role or person>.
  • 每个问题都要说明什么证据可以解决它以及由谁决定。两者皆无的问题只是焦虑;请将它具体化,或删除。
  • 阻碍提案获批的问题必须明确列在这里——它们将成为 fcp 阶段的议程。
  • 处于 draft 状态时,本部分不为空是合理的。为了显得已经完成而隐藏不确定性,才是问题所在;诚实列出未解决的问题,才能让提案便于安全评审。

第 8 步:添加链接并验证

在告诉用户提案已准备就绪之前,先完成以下工作:

  • 所有引用的决策、规范或指南都必须使用普通的 Markdown 相对链接([text](./decisions/0004-x.md)),绝不能用反引号包裹,也不能使用 HTML 锚点。
  • 从 1 到 2 篇密切相关的文档中添加反向链接,让读者能够找到该提案——例如它重新审视的已采纳决策、相关规范或适用指南。使用 links({ kind: "backlinks", ... }) 查看现有的反向链接。
  • audit({ path: "proposals/0007-async-export-pipeline.md" }) 返回无问题(即不存在 lint 违规或内部链接失效)——修复所有发现的问题。
  • Frontmatter 完整:type: proposal、一行描述 description、status: draft、authors、created、tags: [proposal]。
  • 五个 H2 部分均须存在且内容非空:## Motivation、## Design、## Drawbacks、## Alternatives、## Unresolved questions。Drawbacks 为空或 Alternatives 中包含稻草人方案,即使相应部分在形式上存在,也无法通过此项检查。
  • status 仍为 draft。不要推进状态——请参阅“非目标”。

第 9 步:总结并说明进入 fcp 的路径

在对话中与用户一起完成收尾:

## Recap

- Framed: <beneficiary> gets <observable change>; forces the decision <…>.
- Proposal: proposals/NNNN-title.md (status: draft)
- Alternatives weighed: <n>, chosen over them because <one line>.
- Honest drawbacks: <the main one>.
- Open questions still live: <count> — the fcp agenda.

**To advance to `fcp`:** a human moves status draft → fcp and opens the final comment
period. Acceptance (→ accepted, then a record in decisions/) is a human decision, not
mine. If it's rejected, mark status: rejected and keep the doc — the reasoning is the value.

明确说明,推进状态和采纳提案是由人来决定的。你的工作到此为止:产出一份论证诚恳、框架清晰的 draft。

非目标

  • 不要记录决策。 提案获批后,会成为 decisions/ 中的一条记录——这是同级的 /record-a-decision 技能,应在人类接受提案 之后 运行。此技能止步于 draft。
  • 不要编写实现规范。 关注设计层面,而非构建细节。规范由 /write-a-spec 编写。
  • 不要擅自将提案标记为 accepted(或 fcp)。 推进状态是人类的行为。保留 status: draft;说明推进状态需要什么。
  • 不要跳过步骤 1 的问题界定关卡。 在问题达成一致前撰写解决方案,正是此技能旨在防止的问题。如果你已经撰写了 Design,却没有确认受益者和必须做出的决策,就说明你跳过了关卡——请退回上一步。
  • 不要用稻草人充斥 Alternatives,也不要让 Drawbacks 留空。 这两点都表明提案并未经过真正审视。评审者也会如此看待。

评论

支持 Markdown