MMSP-RFC-0001 RFC 流程
- Feature Name:
rfc_process - Start Date: 2026-10-19
- RFC PR: #265
- Updated by: #285, #298, #301
- Kind: process
Abstract
采纳 design/:MMSP 遵守的每项规范,以及每个修改协议或公开 API 的决定,都是一篇 RFC,一篇只记一个决定,合并它的 PR 即为采纳。现行的规范就是已采纳的 spec 类 RFC,索引见 design/README.md;除此之外,没有别处再陈述这些规范。
1. Introduction
MMSP 要遵守的规则原先写在 mmsp-dev skill 里,写法是操作指南:怎样实现一个客户端,同一条里夹着每个客户端都要保证的事。不变量和当下的做法之间没有界线,贡献者无从知道哪句话能随改动调整。
决定也没有持久的记录。变更记录只写改动做了什么,并且按规定不把理由写进仓库;理由写在 PR 描述里,后来的读者得先知道该打开哪个 PR。
项目负责人举的例子:任何客户端都不能因为思考级别而抛出异常。这是对每个调用方的承诺,不是编码技巧,而它能否成立,只取决于每个新客户端的作者有没有读到 skill 里对的那一条。项目负责人还要求,这类规则要像其他决定一样议定,一条规则一篇 RFC,而不是另写一份原则文件。
2026-10-24,项目负责人要求 RFC 规范软件里需要固定下来的一个概念、协议或算法,并像 IETF RFC 那样以名词为题(RFC 8200,"Internet Protocol, Version 6 (IPv6) Specification"),而不是陈述一条规则。原话是:「RFC 应该是讨论一些软件里必须固定下来的概念、协议、定律、算法,比如 IETF RFC-8200: IPv6 Specification 的标题就是名词。」本文的形式,以及每一篇规范的形式,都依此而定。
2. Conventions and Terminology
本文中的关键词“必须”“不得”“应当”“不应”“可以”依次对应 BCP 14(RFC 2119、RFC 8174)中的 MUST、MUST NOT、SHOULD、SHOULD NOT 与 MAY,按其定义解释;本文只在这一含义上使用这五个词。spec 类 RFC 中,描述代码行为的句子用 MUST 或 MUST NOT,SHOULD 与 SHOULD NOT 只用于对调用方与贡献者的要求。RFC 的中文对照把这些关键词依次写作 必须、不得、应当、不应 与 可以。
- Spec:固定代码遵守的一个概念、协议或算法的 RFC。
- Change:修改协议或公开 API 的 RFC。
- Process:说明这个目录如何运作的 RFC。
- Accepted(已采纳):PR 已合并的 RFC 的状态。
- Superseded(被取代):已采纳、后来又被另一篇 RFC 取代的 RFC 的状态,写作
Superseded by MMSP-RFC-NNNN。
3. 文档
- 目录结构:
design/README.md(索引与流程)、design/0000-template.md(只有英文)与design/rfcs/MMSP-RFC-NNNN-<slug>.md;除模板外,每个文件都有.zh.md对照版本。目录中只放 Markdown,因此 CI 把对它的改动归为文档改动,不运行模型测试。 - 小节:
spec类 RFC 包含 Abstract、Introduction、Conventions and Terminology、以名词命名的编号正文各节,以及 Conformance,后者在文件层面列出保证它成立的模块与测试。change与process类 RFC 包含 Abstract、Introduction 与 Rust RFC 的各节,全部编号。无话可说的小节直接省略。 - 语言:模板中的节名在两份文件中都保持英文;
spec类 RFC 正文各节的标题在中文对照中翻译,两份文件靠节号逐节对齐。 - 阅读:修改客户端之前,先读
design/README.md中的索引:类别为spec、状态为「已采纳」的行就是现行的规范。
4. 生命周期
- 发起:修改规范、消息或流的结构、公开 API、路由或凭据规则的含义,或者任何会破坏调用方的改动,都从 RFC 开始:把
0000-template.md复制为design/rfcs/MMSP-RFC-NNNN-<slug>.md,设定它的类别,写好它和它的中文对照,向dev提交 PR。新模型、遵循既有模式的客户端、缺陷修复这类改动,仍然提普通 PR;完整的清单与步骤见design/README.md。 - 生命周期:PR 打开即提议,合并即采纳,关闭即撤回。
design/README.md中的索引为每篇已采纳的 RFC 列一行,写明类别与状态,状态为「已采纳」或「被 MMSP-RFC-NNNN 取代」;这一行由 RFC 自己的 PR 添加。规范只能经由一篇spec类 RFC 修改:它完整陈述修改后的规范,并取代旧的那篇;取代旧 RFC 的 RFC,在同一个 PR 中更新旧文件的元数据与索引中旧的那一行。实现某篇change类 RFC 的 PR 加上它的Implementation PR一行。 - 优先级:代码与已采纳的 RFC 不一致时,以 RFC 为准:要么修正代码,要么先取代这篇 RFC。
- 元数据:
Feature Name、Start Date、RFC PR、Kind,适用时还有Updated by(process类 RFC 采纳之后修改过它的 PR)、Supersedes、Superseded by与Implementation PR;PR 链接写完整 URL。 - 变更记录:RFC 的 PR 附一条
process类型、Scope 为design的记录;实现 PR 附自己的记录,并链接这篇 RFC。
5. 编号
RFC 取目录与未关闭的 PR 都没有用过的下一个 MMSP-RFC-NNNN,编号永不复用。例外是 2026-10-24 的两次重新分配,都出自项目负责人的要求。#298 按项目负责人给出的标题顺序,把各条规则依次编为 MMSP-RFC-0002 到 MMSP-RFC-0013。#301 随后把它们重写为九项规范 MMSP-RFC-0002 到 MMSP-RFC-0009,新增 MMSP-RFC-0010,并给每一篇一个名词标题,顺序同样出自项目负责人。内容按下表迁移:
| 0.5.5 的编号 | 第一次重编号(#298) | 内容现在所在 |
|---|---|---|
| MMSP-RFC-0002 所有模型共用一套协议 | MMSP-RFC-0002 消息协议须统一 | MMSP-RFC-0002;MMSP-RFC-0009 §6(顺序) |
| MMSP-RFC-0003 同一套流语法,由基类收尾 | MMSP-RFC-0003 请求须异步流式(流语法);MMSP-RFC-0005(IncompleteStreamError) |
MMSP-RFC-0003 |
| MMSP-RFC-0004 路由是显式的 | MMSP-RFC-0006 客户端路由须显式;MMSP-RFC-0011(版本匹配) | MMSP-RFC-0005;MMSP-RFC-0003 §6 |
| MMSP-RFC-0005 凭据只发往它被指定的地方 | MMSP-RFC-0007 保护密钥安全 | MMSP-RFC-0006 |
| MMSP-RFC-0006 每个思考级别在每个客户端上都可用 | MMSP-RFC-0010 支持全部思考等级 | MMSP-RFC-0003 §6 |
| MMSP-RFC-0007 被拒绝的值抛出有类型的错误 | MMSP-RFC-0009 异常要有类型 | MMSP-RFC-0007 |
| MMSP-RFC-0008 回传最小化,fidelity 是例外通道 | MMSP-RFC-0004 消息结构保持精简;MMSP-RFC-0005(tool_call_id、不带签名的思考) |
MMSP-RFC-0002 §5;MMSP-RFC-0004 |
| MMSP-RFC-0009 两个包,一份契约 | MMSP-RFC-0002 消息协议须统一 | MMSP-RFC-0002 §6 |
| MMSP-RFC-0010 每条流都以用量和结束原因收尾 | MMSP-RFC-0005 重要字段不能丢弃 | MMSP-RFC-0003 §5 |
| MMSP-RFC-0011 思考经往返转换不丢失 | MMSP-RFC-0005 重要字段不能丢弃 | MMSP-RFC-0004 |
| MMSP-RFC-0012 转换直白,不带冗余 | MMSP-RFC-0013 实现代码须直观;MMSP-RFC-0004(不带冗余) | MMSP-RFC-0009;MMSP-RFC-0002 §5 |
| — | MMSP-RFC-0008 历史消息不改变 | MMSP-RFC-0004 §6 |
| — | MMSP-RFC-0012 允许中断请求 | MMSP-RFC-0008 |
| — | — | MMSP-RFC-0010,新增 |
网站把前两套编号下的每个旧网址,都重定向到现在承载其内容的文档。
6. 指引与网站
- 指引:
AGENTS.md与 mmsp-dev skill 说明具体怎么做,其中服务于某篇 RFC 的规则以(MMSP-RFC-NNNN)注明。AGENTS.md写明这个目录以及何时需要 RFC;mmsp-dev skill 要求修改客户端之前先读这些规范;README 链接这个目录。 - 网站:
/rfcs/的 RFCs 区直接用仓库中的design/README.md与每一篇design/rfcs/MMSP-RFC-*.md以两种语言渲染,因此新增一篇 RFC 就多一个页面,不必修改网站代码。
7. Drawbacks
改动之前要多读一处文档,而且规范分散在多个文件里,不在同一页上;要一眼看全,靠的是索引。规范可能与代码脱节:每句话写下时都对照过代码,但之后的改动可能让某句话失效,直到有人在评审时把两者对照着读。
8. Rationale and Alternatives
- 像 penguin-harness-design 那样,在 RFC 之外另设一份原则文件:项目负责人没有采用。那样会有两份文档陈述规范,一份作为现状,一份作为决定;一项规范一篇 RFC 时,陈述规范的文件就是做出这个决定的文件,而索引就是现状。
- 把规则写在 skill 里:不采用。skill 是操作指南,每加一个客户端都会改;规范只因决定而改变。两者分开,skill 才能引用规范。
- 另建一个设计仓库,再用软链接接入:不采用。MMSP 是一个仓库、两个包,工作树很多,每个工作树都要建一遍链接。
- 在文件里设状态字段:不采用。PR 的状态就是 RFC 的状态;索引只记录读者从文件本身看不出的那一件事,即后来有没有别的 RFC 取代了它。
- 架构决策记录(ADR):它的简短格式(背景、决定、后果)与当初的规则 RFC 很接近;
change类 RFC 保留 Rust 的节次,因为原先缺的正是备选方案与先例。 - 规范性关键词:RFC 8200 本身用小写的 must 与 should;MMSP 采用 BCP 14 的大写形式,因为每一句规范性语句都要对照代码核查,大写的 MUST 能逐条核查,小写的 must 只是行文。
9. Prior Art
- Rust RFC:模板,以及一篇只记一个决定的做法。
- IETF RFC:名词标题、Abstract、编号的小节与 BCP 14;形式上以 RFC 8200 为范本。
- Prism-Shadow/penguin-harness-design(私有仓库):
PRN-NNN原则与PRFC-NNNNRFC 并列。本流程保留 RFC,不设原则文件。 - 架构决策记录。
- Python PEP:刻意没有照搬它的状态流转。
10. Unresolved Questions
Conformance 小节是否保留。它列的是文件,而文件会移动;目前保留,因为它告诉读者去哪里核对一项规范。
11. Future Possibilities
增加一项 CI 检查,确认每个 Conformance 小节列出的路径都存在,并且每篇 spec 类 RFC 在索引中都有一行。