契约优先(Contract-First / Consumer-Driven Contracts)

SkillAI & models

For projects developed across frontend/backend (or multiple services), use a single machine-readable contract referenced by CONTRACT.md; each side implements against it independently to prevent field drift causing blank screens at integration. Supports two modes: multiple agents in one session, and

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the 契约优先(Contract-First / Consumer-Driven Contracts) skill

What this skill tells your AI

The instructions your AI receives, as published by qshanx/docs-governance in skills/contract-first/SKILL.md and read by ahel’s review.

多端并行开发的项目(前端 + 后端,或再加多个服务),最容易炸在"连接"那一刻:

后端把 userName 改成 user_name,忘了通知前端。两边各自"自测通过",一集成——白屏。两份文档各自为真,合起来是假的。

契约优先把接口当成一份唯一机器契约(由 CONTRACT.md 登记入口):所有数据接口只定义一次,各端照它各做各的,谁都不许私自偏离。它和 living-docs-governance 是姊妹篇——那套防"项目文档"漂移,这套防"端与端之间的接口"漂移。

学名:这套就是 消费者驱动契约(Consumer-Driven Contracts, CDC)/ 契约测试(contract testing)。"消费方需求先行"=CDC 核心;"后端写返回符合契约的测试"=提供者验证(provider verification);标杆工具是 Pact,契约规格常用 OpenAPI/Swagger。

什么时候启用

  • 项目分前端 + 后端(或多个服务),且各端可能并行开发。
  • 接口字段老对不上:userName vs user_name、类型不符、枚举值不一致。
  • 某端为渲染一个页面要调 5 个接口拼数据。
  • 某端改了接口忘了通知别人,集成时才发现。

不要用在只有单端、不存在跨端集成的项目上——那时退化成单层,用 living-docs-governance 即可。接口少、单人、不会漂移时也别上,过度工程化。

两种协作模式(关键:选对你的现实)

这套契约协作有两种落地方式,纪律一致、组织方式不同:

模式 A — 单会话多 agent(中心化派活)

一个支持多 agent 的会话里,契约拥有者派出前端 / 后端(及更多服务工人)并行干活,最后由它集成对账。Claude Code 可使用 contract-director、frontend-dev、backend-dev;Codex 可由当前 agent 持有契约并使用内置 worker,任务提示中明确端别、文件所有权和“只读契约”的边界。适合一人一个会话内推进、需要实时编排时。

模式 B — 多终端各自跑(去中心化,契约当异步媒介)⭐ 更贴近真实团队

终端1 跑前端、终端2 跑后端、终端N 跑某个服务,各端完全独立、上下文隔离,没有一个活的主任在线派活。协调的唯一媒介就是那份 CONTRACT.md 文件:

  • "主任"在这里退化成"契约拥有者"——就是定契约、有权改契约那个人/终端(很可能是你本人或某个指定终端),不是实时调度器。
  • 各端要改接口时,不存在"喊一个在线 agent",而是提一条"契约变更请求":写进约定位置(如 Issue,或 PROJECT_LOG.md 追加一条 contract-request),由契约拥有者评估后更新契约,各端再各自重新拉取对齐。
  • 适合双终端/多终端、多人、跨时区——这才是大多数真实前后端团队的样子。

两种模式的铁律完全相同:接口只在 CONTRACT.md 指向的机器契约定义一次;各端只读不改;要改接口必须先改契约,绝不在实现里私自偏离。

宿主适配:Claude Code 的 /contract 与自定义 agents 是交互适配层;Codex / ChatGPT 直接调用 $contract-first 并由当前 agent 执行同一流程。没有可用子 agent 时退化为顺序执行,不得因此跳过契约前置、提供方验证或集成对账。

三条核心纪律

1. 契约是唯一真相源,只有一个拥有者,且分两层

将协作约定与机器定义分开,字段只保留一个来源:

  • 入口与协作层(CONTRACT.md):登记机器契约路径、版本/hash、拥有者、生成/校验命令和兼容策略;不手抄字段表。
  • 机器定义层:沿用项目已有 OpenAPI / JSON Schema / GraphQL / protobuf。HTTP 项目无现有契约时可用 templates/openapi.example.json;方法、路径、字段、类型、错误响应只在机器契约定义,重复类型用引用复用。

跨接口字段约束通过机器契约的公共 schema 或类型定义复用。所有接口只在 CONTRACT.md 指向的机器契约定义一次,各端只读;改契约的权力归契约拥有者(模式 A 是 director,模式 B 是指定的人/终端)。要改接口 → 提契约变更请求 → 拥有者改契约 → 各端再对齐。绝不在实现里单方偏离契约——这是头号集成杀手。

2. 消费方需求先行(CDC 核心:别让提供方拍脑袋定)

接口是给消费方(如前端)用的,先看消费方渲染/使用需要什么,再定接口形状,而不是照着数据库表结构透传。定契约时优先问:

  • 这个页面/调用方实际需要哪些字段?一次请求能不能拿全?
  • 字段类型有没有坑?(19 位商品 ID 必须 string,用 number 会截零;金额用 number 保留 2 位;状态用枚举别用裸字符串)
  • 分页、错误码、空值怎么约定?

3. 让契约机器可校验,谁偏离谁先红

  • 机器契约必须能被对应格式的标准工具直接解析和校验;JSONC 响应示例、Markdown 字段表与内部 DTO 不能替代 schema。CONTRACT.md 使用 templates/CONTRACT.example.md 只登记权威入口。
  • 消费方拿它生成类型和 mock(提供方没好也能先把界面跑起来)。
  • 提供方拿它写**"返回必须符合契约"的校验测试**(即 provider verification)——提供方改实现不小心偏离了,自己的测试先红,炸在自己这边,炸不到别人。

工作流程

模式 A 由 contract-director 串起全流程;模式 B 下每端在自己终端各做第 1、2、4 步,第 3 步(定契约)和第 5 步(对账)由契约拥有者做。

  1. 先反问消歧义,再定契约。 定契约前,就模糊点反问消费方(字段语义、类型、空值怎么传、枚举到底有哪几个),把歧义消灭在动手前(借 Spec Kit 的 /clarify 思路)。然后按"消费方需求先行"更新唯一机器契约,并在 CONTRACT.md 登记入口和版本(模板见 templates/CONTRACT.example.md)。契约必须前置——绝不先写实现、再从代码事后导出契约,那样契约永远滞后、必然漂移。
  2. 各端以契约为强制起点开发。 每端读取机器契约对应段、只读不改。每个接口任务第一步就是读 CONTRACT.md 及其机器契约,不是凭记忆;复杂改动先声明"我打算怎么对齐契约",审过再写代码——在偏离前就拦下来。
  3. 要改接口 → 提契约变更请求。 不在实现里偷改。模式 A 回报 director;模式 B 写进约定位置(Issue 或 PROJECT_LOG.md 的 contract-request),由契约拥有者裁决后更新契约。破坏性变化必须同时写明兼容期、消费者迁移顺序、回滚条件和不可逆部分;缺失时不进入实现。
  4. 本端自检。 消费方回查所有用到的字段是否都在契约里;提供方跑契约校验测试。
  5. 集成对账。 逐字段核对:提供方返回 vs 契约、消费方用到的字段 vs 契约、字段名大小写/枚举值是否一致。对不上 → 指出哪边偏离、让其修正;若契约本身不合理 → 契约拥有者改契约再让各端对齐。
  6. 记账。 契约有变更 → 往 PROJECT_LOG.md 追加一行 ## [日期] contract | 改了什么接口、为什么(与 living-docs-governance 共用同一本流水账)。

例子

  • 字段名漂移:前端按契约用 userName,后端数据库列叫 user_name。后端在接口层做映射,对外一律按契约 userName,集成对得上。
  • 多终端不用互等:契约先定好,前端在终端1按契约造 mock 把整个下单页跑通,后端在终端2按契约写实现 + 校验测试,两边并行、互不打扰,联调时一次对齐。
  • 多终端改字段:终端1 前端发现少个字段,不去打断终端2,而是在契约"待定变更"区写一条请求;契约拥有者评估后更新 CONTRACT.md,两个终端各自重新拉取对齐。

相关

  • contract-director(契约拥有者/对账)、frontend-dev / backend-dev(各端工人)—— 执行这套方法论的 agent,两种模式通用。
  • living-docs-governance skill —— 防项目文档漂移的姊妹篇;两套共用一本 PROJECT_LOG.md。

角色边界与执行证据

  • 契约拥有者只维护契约、处理变更请求、按已选择模式分工与集成,不实现业务代码;派工注明文件所有权,各端不得回退其他协作者的改动。
  • 消费方只写分配的消费方目录;提供方只写分配的提供方目录。两者均只读契约,变更请求写到约定的 Issue/LOG,不越权编辑契约入口的“待定变更”区。
  • 消费方从同一机器契约生成或校验类型和 mock;没有提供方时可先做契约已定义范围内的页面,不能把新猜测字段塞入 mock 当真。
  • 提供方验证真实序列化响应,覆盖字段改名、大整数 ID、空值、枚举和错误结构;内部 DTO 或状态码为 200 不是足够证据。
  • 用 test-collaboration 将契约格式、消费者、提供者、真实联调四层证据关联到同一 TEST-ID 和契约版本;未跑真实联调时标缺口。
  • 模板参考 tests/test_contract_template.py 只证明模板格式和响应约束,不证明用户项目已经生成类型、实现服务或完成联调。

Signals

GitHub stars
127
Forks
3
Last commit
Sep 2026
Hacker News mentions
1
Advanced
Item type
skill
Key
contract-first-qshanx
Source
github.com/qshanx/docs-governance