关于 Evidrift
Evidrift 是一款本地优先的 CLI 和 MCP 服务,可记录 TypeScript 与仓库 JSON 契约,并在 CI 中重新校验;也能通过验证回放缩减失败请求。
主要功能
- 01记录 TypeScript 调用签名
- 02锁定 OpenAPI 或 JSON Schema 值
- 03在 CI 中重新校验契约
- 04通过回放缩减失败 JSON
- 05内容寻址回执与完整性检查
适用场景
- 01在合并前发现依赖 API 变更
- 02在 CI 中检查 OpenAPI 操作值
- 03为 HTTP 故障生成最小复现
MCP 相关
本地 STDIO MCP 服务提供契约记录工具,包括 TypeScript 与 JSON Pointer 回执。回放命令独立运行,不能通过 MCP 使用。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
2收录的工具列表 · 更新于 3 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| claim | string | 是 | 说明这项证据为何重要的人类声明。 |
| symbol | string | 是 | 导出的可调用 TypeScript 符号。 |
| overload | integer | 否 | 仅在记录重载符号时使用的可选 1 起始重载选择器。 |
| parameter | string | 否 | 必须存在的可选参数名称。 |
| packageName | string | 是 | 已安装的 npm 依赖项名称。 |
| projectRoot | string | 否 | 包含使用方 package.json 的、相对于仓库的目录。 |
| affectedCodeLine | integer | 否 | 可选的 1 起始受影响源代码行。 |
| affectedCodePath | string | 是 | 受该声明影响的、相对于仓库的源文件。 |
详细介绍
Evidrift——经过重放验证的 JSON 缩减与 API 漂移证据
故障来势汹汹,API 却悄然漂移。Evidrift 将两者都转化为确定性证据。
Evidrift 提供两种刻意分离的工作流:
- ReproMin 反复移除 JSON 数据,将每个候选项重放到一次性本地 HTTP 目标上,并仅保留仍与所选故障标识匹配的缩减结果。
- Contract drift 将精确的 TypeScript 调用签名或存储库 JSON 值记录为内容寻址的 Receipt,然后在合并前让 CI 重新计算并验证。
本地优先的 CLI。仅用于记录合约的 STDIO MCP 服务。无需账户、云后端、遥测或 LLM 判定。

动画根据捕获的 CLI 记录渲染而成。PASS、变更后的签名、受影响的文件以及确定性的 FAIL 均来自实际的本地 evidrift demo 运行;只有场景标题是编辑性内容。
快速开始——缩减失败的请求
需要 Node.js 22 或更高版本。零配置演示会启动一次性 loopback 服务器,验证一次 HTTP 故障,缩减其 JSON 请求,再次验证结果,随后关闭服务器:
npx --yes evidrift@latest repro-demo
结果并非由 LLM 选出。每个被接受的缩减都会实际重放,并且必须同时匹配预期的 HTTP 状态和错误标识。
使用你自己的本地端点:
npx evidrift minimize \
--request failing-request.json \
--status 500 \
--response-pointer /error/code \
--response-equals '"INVALID_FILTER"' \
--output minimal-repro.json \
--confirm-replay yes
然后重放一次内容寻址的产物:
npx evidrift reproduce --artifact minimal-repro.json --confirm-replay yes
请参阅完整的 ReproMin 固定样例、保证和重放安全边界。
快速开始——一条命令查看漂移
需要 Node.js 22 或更高版本。无需全局安装:
npx --yes evidrift@latest demo
该命令会创建一次性本地固定样例,记录 parseConfig 上可选的 options 参数,并成功检查;随后修改固定样例,使 options 成为必需参数,再证明 evidrift check 能捕获不匹配。它不会运行任何下载的程序包代码。
如果你希望在合并前捕获此类故障,请在 GitHub 上为 Evidrift 点星。
真实环境实验 — React 19 useRef
合成演示速度很快;这个源代码仓库实验则针对真实且有文档记录的生态变化,验证相同工作流。React 官方升级指南指出,React 19 要求提供 useRef 的第一个参数。Evidrift 记录了 @types/[email protected] 中的无参数重载,将该类型包单独升级到 @types/[email protected],并报告缺失的重载:
git clone https://github.com/bm1016bm-svg/evidrift.git
cd evidrift
npm ci --ignore-scripts
npm run demo:react-19
安装后会验证两个包版本是否准确。实验会禁用依赖的生命周期脚本,最终的 evidrift check 必须返回确定性的契约不匹配结果。请参阅复现步骤和完整信任边界以及React 19 官方升级指南。
当前支持
| 表面 | 确定性证据 | 状态 |
|---|---|---|
| 回环 HTTP JSON 错误 | 重放后的归约结果匹配状态码和错误标识 | 仅 CLI |
| 已安装的 TypeScript 依赖 | 选定的调用签名、参数、包版本和声明 | 支持 |
| 仓库中的 OpenAPI / JSON Schema | 通过 RFC 6901 JSON Pointer 选定的规范值 | 支持 JSON |
| 契约 CLI 和本地 STDIO MCP | 相同的记录与重新验证核心 | 支持 |
远程重放、cURL 导入、YAML、远程 $ref | 无;Evidrift 会拒绝这些输入,而不会猜测 | 不支持 |
安装 — 添加到仓库
无需全局安装、账户、API 密钥或云后端,即可初始化当前仓库:
npx --yes evidrift@latest init
如需添加带有文件和行号注释的幂等拉取请求工作流:
npx --yes evidrift@latest init --github-actions
初始化程序会检测 npm、pnpm 或 Yarn,添加 scripts.evidrift:check,并创建 .github/workflows/evidrift.yml。如果现有脚本和工作流已存在,程序会提示并保留它们,而不会覆盖。
如需为团队或 CI 工作流固定 Evidrift 版本:
npm install --save-dev evidrift
npx evidrift init
这就是产品:立即让 AI 假设可供审查,之后再让 CI 检查同一份契约。
在仓库中使用
目标仓库中必须已安装该依赖,受影响的代码路径也必须指定真实文件。
cd /path/to/your/repository
evidrift init
evidrift record \
--project . \
--package your-package \
--symbol exportedFunction \
--parameter options \
--claim "exportedFunction accepts the options used here." \
--code src/caller.ts:12
evidrift check
当 --code 包含一行使用了重载调用的代码时,Evidrift 会询问 TypeScript 该调用实际解析到哪个重载。对于不完整或无法编译的调用点,--overload <number> 仍可作为显式备用方案。
从仓库本地的 OpenAPI 或 JSON Schema 文档中锁定一个值:
evidrift record \
--json openapi.json \
--pointer /paths/~1users/get/operationId \
--claim "The generated client calls listUsers." \
--code src/client.ts:24
JSON Pointer 遵循 RFC 6901,其中 / 使用 ~1 表示,~ 使用 ~0 表示。Evidrift 仅读取 .json 文件;它不会获取 URL,也不会解析远程引用。
编码 Agent 通过 evidrift_record 和 evidrift_record_json_pointer 调用同一核心。此处提供了精简的 Codex、Claude Code 和 Cursor 配置。
工作原理
flowchart LR
Author["Developer"] --> Minimize["Minimize failing JSON"]
Minimize --> Replay["Replay loopback failure"]
Replay --> Repro["Content-addressed reproduction"]
Agent["Coding agent or developer"] --> Record["Record one assumption"]
Record --> Adapter["TypeScript or JSON adapter"]
Adapter --> Receipt["Content-addressed Receipt"]
Receipt --> Review["Git review"]
Review --> Check["evidrift check in CI"]
Check --> Result{"Contract still matches?"}
Result -->|Yes| Pass["PASS"]
Result -->|Source unavailable| Warn["WARNING"]
Result -->|No or tampered| Fail["FAIL"]
CLI 和 MCP 服务是基于同一核心构建的轻量入口。完整的组件图、检查策略、资源限制和信任边界均记录在架构文档中。
文件
Evidrift 会为每个 Receipt 写入一个锁文件和一个不可变的 JSON 文件:
.evidrift/
evidence.lock
receipts/
<64-character-sha256>.json
不存在 .evidrift/receipts.json。evidence.lock 仅包含内容寻址的 Receipt ID:
{
"receipts": ["sha256:9bfbb065cff372abe52e8e269123959e9f2ae84cd02230dc751f768ac5e4c274"],
"schemaVersion": 1
}
每个 Receipt 都会存储声明和受影响的代码,以及一份确定性契约:已安装的 TypeScript 符号签名,或仓库 JSON 路径、指针、规范值和哈希。请参阅 Receipt 架构。
将其加入 CI
生成包脚本和只读拉取请求工作流:
npx evidrift init --github-actions
生成的包脚本会固定到当前 Evidrift 版本:
{
"scripts": {
"evidrift:check": "npx --yes [email protected] check"
}
}
使用 npm run evidrift:check 在本地运行相同的固定版本检查。
生成的工作流会在禁用生命周期脚本的情况下安装锁定的仓库依赖, 然后运行 Marketplace Action。契约不匹配和完整性失败会在受影响的文件及行号处变成 PR 错误;源代码变更和证据不可用结果则会变成警告。
evidrift check --annotations github
使用 --format json 时,GitHub 工作流命令会写入标准错误,因此标准输出仍是有效的 JSON。GitHub Actions 完整设置介绍了生成的工作流、权限、包管理器行为和手动设置。
根目录下的 action.yml 提供可用于 Marketplace 的契约检查。它只运行无需联网的契约工作流;该 Action 绝不会触发 ReproMin 重放。
CI 行为
evidrift check 不会信任已保存的 matched 或 verified 标志。它会验证 Receipt、重新加载源代码,并重新计算所选签名或 JSON 值。
| 结果 | 含义 | 退出码 |
|---|---|---|
PASS | 确定性签名或 JSON 值仍然匹配 | 0 |
WARNING source_changed | 源代码标识/内容已更改,但所选契约仍然匹配 | 0 |
WARNING unverifiable | 源代码缺失、无效或无法检查 | 0 |
FAIL contract_mismatch | 所选 TypeScript 签名或 JSON 值已更改/消失 | 1 |
FAIL evidence_integrity | 锁文件或 Receipt 格式错误、缺失、伪造或哈希无效 | 2 |
对于 CI 系统、编码 Agent 和其他工具,可请求版本化 JSON 报告,而不更改这些退出码:
npx evidrift check --format json
报告包含 schemaVersion、Evidrift 版本、摘要计数以及按顺序排列的 CheckResult 对象。报告不含时间戳或仓库绝对路径,因此相同结果序列化后完全一致。请参阅 JSON 检查报告契约。
手动编辑 Receipt 中的一行会生成可直接采取行动的完整性报告:
FAIL evidence_integrity sha256:...
Message: Receipt content hash mismatch.
Receipt ID: sha256:...
Action: Do not trust or hand-edit this Receipt. Restore it from version control, or intentionally create a new Receipt with `evidrift record`.
项目工作流会在 Linux 和 Windows 上使用 Node.js 22 和 24 运行完整检查。第三方 Action 均固定到完整的提交 SHA。
在人工 TTY 中,check、diff、explain 和 demo 会显示微调器以及绿色 ✅、黄色 ⚠ 和红色 ❌ 状态输出。重定向输出、CI、TERM=dumb 和 NO_COLOR 环境下均不使用 ANSI 转义序列,并保持 Agent 和测试使用的稳定纯文本格式。
为什么这不是 RAG、Sonar 或 AI 评审
| 工具 | 职责 | Evidrift 的职责 |
|---|---|---|
| RAG | 在编写回答时获取上下文 | 提交一项假设,并在之后再次检查 |
| Sonar/静态分析 | 查找代码模式和质量问题 | 重新验证明确的外部依赖契约 |
| AI 代码评审 | 做出概率性判断 | 生成确定性结果,不依赖由大模型担任评审的 CI |
如果有帮助,可以同时使用它们。Evidrift 弥补的是一个缺口:即使代码本身没有变化,编写代码的原因也可能过时。
常见问题
什么是 API 漂移?
API 漂移是指代码编写完成后,依赖或契约发生了变化。Evidrift 会检查两种确定性形式:受影响代码位置所选的 TypeScript 调用签名,以及从仓库本地 OpenAPI JSON 或 JSON Schema 中选出的规范值。
Evidrift 是合约测试工具吗?
它的范围比端到端合约测试更窄。合约测试会检验提供方和使用方的行为;Evidrift 则锁定一个影响代码的明确假设,并在 CI 中重新验证该假设,而不运行依赖代码。
Evidrift 能与 Codex、Claude Code 和 Cursor 搭配使用吗?
可以。它们可以调用本地 STDIO MCP 服务,通过共享的验证核心创建 Receipt。Agent 无法直接将 Receipt 标记为已验证。请参阅最简 MCP 配置。
Evidrift 会获取 OpenAPI URL 或执行软件包代码吗?
合约适配器不会。它们会检查已安装的 TypeScript 声明和仓库本地的 .json 文件,不会获取 URL、解析远程 $ref、导入依赖的 JavaScript,也不会执行任意命令。
minimize 和 reproduce 是独立且明确的重放命令。只有在指定 --confirm-replay yes 后,它们才会向字面值形式的回环 HTTP 地址发送 JSON;它们绝不会在 check 期间或通过 MCP 工具运行。
Evidrift 能证明 AI 生成的代码正确吗?
不能。它可以检测确定性证据漂移和 Receipt 篡改,但不能证明运行时正确性、验证自由文本语义或消除幻觉。请参阅What Evidrift Does Not Prove。
CLI
evidrift init [--github-actions]
evidrift record --project <path> --package <name> --symbol <name> \
[--parameter <name>] [--overload <number>] --claim <text> --code <path[:line]>
evidrift record --json <path> --pointer <RFC6901> --claim <text> --code <path[:line]>
evidrift check [--format text|json] [--annotations none|github]
evidrift diff
evidrift explain <receipt-id>
evidrift demo
evidrift repro-demo
evidrift minimize --request <json> --status <code> \
(--response-contains <text> | --response-pointer <RFC6901> --response-equals <json>) \
--output <json> --confirm-replay yes
evidrift reproduce --artifact <json> --confirm-replay yes
evidrift mcp
面向仓库的命令接受 --root <repo>。record 要求已初始化 .evidrift/evidence.lock;repro-demo 和 mcp 不使用仓库根目录。
evidrift mcp 会启动与 evidrift-mcp bin 提供的相同本地 STDIO 服务。此命令的作用是让软件包注册表和 MCP 客户端能够从主 npm 软件包确定性地启动 Evidrift。
信任边界
.evidrift/receipts/*.json 属于不可信输入。每次检查都会:
- 严格验证锁文件和 Receipt 架构。
- 仅根据完整的 SHA-256 ID 推导文件路径。
- 重新计算预期合约哈希和 Receipt 内容哈希。
- 解析声明或仓库本地 JSON,不导入软件包 JavaScript、不运行 Shell 命令、不发起网络请求,也不调用大模型。
- 分别报告证据完整性、源漂移、语义支持情况和运行时正确性。
解析器最多接受 1,024 个 Receipt ID,且每个符号最多接受 64 个调用签名。TypeScript 证据仅限于仓库文件,并限制为最多 256 个源文件、每个文件最多 2 MiB、总计最多 16 MiB。JSON 源文件最多为 4 MiB,选取的规范值最多为 1 MiB。动态文本会被拒绝或转义,以防 Receipt 注入终端控制字符或伪造 CI 行。
内容哈希可以检测不一致的编辑,但不能证明作者身份。有人可以重写 Receipt、重新计算其 ID 并修改 evidence.lock,从而创建内部有效的新证据。必须通过 Git 审查和分支保护来发现此类替换。请参阅架构。
ReproMin 有独立的边界,因为重放可能造成副作用。它只接受字面值形式的回环 HTTP 目标,拒绝重定向和常见的类似密钥输入,要求明确确认重放,并限制请求数量和响应检查范围;它绝不会从 check 或 MCP 服务运行。产物会记录 Evidrift 观察到的内容;其内容哈希可以检测不一致的编辑,但不能验证探测历史的真实性。reproduce 会验证一次当前重放。
Evidrift 不证明什么
Evidrift 不证明代码正确。契约工作流无法证明自由文本声明、执行运行时行为、消除幻觉、扫描依赖漏洞或验证任意 URL。
ReproMin 不证明全局最小性,也不确定根本原因。在预算未耗尽时,它只能根据其文档所述的 JSON 缩减器和所选失败谓词,证明 1-最小性。较弱的谓词仍可能描述错误,因此不能只看状态。
当使用者代码可编译且 TypeScript 能确定一个已声明的重载时,契约工作流会根据受影响的 path:line 解析重载。无效、有歧义或缺失的调用会被拒绝,而非猜测;--overload 是明确指定重载的备用方式。Receipt 会存储所选的规范化签名及其哈希,因此声明顺序变化不会导致误报漂移。
json.pointer 适配器会锁定仓库本地 .json 文件中的规范值。它不支持 YAML、URL、远程 $ref、架构验证或语义等价性。它会沿着仓库本地的 TypeScript 声明导入,但不会将每个命名类型展开为深层结构化契约。源文件缺失或无法读取时,会显示警告,但不会阻断流程。这些是有意设定的限制,并非隐藏的保证。
可运行的 boss-fight 测试 会根据一个使用复杂跨文件类型别名的实际调用,在三个重载中解析出一个;即使声明顺序发生变化,测试仍能通过;只有所选重载发生变化时,测试才会以确定的方式失败。
开发与 UAT
npm run format:check
npm run lint
npm run typecheck
npm test
npm run uat
npm run check
npm run verify 会运行发布门禁。测试使用临时夹具和一次性环回服务器;不需要密钥、付费 API、Evidrift 后端或外部网络访问。详细的 UAT 报告将每个验收案例对应到自动化测试,并说明剩余风险。
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。
