内容
# agentboard
[](https://github.com/anp0429/agentboard/actions/workflows/ci.yml)
[](LICENSE)
一个审查门控,验证变更的方法是执行测试,而不是判断差异。大型语言模型(LLM)根据意图和变更提出边缘情况测试。确定性测试框架在干净的checkout中针对真实代码运行每个测试。如果测试编译、运行并失败,则报告行为存在差距。没有任何模型参与通过或失败的决策。
一个工具,两个阶段:作者在推送前运行它并修复实际问题,以便变更以更干净的状态到达;维护者在拉取请求中看到它并更快地做出决定。在两个阶段中,都没有人被取代。
```bash
agentboard review --target src/parser.ts --intent "handle empty input"
```
## 为什么
LLM代码审查器读取差异并返回意见。但是,没有任何内容可以用来验证该意见。agentboard的裁决是执行后的测试:它通过了,它失败了,它没有编译,或者它超时了。每个报告的差距都附带一个您可以自己运行的测试,并亲眼看到测试失败。
## 快速开始
安装(Python 3.11+):
```bash
pip install reviewgate
```
该软件包名为`reviewgate`,命令名为`agentboard`:项目名为agentboard,但该名称已被PyPI占用,因此软件包以门控的作业描述名义发布。
或者,从源代码进行开发:`pip install -e ".[dev]"`。
演示在没有API密钥的情况下运行:
```bash
agentboard demo
agentboard demo --fixed
```
它门控一个小型捆绑项目,其中包含一个植入的错误。提案是预先生成的,因此演示练习了管道的确定性部分:门控找到差距,并发现已修复的变体已解决。在实时审查中,需要`OPENAI_API_KEY`(审查者)和`ANTHROPIC_API_KEY`( advisory auditor)。
## 用法
在您的仓库根目录添加一个`.agentboard.toml`文件,或者跳过它:配置文件将从锁定文件自动检测。
```toml
base = "main"
project = "unit"
harness_notes = "Tests already import the framework; reuse existing helpers."
```
审查您不拥有的仓库? agentboard 永远不需要写入其中。运行 `agentboard init --user` 将配置文件保存在您的用户目录中(`~/.config/agentboard/repos/<repo>.toml`),或者显式传递 `--config path.toml`。审查本身也保持树形结构不变:板子和所有运行的工件默认使用系统临时目录。
审查更改前:
```bash
agentboard review --repo . --target src/parser.ts --intent "handle empty input"
```
默认值:头部是您的当前分支,基础是其分叉点,测试文件按以下四个规则自动检测:共存、basename匹配(具有最近路径的消歧义)、审查差异本身所触及的测试文件(当差异命名确切一个时),以及对于显式命名的目标,仅目标目录中的测试文件。意图可以来自 `--intent`、`--issue <url>` 或分支的提交消息(如果您不传递任何参数)。
JS工具链从目标的项目根目录运行,通过遍历到最近的具有锁定文件的祖先(否则是`package.json`)。因此,嵌套在较大仓库中的软件包可以正常工作,工作空间仓库仍在其顶级安装。
## 多文件审查
显式添加文件:
```bash
agentboard review --target src/parser.ts --also src/lexer.ts --also src/ast.ts:tests/ast.test.ts
```
`--also` 可重复使用。测试按文件自动检测;传递 `file:tests` 以覆盖。找不到测试的文件将被跳过并附上注释。
或者,按变更的辐射范围选择文件:
```bash
agentboard review --target src/parser.ts --scope all --depth 2
```
`--scope` 使用 [code-review-graph](https://github.com/tirth8205/code-review-graph) 作为图引擎计算哪些文件受变更影响。它是一个可选依赖:如果未安装,审查将退回到显式目标。范围:
| 范围 | 选择 |
| --- | --- |
| `changed` | 差异中更改的文件 |
| `test-gaps` | 受影响的文件,无可用的测试 |
| `all` | `--depth` 跳数内的每个受影响的文件 |
在提案开始之前,将打印每个深度的成本曲线,显示受影响的文件计数和测试间隙计数。大于 `--max-files`(默认为 20)的选择需要 `--yes`。图表仅决定哪些文件在范围内;每个选定的文件都经过与单个目标运行相同的门控。
## 在CI中审查拉取请求
相同的门控作为GitHub Action运行,并将其发现作为PR评论发布。评论显示每个确认的间隙,带有失败测试的源代码及其观察到的输出,因此审查者可以在几秒钟内判断证据;所有通过或已覆盖的内容都已折叠。设计上它是 advisory的:间隙永远不会导致构建失败,没有自动批准,两个阶段的决策都由人工决定。
工作流位于 `.github/workflows/agentboard-review.yml`,评论渲染器位于 `scripts/render_pr_comment.py`。它选择PR中更改的第一个源文件,如果PR更改了任何审查代码,则静默跳过,如果PR是fork,则完全跳过(仓库机密被保留在fork之外,因此模型密钥在那里不可用;这是正确的,而不是错误)。
## 机器可读输出
`--json-out <path>` 将运行结果写入JSON工件(`schema_version: 1`):仓库、基准、头部、意图、目标、`env_error`、判决计数和每个发现的条目,包含 `behavior`、`status`、`observed`、`source_file` 和 `test_code`。`test_code` 和 `observed` 为 `skipped_covered` 发现的结果为 null,永远不会生成测试。退出代码是 advisory的:0 表示运行完成(间隙存在于JSON中,从不退出代码),1 表示无法运行。这是每个集成的边界;引擎本身不知道拉取请求。
## 从编码代理(MCP)使用
门控作为MCP服务器运行,因此编码代理可以在提交其编辑之前门控它们:
```bash
pip install "reviewgate[mcp]"
```
对于Claude Code:
```bash
claude mcp add agentboard -- agentboard-mcp
```
对于其他MCP客户端(Cursor等),服务器配置为:
```json
{ "agentboard": { "command": "agentboard-mcp" } }
```
此工具暴露一个名为 `review` 的工具,它返回与 `--json-out` 相同的 schema_version-1 工件。它默认为 `--worktree` 模式:差异是工作树的未提交编辑,沙盒执行相同的磁盘状态,这是代理在会话期间实际询问的问题。`intent` 是必需的:调用代理说明其更改的意图;不会从提交消息中推导任何内容。
服务器是与GitHub Action相同的薄适配器:它构建CLI自己的参数并运行相同的 `review()` 路径,并且一致性测试如果两个接受不同的标志,则失败。判决仍然是 advisory的。工具返回发现及其测试源和观察到的输出;它永远不会因确认的间隙而引发,因为决定间隙的含义是调用代理(和最终用户)的任务。
## 工作原理
1. 提案。LLM读取意图和差异,并提出行为,每个行为作为一个可运行的测试。二次检查者寻找该覆盖范围中的间隙。
2. 门控。每个测试都在干净的checkout中针对真实代码运行。门控是确定性的,不包含任何LLM。判决:`handled`、`confirmed_gap`、`broken_test`、`timed_out`、`skipped_covered`。
3. 板块。判决结果渲染到HTML审查板块中。运行指纹允许任意两个运行结果通过一个字符串进行比较。
4. 审计。不同的模型标记确认间隙的可能假阳性。审计是 advisory的,永远不会更改判决。
## 缓存和成本
提出测试是唯一消耗令牌的步骤,因此这是缓存的步骤。提案按意图、差异和目标进行缓存;重新运行未更改的审查会重用缓存的集合,令牌消耗为零,缓存ID在发生这种情况时打印。门控始终重新运行,因为执行测试很便宜,重新验证是重点。
门控是批处理的:一个测试框架调用门控多个行为,每个行为具有串行后备,当批处理无法隔离结果时。批处理和串行路径通过指纹断言判决相同。通过 `--scope`,在任何花费之前会打印成本曲线。
## 本地和开放权重模型
模型路由是一条规则:名为 `claude*` 的模型使用Anthropic;其他名称使用兼容OpenAI的客户端。设置 `OPENAI_BASE_URL` 将该客户端指向任何地方,因此相同的安装程序在本地服务器或托管的开放权重提供商处运行,无需更改代码:
```bash
# Ollama(免费,离线;不需要密钥)
export OPENAI_BASE_URL=http://localhost:11434/v1
# 或托管提供商(OpenRouter显示;需要其密钥)
export OPENAI_BASE_URL=https://openrouter.ai/api/v1
export OPENAI_API_KEY=sk-or-...
```
```toml
# .agentboard.toml
reviewer_model = "qwen3.6:27b" # 或 "moonshotai/kimi-k2.6" 等
critic_model = "devstral-small-2" # 不同血统解相关
```
设计吸收较弱的提案者安全:一个提案如果无法编译或运行,则针对测试(`broken_test`)进行评分,而不是针对代码,因此较小的模型只能降低召回率,而不影响信任。判决路径保持不变,因为它从来不包含模型。
## 结果来自真实仓库
- [supabase/mcp#317](https://github.com/supabase/mcp/pull/317):提出的测试重现了主线上的一个错误。复合外键在 `list_tables` 中返回列对的笛卡尔积,因此N列键报告了N²个配对,其中许多在模式中不存在。修复和生成的回归测试(自引用、跨模式、非主键唯一、多FK、三列)已合并到主线中。
- [colinhacks/zod#6211](https://github.com/colinhacks/zod/issues/6211):在打开的修复分支上运行提出的套件([#6181](https://github.com/colinhacks/zod/pull/6181))。运行确认修复解决了11种形状的崩溃,并提出了涉及`__proto__`路径元素的残留问题,其中括号赋值设置了原型而不是自己的键。在发布的zod上用纯JavaScript验证(所有五个继承的名称崩溃了`formatError`和`treeifyError`),将问题报告为6211,并修复了[PR #6212](https://github.com/colinhacks/zod/pull/6212),涵盖了两个函数和回归测试,从红色到绿色,无回归。
- [unjs/ufo#360](https://github.com/unjs/ufo/pull/360):提出的测试捕获了`withBase`/`withoutBase`将`/`和`?`视为基边界但不视为 `#`,因此基路径后的片段直接破坏了两个操作。向上游报告了发现、修复和回归测试。
## 基准测试
[BENCHMARK.md](BENCHMARK.md)衡量更难的问题:agentboard能否在代码中发现真实的错误,而这些错误它以前从未见过,意图中也没有明确指出?它在最近合并的错误修复PR的父提交中运行,中立的意图,并针对修复进行评分。
在8个仓库的12个错误中,8行产生了真实的确认错误,4行是精确严格的捕获。其中一行指向vueuse,在已知的修复之前捕获了修复的邻域和PR从未触及的另外两个错误。 四行未命中,并有完整的文档记录。 基准测试还记录了工具最有用的失败: advisory审计两次将真正的严格捕获称为假阳性,一次引用错误的行,如果它被视为合同,这正是判决来自执行而非模型的原因。
## 每次运行都是训练数据
门控是一个具有无模型奖励函数的奖励函数,因此每次发现都是一个标记示例:提案者看到的输入,它编写的测试以及执行的判决。 `--dataset` 将每个发现的JSONL行追加到增长的语料库中。
```bash
agentboard review --target src/parser.ts --intent "handle empty input" --dataset
```
每行存储提案和执行的判决。诚实的标签是`ran`(测试是否执行),仅由门控状态导出。 advisory审计存储在旁边,但永远不会覆盖它。收集是选择加入的,并且是追加的,写入`~/.agentboard/dataset.jsonl`,默认为此值。
## 可靠性
分类路径针对每个CI推送的判决类别进行检查,共有1,000次运行。 失效测试(`expect(1).toBe(2)`)必须始终分类为真正的失败;如果不可能的测试曾经读取为通过,则CI失败。 批处理和串行门控路径通过指纹断言判决相同。
## 限制
- 执行信任模型:审查仓库运行该仓库的代码。你将仓库复制到一个临时目录,但安装步骤执行仓库的依赖生命周期脚本,测试在您的OS用户、网络和环境(减去两个模型提供商密钥,它们被清除)下运行。 目前尚无容器或VM边界。 仅审查您愿意运行`npm install`的仓库。 更强的隔离功能正在路线图中。
- 提案覆盖率是一个采样过程。提案者可靠地到达主题,但采样哪些边缘情况;重复运行会找到重叠但不相同的集合。
- 图范围依赖于引擎的导入解析。存储库通过桶文件(`export * from`链)路由导出,可以报告其半径不足。 成本曲线显示图表在任何花费之前看到的内容,并且 `--also` 无论如何都有效。
- 受影响的文件如果没有自己的测试,则在最近的现有测试文件中门控,这可能会使结果偏向`broken_test`,直到测试脚手架实现。
- 审计通过是 advisory的,并且不是负载承载的。
- Vitest(pnpm或npm)是支持的测试框架。
- 当前的vitest是支持的目标。 旧版本(vitest 0.2x时代)往往在环境准备阶段因toolchain原因失败,agentboard将此报告为环境失败而不是产生判决。
- pnpm仓库在仓库自己的配置解析的版本下运行:`packageManager`在现代 (>= 9)时被遵守,对于古老或不存在的pin,fallback到固定的`pnpm@9`。 单个硬编码的pin在两个方向上都中断(旧的pnpm在Node 22上死亡;pnpm 9拒绝pnpm 10/11的`pnpm-workspace.yaml`配置),因此规则是“在配置编写的版本下运行”。
- 具有多个vitest项目或每个包配置的多仓库需要一行`.agentboard.toml`文件命名`project`或`filter`,就像您将CI范围一样。 未作用域时,运行程序可能会启动一个无关的(例如浏览器)项目并报告环境失败而不是判决。