关于 Rebuild Dossier
Rebuild Dossier 是面向编码 Agent 的 MCP 服务,用于分析现有应用并生成锁定的重建规格、配置和测试。它先收集证据并要求逐项解决歧义,不会自行重建应用。
主要功能
- 01静态分析代码库与路由
- 02爬取运行中的网站
- 03整理并解决歧义案例
- 04生成规格、契约与测试
- 05通过变异检查验证测试
- 06用钩子限制规格和写入
适用场景
- 01为现有应用建立重建规格
- 02把代码库交接给新的编码 Agent
- 03明确尚未决定的界面行为
- 04检查生成测试能否捕获代码变更
MCP 相关
MCP 服务向兼容客户端提供代码库分析、网站爬取、案例处理和规格生成工具,并可通过 elicitation 交互询问未决事项。生成的规格供编码 Agent 后续重建应用;该服务本身不重建应用。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
6收录的工具列表 · 更新于 3 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| path | string | 是 | 要导入的仓库绝对路径 |
| interactive | boolean | 否 | 为 true 时,如果在具有 monorepo 结构的路径中未找到任何路由,则通过 elicitation 询问哪个候选目录才是真正的应用,然后改为导入该目录 |
详细介绍
rebuild-dossier
一个 MCP 服务,可从现有应用中逆向工程出可信的重建规范——包括锁定的 CLAUDE.md、
.claude/ 配置和经过变异测试的测试套件,让任何编码 Agent 都能依据该规范干净地重建应用,而不是靠猜测。
**它不会重建应用。**它会生成编码 Agent 用于另行重建应用的规范、契约和测试。这个边界是有意为之——请参阅下文的原因。
**已在真实应用上验证。**核心流程(导入、处理案例、生成规范)已针对一个真实且杂乱的代码仓库进行端到端测试,涵盖在两个模型等级上由两个独立的新 Agent 接手,以及一个经过变异测试的测试套件。 docs/v0-findings.md 介绍了哪些有效、哪些失败,以及哪些问题仍未解决。
快速开始
可通过 npm 获取:
npx rebuild-dossier@latest --help # pulls and verifies the package, or:
npm install -g rebuild-dossier # install the CLI globally
需要 Node 20.12+(在 package.json 的 engines 中设置)。若要从源代码运行,请克隆代码仓库、执行 npm install,然后使用 npm start。
然后将其添加为 MCP 服务。在 Claude Code 中,进入你想要重建的项目:
claude mcp add rebuild-dossier -- npx -y rebuild-dossier@latest
(或者将以下内容添加到你的 ~/.claude.json / 项目 .mcp.json 中):
{
"mcpServers": {
"rebuild-dossier": {
"command": "npx",
"args": ["-y", "rebuild-dossier@latest"]
}
}
}
然后在会话中调用。首次调用 ingest_repo 会立即运行,无需任何设置:仅进行静态分析,不需要浏览器、Chromium 或 LLM 调用。先在任意应用上运行它,确认服务正常运行,再决定是否采用完整工作流:
ingest_repo({ path: "/path/to/some-app" })
get_case_queue({ repoPath: "/path/to/some-app", interactive: true })
# ...resolve whatever the queue surfaces...
generate_spec({ repoPath: "/path/to/some-app" })
这会在旁边创建一个干净的 some-app-rebuild/ 目录。进入该目录,启动一个全新的 Claude Code 会话(不要将其他内容纳入其范围),然后粘贴 kickoff-prompt.txt 的内容。
如果你觉得这有用,点个星标可以帮助其他开发者发现它。
原因
先前的研究(AgentModernize, arXiv:2605.17535)发现,没有经过验证的反馈循环时,重建流水线的行为等效性得分为 0%,而使用粗略反馈循环时也只有 9–19%。这个工具的核心设想是:在运行测试之前锁定接口契约,并采用严格的逐项测试重试循环,而不是批量重新生成,这样确实能取得更好的效果。
任何此类流水线中风险最高的部分,是悄无声息地将错误验证为有意设计——四种证据来源可能会不动声色地认可同一个错误,却从来没有人解释过原因。因此,本工具唯一不可妥协的规则是:自动消除歧义必须同时满足信号一致且有明确的信号表明有人确实做出了决定(明确的注释、承认存在 bug 的 TODO,或直接的人类答复)。仅凭默契一致——代码与观察到的行为相符,却从未有人解释原因——永远会被转为一个问题,而不会自动消除歧义,无论表面上的置信度有多高。
工作原理
在普通的 Claude Code(或任何兼容 MCP 的)会话中运行六个 MCP 工具:
| 工具 | 功能 |
|---|---|
ingest_repo(path) | 仅进行静态分析,不调用大模型:分析路由、package.json、构建配置(通过 AST,绝不执行)、现有测试,以及结构性异味检测器(例如,仅在客户端检查凭证却没有服务端验证),即使从未有人评论过,也能发现真实的模糊之处。 |
crawl_site(url) | 使用无头 Playwright 抓取可访问的路由,并发送进度通知,避免长时间抓取被误判为无响应而终止。 |
flag_known_bug(description) | 自由文本,按原样存储。对于匹配的任何内容,始终优先于自动解决;这是系统中成本最低、权威性最高的信号。 |
get_case_queue() / resolve_case(id, decision) | 模糊问题队列。客户端支持时,会通过 MCP 引导式提问呈现待解决的问题;resolve_case 始终可用,作为脚本化的备用方案。 |
generate_spec() | 仅在问题队列清空后才能调用。将 CLAUDE.md、.claude/rules/、.claude/settings.json(用于通过机制强制执行规范的钩子,见下文)、spec/contracts/*.md、tests/visible/ + tests/held-out/ 以及 kickoff-prompt.txt 写入一个干净的同级 <repo>-rebuild/ 目录,而绝不写入原始仓库。在完成测试前会执行真实的变异检查:故意破坏原始代码,并确认生成的每项测试都能发现问题;对未能发现问题的测试则降低其等级。 |
crawl_site 需要 Chromium(见下文第 2 步中的 npx playwright install chromium)——服务器本身不附带 Chromium,通过 Smithery 安装时也不附带,因此请先运行一次安装命令,否则该工具会失败。
通过机制强制执行的护栏,而非只写在文档中的规则
对两个模型层级进行的对比运行发现,较弱的模型可能会认真阅读
CLAUDE.md,理解“只构建当前失败的部分,不要批量重新生成”,
却仍会悄悄违反规则——因为没有任何机制检查它。正因如此,此工具中的两条规则现由实际钩子强制执行,而非仅靠文字说明:
spec/已锁定。 禁止在spec/下写入内容。- 没有测试覆盖的合约不会提前构建。
generate_spec会写入spec/untested-contracts.json(所有没有测试覆盖的路由/合约),并禁止写入该列表中的任何内容。
这两条规则由同一个生成的守卫脚本 .claude/hooks/rebuild-guard.mjs 实现,该脚本作为
PreToolUse 钩子,在 Edit、Write、MultiEdit、NotebookEdit 以及 Bash 上运行。它会在匹配前解析符号链接、.. 路径段以及(在 macOS/Windows 上)大小写;解析具有写入特征的 shell 命令(重定向、heredoc、tee、sed -i、rm/mv/cp、git 写入子命令、会执行写入的解释器单行命令);锁定自身脚本和 settings.json;如果输入、阻止列表或脚本本身缺失或无法读取,则默认拒绝操作。已知限制:shell 解析采用启发式方法,因此无法检测到通过 Agent 先前编写的脚本执行的写入操作。(0.2.10 之前的版本附带了一个未测试合约钩子,该钩子在 shell 中会崩溃,完全无法阻止任何操作;请升级。)
每次编辑后,PostToolUse 钩子都会运行可见测试套件,并在
.claude/.hook-heartbeat.json 中记录心跳,这样你之后可以检查钩子是否确实处于运行状态。

操作指南
完整生命周期,按顺序列出——介绍每一步的实际行为,而不只是调用签名。
1. 导入仓库
ingest_repo({ path: "/absolute/path/to/some-app" })
仅进行静态分析——不会调用大模型,也不会执行任何内容。解析 package.json、路由文件(目前支持 Express 和 Next.js App Router——参见范围)、构建配置(通过 AST 分析 Tailwind/Vite/Next,绝不执行)、现有测试,并扫描注释/TODO 信号及结构性问题(例如,硬编码的客户端凭据检查,却没有服务端验证——这种问题没人会写注释,这也正是它需要单独的检测器,而不能依赖现有注释的原因)。所有内容都会保存在 <repo>/.dossier/ 中——这是此工具自己的临时状态,位于原始仓库内,不会共享或上传到任何地方。你会收到一份摘要:
{
"routes": 8,
"existingTests": 0,
"signals": 3,
"buildConfig": ["tailwind", "next"],
"openCases": 3,
"savedTo": "/absolute/path/to/some-app/.dossier/evidence.json"
}
此处的 openCases 已反映协调结果——未自动解决的注释/TODO 信号和结构性问题会自动成为待处理队列条目。
如果返回的 routes 为 0,先检查是否有 monorepoHint 字段,再判断应用是否没有路由——ingest_repo 必须指向实际的应用目录,而不是 monorepo 的根包装目录(其旁边有 apps/*/packages/* 的 package.json,这在 Turborepo/Nx/workspace 布局中很常见,包括那些实际上没有声明 workspaces 字段的项目)。该提示会列出在 apps//packages/ 下找到的真实候选目录,因此你不必自己寻找实际的应用——改为将 ingest_repo 指向其中一个目录并重新运行即可。
如果你的客户端支持 MCP elicitation,可以完全跳过手动重新运行:传入 interactive: true,当检测到带有候选项的 monorepo 根目录时,ingest_repo 会询问哪个才是真正的应用,并直接导入它——它绝不会擅自猜测;这与 get_case_queue 的交互模式一样,总会先询问你,而不会在未经你同意的情况下解决任何问题。如果你拒绝、客户端不支持此功能,或答案不属于真实候选项,都会回退到上面的普通提示,内容不变。
2.(可选)爬取线上网站
crawl_site({ url: "http://localhost:3000", repoPath: "/absolute/path/to/some-app" })
只有在应用确实运行于某处时,这一步才有用。使用无头 Playwright 爬取可访问的路由,并定期发送进度通知——大多数 MCP 客户端会自动将长时间爬取转为后台任务;如果没有进度通知,静默运行数分钟的调用可能会因看似无响应而被终止。
这一步是唯一需要浏览器的步骤。crawl_site 会驱动无头 Chromium,但服务器不附带 Chromium(包括通过 Smithery 安装的服务器),因此请先运行一次 npx playwright install chromium,否则工具会失败。跳过此步骤,其余工作流仍可正常运行。ingest_repo、resolve_case 和 generate_spec 完全不需要浏览器。
3.(可选,但请在第 4 步之前完成)标记你已知存在的问题
flag_known_bug({
repoPath: "/absolute/path/to/some-app",
description: "The login gate secret check runs entirely client-side and is bypassable"
})
这是整个系统中成本最低、权威性最高的信号——人类的直接陈述始终优先于推断。它会覆盖所有匹配项的自动解决结果,即使其他所有信号都悄然表明该行为似乎是有意为之。请在处理队列之前完成此操作,因为它会改变队列中显示的内容(而且仅凭此操作就能创建一个待处理事项,即使没有任何其他证据也可以——参见 docs/v0-findings.md,了解这为何重要)。
匹配时会将每个未解决事项的文件路径和描述文本与输入进行普通的词语重叠匹配,不会进行模糊或语义匹配——因此,如果你的代码库中有多个名称相似的组件,一条 Bug 描述可能会匹配并自动解决比预期更多的事项。在已验证的示例中,一条关于“登录门控”的 Bug 描述,在逐一审查之前,就通过一次调用匹配并关闭了 Madeline 的三个近似重复门控组件。resolve_case 无论事项当前处于什么状态,都会覆盖其处理决定;所以,如果这不是你的本意,请直接对它误伤的事项调用该工具——不要假定它处理的每个事项都属于同一个决定。
4. 解决案例队列
get_case_queue({ repoPath: "/absolute/path/to/some-app", interactive: true })
interactive: true 会通过 MCP 引导交互,逐一处理每个未解决的案例——如果你的客户端支持,就会在客户端中显示一个真正的交互式提示,并排展示证据。如果不支持(或者你正在编写脚本),则应逐个解决案例:
resolve_case({ repoPath: "/absolute/path/to/some-app", id: "case:...", decision: "intentional", note: "..." })
这一步没有捷径。 只要还有未解决的案例,generate_spec 就会拒绝运行,这是有意为之——不能生成带有注意事项、供重建 Agent 使用的部分或未完成规格;第 1–2 阶段正是生成 spec/ 的过程。
5. 生成规格
generate_spec({ repoPath: "/absolute/path/to/some-app" })
只有队列清空后才能调用。它会将 CLAUDE.md、.claude/(规则、钩子、一个 spec-auditor 子 Agent,以及一个 verify-against-spec 技能——全部根据这个项目的实际契约和测试生成,而非样板内容)、spec/(契约、已锁定的决策、test-dependencies.json、untested-contracts.json)和 tests/ 写入一个干净的同级 some-app-rebuild/ 目录——绝不会写入原始仓库。只有在确实有用时,才会额外生成两个 .claude/ 产物:仅当存在需要防护的保留测试时,才生成 test-verifier 子 Agent;仅当生成的测试按共享路由文件划分为两个或更多值得并行修复的独立集群时,才生成 parallel-test-fix 工作流。像上方经过验证的示例那样,一个只有少数测试覆盖相同路由的小型应用,两者都不会生成;这不是 Bug,而是生成器拒绝为重建 Agent 提供它根本用不上的工具。这一步还会执行一次真实的变异检查:它会在临时副本中故意破坏原始代码(反转比较条件、删除空值检查、将循环边界偏移一位),并确认每个生成的测试都能捕获这些问题——任何未能捕获的测试都会被移到 tests/weak/,而不会作为可信测试发布。你将获得:
{
"outputDir": "/absolute/path/to/some-app-rebuild",
"mutationsChecked": 8,
"weakTests": [],
"unrunnableTests": []
}
weakTests 和 unrunnableTests 都会放在同一个 tests/weak/ 目录中,而不是 tests/visible/,但两者原因不同,值得区分:弱测试能够正常运行,只是从未捕获任何被变异破坏的内容;无法运行的测试即使在原始未变异代码上也从未通过(可能是导入错误、缺少环境变量,或裸仓库不具备的基础设施)——在引入这种区分之前,无法运行的测试看起来和效果达 100% 的测试毫无区别,因为无论被测代码是否经过变异,它都会以同样的方式“失败”。两者都不算错误——这是工具在如实告诉你,某个测试不够格放进 tests/visible/,以及具体原因。
如果所有生成的测试都进入了 tests/weak/,且 mutationsChecked: 0,请先检查是否存在 warning 字段,再判断是否存在结构性问题——更常见的原因是目标仓库尚未运行 npm install,因此变异检查所用的临时副本没有目标项目自身的实际依赖项(next、@prisma/client,或应用实际需要的其他依赖),导致每个生成的测试都无法导入这些依赖。generate_spec 会直接检查这一情况并告知你,而不是让你调试一堆令人困惑的无法运行结果。
可选:借助视觉辅助进行页面内容分类
对于 Next.js 目标,页面路由会获得真实的 Playwright 捕获测试(截图加 DOM 文本断言),与上文所述的 API 路由测试一同运行。默认情况下,是否对捕获的文本进行精确匹配断言(static)还是宽松的形态检查(dynamic),由一个小型正则表达式分类器决定——大多数时候都很可靠,但已确认它在真实应用中可能会在两个方向上判断错误(将硬编码的下拉菜单图例读作实时数据;将实时的逗号分隔数据库计数读作固定值)。
在调用 generate_spec 之前同时设置 GROQ_API_KEY 和 REBUILD_DOSSIER_ENABLE_VISION_CLASSIFICATION=1,就会改为将每个捕获页面的截图和(已遮蔽机密信息的)源代码发送给 Groq 视觉模型。该模型能看到某个值的实际来源——源代码中的字面量数组,还是 fetch/useState 调用——而不是仅仅根据渲染出的字符串外观来猜测。特意要求同时设置这两个变量:遗留自无关工具的环境变量 GROQ_API_KEY,绝不能悄无声息地开始把此目标仓库的代码发送给第三方。两个变量都未设置(默认情况)意味着行为完全不变,除了 generate_spec 原本就会执行的操作外不会产生任何网络请求(唯一的操作是在首次运行时,一次性下载变更检查所用的固定版本 vitest 运行器到 ~/.cache/rebuild-dossier/)。
这会产生实际的额外成本,并非免费:每个捕获页面会调用一次 Groq API,且页面之间会有特意设置的约 20s 间隔(Groq 免费层的每分钟令牌额度很紧,连续发送请求会很快耗尽额度)——generate_spec 自身的响应会说明本次运行增加的准确耗时。任何页面若因任何原因(速率限制、网络问题、响应无效)无法通过这种方式分类,就会仅针对该页面回退到正则表达式分类器,并在 pageVisionFallbacks 中报告——绝不会悄无声息地漏掉,也不会导致运行失败。Groq 免费层(无需信用卡,可通过 console.groq.com 访问)足以用来试试。
6. 交接
cd /absolute/path/to/some-app-rebuild
mv tests/held-out ../held-out-sealed # keep the acceptance suite out of the agent's reach
claude # a genuinely fresh, top-level session
以下三点决定结果是否有意义:
- 在包目录中启动一个顶层 Claude Code 会话来运行它。 防护机制由
.claude/settings.json中的 Claude Code 钩子实现。通过另一个会话的 Agent 工具启动的会话(子 Agent)永远不会加载这些钩子,而且不会有任何提示。其他 Agent(opencode、oh-my-pi、Codex)可以使用此包,但没有这些钩子,防护机制就只是文字说明。 - 在任务完成前,别让 Agent 接触
tests/held-out/,之后再由你自己运行一次:mv ../held-out-sealed tests/held-out && npx vitest run tests/held-out。如果 Agent 能读取或重新运行未通过的保留测试,就可以从错误输出中抄出预期答案。本项目自己的评估中就发生过这种情况。 - 事后检查钩子是否生效: 应能读取到
cat .claude/.hook-heartbeat.json,且其中的count大于零。文件不存在就表示钩子从未触发。
原样粘贴 kickoff-prompt.txt 的内容。该会话的上下文中不应包含其他内容——此目录特意设计为完全自包含(见工作原理),因此重建 Agent 无需读取其他内容、偏离方向,或直接编辑现有内容,而应从头干净地构建。阅读 docs/v0-findings.md,了解对真实应用执行此操作时实际会发生什么,包括具体卡在哪里。
从其他工具连接(oh-my-pi、opencode 等)
有两种运行方式,且都完全在本地运行——没有托管/共享实例,也不需要:
stdio(默认)——每个工具都会以本地子进程的形式启动一份服务副本。这是所有 MCP 客户端(Claude Code、oh-my-pi、opencode)添加本地 MCP 服务的标准方式——从此仓库的目录中,将其指向 npx tsx src/index.ts(或构建后的 node dist/index.js)即可。无需额外设置,也不需要身份验证;本节内容均不适用。
HTTP(可选)——在 localhost 上运行一个持久服务,供多个工具/会话连接,而不是由每个工具各自启动服务副本。如果你希望 oh-my-pi 和 opencode(或多个 Claude Code 会话)共享同一个运行实例,这种方式会很有用。它仍完全在本地运行——MCP_ALLOWED_HOSTS 只需包含你实际要连接的主机名(localhost),而不需要真实域名;除非你有意将服务开放给自己的计算机以外的地方。
npm run build
PORT=8080 \
MCP_AUTH_TOKEN=$(openssl rand -hex 32) \
MCP_ALLOWED_HOSTS=localhost,127.0.0.1 \
REBUILD_DOSSIER_ALLOWED_PATHS=/absolute/path/to/your/projects \
npm run start:http:prod
这三个环境变量都是必需的——服务会有意拒绝在缺少其中任何一个的情况下启动:MCP_AUTH_TOKEN 会对每个 /mcp 请求进行授权(Bearer 身份验证),MCP_ALLOWED_HOSTS 用于防范 DNS 重绑定,而 REBUILD_DOSSIER_ALLOWED_PATHS(以逗号分隔的绝对目录)是 ingest_repo/generate_spec/等操作唯一获准访问的路径——将其设置为包含你实际想要重建的仓库的父目录即可。
oh-my-pi(.omp/mcp.json 或 ~/.omp/agent/mcp.json):
{
"mcpServers": {
"rebuild-dossier": {
"type": "http",
"url": "http://localhost:8080/mcp",
"headers": { "Authorization": "Bearer ${REBUILD_DOSSIER_TOKEN}" }
}
}
}
opencode(opencode.json):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"rebuild-dossier": {
"type": "remote",
"url": "http://localhost:8080/mcp",
"enabled": true,
"oauth": false,
"headers": { "Authorization": "Bearer {env:REBUILD_DOSSIER_TOKEN}" }
}
}
}
oauth: false 会停用 opencode 在收到 401 时自动发现 OAuth 的功能——此服务只支持上述静态 Bearer 令牌,不支持真正的 OAuth 流程。将所引用的环境变量(两个示例中的 REBUILD_DOSSIER_TOKEN)设置为与上文 MCP_AUTH_TOKEN 相同的值。
开发
npm test # full suite
npm run typecheck
函数小巧且用途单一;全程采用 TDD(先编写测试,再实现测试覆盖的功能,包括协调逻辑本身的测试——这是一个生成测试的工具,因此自身的正确性与任何功能同等重要)。
当前范围,以及有意暂不实现的内容
v0 的范围旨在验证核心循环,而非实现完整功能。以下内容有意推迟,并作为真正的待办事项跟踪,而不是悄悄跳过:
- 对 API 形式歧义(例如验证规则、错误响应结构)的协调仍未经过实际测试——目前验证过的、结构有所不同的真实应用只有 catchandtrade,但它恰好没有任何需要协调的注释/TODO 信号,因此这个具体问题目前仍没有答案。参见 docs/v0-findings.md。
- 视频/屏幕录制内容摄取,以及由视频大模型标记的时间段审查。
- 将 Original-CLAUDE.md / 自动记忆作为证据来源。
- 通过实时 Chrome MCP 捕获无头爬虫无法访问的、需要身份验证的/多账户流程。
- 资产清单提取(以原始字节复制二进制文件 + 哈希清单,锁定契约层级)——设计已完成,尚未实现。
- 一种可以完全不执行处理函数的变异器(当前的三种——翻转比较、删除空值检查、差一错误——无法生成“这个分支从未执行”的变异体)。
请参见 docs/v0-findings.md,了解完整且坦诚的说明:验证期间发现并修复的真实错误、不同模型层级之间的比较,以及仍待解决的问题。
贡献
感谢你考虑贡献!这是一个学术/研究项目——更改应符合论文中描述的设计。有关设置、测试和 PR 指南,请参见 CONTRIBUTING.md。欢迎首次贡献者——查找标记为 good first issue 的问题,或新建问题并询问哪些工作最有帮助。
请参见 How rebuild-dossier compares,了解它与其他方案的区别。
许可证
⭐ 如果 rebuild-dossier 帮助你交付更完善的重建成果,点个星标也能帮助其他开发者发现它。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。