blasrodri/truth
GitHub: blasrodri/truth
truth 是一个确定性事实核查工具,用于验证 AI 编程 Agent 对其所做代码变更的声明是否与真实代码和运行结果一致。
Stars: 0 | Forks: 0
# truth
**`truth` 是一个确定性的事实核查工具,用于验证 AI 编程 agent 对其所做工作的声明。**
当 agent 说*“我添加了 `/v1/refund` 路由,将 `MAX_RETRIES` 设置为 5,只修改了解析器,并且测试通过了”*时,`truth` 会将每一项声明与**实际代码、工作树 git diff、记录的命令运行情况以及日志**进行核对,并给出**成立 / 矛盾 / 拒绝** 的判定 —— 每一个判定都会提供引用出处。
它不是聊天机器人,也不会通过模型来判定真伪。语言模型仅用于将 agent 的句子解析为结构化声明;而一个固定规则引擎会根据检索到的证据给出判定。**agent 无法通过巧言令色改变判定结果。**

真实命令,真实输出:agent 发送给 `truth-mcp` 的确切 `verify_turn` 请求及其获得的确切响应。你可以自己复现:`bash examples/demo.sh`。
```
$ truth verify-turn "I added the /v1/refund endpoint, set MAX_RETRIES to 3, I only changed src/api.rs, and tests pass"
✓ Supported I added the /v1/refund endpoint (src/api.rs)
✗ Contradicted set MAX_RETRIES to 3 (src/config.rs:1)
✗ Contradicted I only changed src/api.rs (src/api.rs)
✗ Contradicted tests pass (recorded 2026-06-11 09:14 UTC)
1 supported · 3 contradicted · 0 refused
⚠ The agent's message contradicts the evidence above.
```
**跳转至:**[安装](#install) · [60 秒体验](#try-in-60-seconds) ·
[从你的 agent 中使用 (MCP)](#use-it-from-your-coding-agent-mcp) ·
[设为关卡](#make-it-a-gate-the-agent-cant-skip-hooks) ·
[工作原理](#how-it-works) · [基准测试](#benchmarks) ·
[局限性与威胁模型](#limitations--threat-model)
## 为什么需要
编程 agent 往往会夸大其词。它们根据干净的日志推断并报告成功,捏造终端输出,并自信地描述他们并没有做出的更改。我们对此进行了测量:在针对真实 GitHub issue 进行的 100 次真实 SWE-agent 运行中,**30% *失败* 于测试套件的尝试仍然声称自己修复了该问题**(“方法已成功添加”、“问题已解决”)—— 这些基本事实来自 SWE-bench 评估,声明由 LLM 判定,[可复现](docs/BENCHMARKS.md#external-validation--real-agent-over-claims-not-our-fixtures)。
`truth` 会捕捉那些声明中**可核查的**部分 —— 错误的配置值、声称添加或删除的路由/函数、声称编辑的文件、“我只修改了 X” 的范围声明、重命名,以及 *“测试通过”*(对照已记录的运行情况)—— 并对其他部分(*“这样更简洁”*)直接**拒绝**,而不是瞎猜。拒绝是诚实的表现,而不是一种缺陷:一个虚张声势的验证器比没有验证器更糟糕。
所有操作均在**本地**运行。存储区是位于 `.truth/` 中的单个 SQLite 文件;原始日志从不持久化保存(仅保存脱敏后的聚合数据);你的代码永远不会离开本机。不需要 LLM、网络或账户。
## 安装
**Claude Code —— 作为插件**(一次安装即包含 hooks 和 MCP 工具,适用于所有仓库):
```
/plugin marketplace add blasrodri/truth
/plugin install truth@truth
```
然后安装二进制文件(如果你跳过此步,插件会在会话开始时提醒你):
```
curl -fsSL https://raw.githubusercontent.com/blasrodri/truth/main/install.sh | sh
```
安装程序会下载预构建的 tarball,并**在解压前验证其发布的 SHA-256** —— 损坏或被篡改的下载将会安全失败,而不会被安装。(一个用于建立信任的工具不应该要求你运行未经验证的二进制文件。)
这就是全部步骤。**无需针对单个仓库进行设置**:这些 hooks 会对您工作的任何 git 仓库进行事实核查 —— 存储区会在首次使用时自动创建(自动添加至 gitignore),索引会在每次检查时自动刷新。使用 `truth hook auto off` 可退出未初始化的仓库;使用 `truth setup` 可将单个仓库加入到项目级 hooks 中。
**不使用插件** —— 当存在 `claude` CLI 时,安装程序也会注册 MCP 服务器;使用 `truth hook install --user` 一次性添加 hooks(或者在每个仓库中使用 `truth setup`)。
**或者手动安装** —— 从[最新发布版本](https://github.com/blasrodri/truth/releases/latest)中获取适用于您平台的 tarball(macOS arm64/x64,Linux x64/arm64),然后执行:
```
# 根据其旁边发布的 .sha256 校验下载,然后解压
shasum -a 256 -c truth-*.tar.gz.sha256 # or: sha256sum -c truth-*.tar.gz.sha256
tar -xzf truth-*.tar.gz
install truth-*/truth truth-*/truth-mcp /usr/local/bin/
```
**或者从源码构建:**
```
cargo build --release --workspace
install target/release/truth target/release/truth-mcp /usr/local/bin/
# 二进制文件:truth (CLI) 和 truth-mcp(MCP 服务器)
```
## 60 秒体验
不要只听信 README —— 亲自看看 `truth` 如何抓出谎言并自己复现它。最快的路径是重放上图中 GIF 展示的确切请求/响应:
```
bash examples/demo.sh
```
或者手动运行它来对内置的[示例仓库](examples/sample-repo)进行验证(真实命令,真实判定 —— 两个真实的声明和一个植入的谎言):
```
cp -r examples/sample-repo /tmp/demo && cd /tmp/demo
git init -q . && git add -A && git commit -qm baseline
truth init && truth index .
truth verify-turn "I set the payment retry count to 5, the service runs on \
port 8080, and I lowered the request timeout to 10 seconds" --repo /tmp/demo
```
```
✓ Supported I set the payment retry count to 5 (/tmp/demo/src/routes/checkout.rs:4)
✓ Supported the service runs on port 8080 (/tmp/demo/src/config.toml:3)
✗ Contradicted I lowered the request timeout to 10 seconds (/tmp/demo/src/routes/checkout.rs:10)
2 supported · 1 contradicted · 0 refused
```
关于超时的谎言会被代码抓出;真实的声明会被判定为成立,并附带 file:line 引用。完整的分步说明 —— 包括范围谎言(“我只修改了 X”)、`tests pass` 凭证以及审计账本 —— 位于 [`examples/sample-repo/WALKTHROUGH.md`](examples/sample-repo/WALKTHROUGH.md) 中。
## 审计你自己的 agent 历史
如果你使用 Claude Code,`truth` 可以重放你过去的会话,并展示它本可以抓到的夸大声明 —— 这是根据**当时的**代码进行核查的(每一轮对话都会在 agent 编写时通过一个临时的 git worktree 针对 HEAD 所在的 commit 进行验证,因此它绝不会对后续发生变动的代码产生误报):
```
truth audit-session --last 10 # your 10 most recent sessions
truth audit-session --repo /path/to/repo # just one project
```
它只会审计第一人称的工作汇报(“我添加了 X”、“测试通过了”),而不会审计 agent 的推理过程或引用的示例 —— 审计这些内容是制造误报的工厂(测得噪声高达 81%,现已过滤)。这是一种诚实的方式,让你能在自己的仓库中查看,你的 agent 有多常告诉你一些与代码相矛盾的信息。
## 从你的编程 agent 中使用它 (MCP)
`truth-mcp` 是一个本地 [Model Context Protocol](https://modelcontextprotocol.io)服务器(stdio JSON-RPC)。它公开了一个名为 **`verify_turn`** 的工具,agent 会在告诉你修改完成**之前**,对其**自己的**消息调用该工具 —— 这样 agent 就能首先捕获并纠正自己的谎言。
该仓库附带了一个 [`server.json`](server.json)(MCP 注册清单)和一个 [`.mcp.json`](.mcp.json),因此克隆它时会在支持 MCP 的客户端中自动注册服务器(需经过其批准提示)。
### Claude Code
`truth setup`(或 `install.sh`)会为你注册此项。手动操作如下:
```
claude mcp add --scope user truth -- truth-mcp
claude mcp list # verify it connected
```
### Cursor 或任何 MCP 客户端(通用配置)
添加到 `~/.cursor/mcp.json`(Cursor)或你客户端的 `mcpServers` 代码块中:
```
{
"mcpServers": {
"truth": {
"type": "stdio",
"command": "/usr/local/bin/truth-mcp"
}
}
}
```
这就是整个配置 —— **在 MCP 文件中不需要进行针对单个仓库的设置**。agent 会在每次调用时传递仓库路径(即下方的 `repo` 参数),因此一次注册即可适用于你所有的项目。
### `verify_turn` 工具
| 参数 | 必填 | 含义 |
|---|---|---|
| `message` | 是 | agent 关于其工作的原始文本。truth 会将其作为后盾进行扫描,因此你忘记在 `claims` 中列出的声明依然会得到核查。 |
| `claims` | 推荐 | 包含各项独立事实声明的数组,每项都是一个简短、自成一体的句子(`["I set MAX_RETRIES to 5", "I added the /v1/refund route"]`)。**由调用的模型从其自身的消息中提取这些声明** —— 这几乎没有成本(agent 本就处于对话中途),并且比 truth 重新解析文本要可靠得多。truth 依然会根据真实证据而非文字表述来决定每一项判定。 |
| `repo` | 推荐 | 仓库根目录的绝对路径。`truth` 会打开 `/.truth` 并对该工作树进行 diff。如果省略,服务器将回退到它自己的工作目录,这可能会导致错误。 |
| `local_log` | 否 | 用于记录使用情况/错误声明的本地日志文件路径。 |
**确保 agent 使用 `claims`。** 工具描述中提出了此项要求,但要使其成为你自有仓库中的一项习惯,请在 agent 的项目指令(例如 `CLAUDE.md`)中添加一行:
```
Before telling me a code change is done, call the `verify_turn` tool: extract
your concrete factual claims (files edited, values set, routes/functions added
or removed, renames, "only changed X", "tests pass") into the `claims` array
and pass the repo path. Run tests through `truth run -- ` so "tests pass"
is checkable. Fix anything it marks `contradicted` before reporting done.
```
或者完全抛开这种信任机制:`truth hook install`(下一节)会让验证操作在 agent 每一次轮换时都执行,无论 agent 是否调用了该工具。
它会以文本形式返回判定表格,并附带 `structuredContent`(下方的 JSON),其中包括一个 `index` 块,用于报告索引是否为空或已过期 —— 这样就绝不会盲目信任一个“干净”的结果。
## 将其设为 agent 无法跳过的关卡
MCP 工具依赖于 agent *主动选择* 进行自我验证。而 hooks 则消除了这种选择:
```
truth hook install # project .claude/settings.json (--user for global)
```
这会注册两个 Claude Code hooks:
- **Stop** —— 当 agent 结束其轮次时,其最终消息会根据仓库、工作树 diff 以及记录的运行情况进行事实核查。矛盾之处会**阻止停止动作**,并将带有引用的判定结果反馈回去,因此 agent 会在你读到声明之前就进行自我纠正。
- **PostToolUse (Bash)** —— agent 运行的测试/构建/lint 命令会自动作为命令凭证被记录下来,这正是使其后来声称的 *“测试通过”* 可被核查的原因。(仅当 hook 负载携带真实的退出代码时才会记录凭证 —— 绝不靠猜。)
这两个 hooks 均采用失败放行设计:如果 truth 出错,会话绝不会卡死。而且它们是零配置的:在一个从未运行过 `truth init` 的 git 仓库中,hooks 会在 git 根目录自动创建存储区(自动添加至 gitignore —— 保持你的 diff 整洁)并立即开始验证。`truth hook auto off` 会将它们限制在显式初始化的仓库中。
对于 pull request,[`examples/github/pr-factcheck.yml`](examples/github/pr-factcheck.yml) 是一个即插即用的 GitHub 工作流,它会将 PR 的**描述与其实际 diff 进行事实核查**,并将判定表作为评论发布 —— 代理编写的 PR 在任何人工阅读之前就会得到核查。
## 谎言账本
每次检查都已作为审计追踪存储起来;`truth stats` 会将其读取出来:
```
$ truth stats --window 7d
claims checked 142
supported 96 (68%)
contradicted 9 (6%)
refused 37 (26%)
runs recorded 12 (10 green, 2 failing)
contradictions by claim type:
config_value 4
file_changed 3
```
`truth stats --all` 会聚合你运行过 `truth init` 的所有仓库的数据(通过 `~/.truth/registry.json` 实现 —— 存储区本身仍保持各仓库独立)。
## 自己使用 (CLI)
```
cd your-repo
truth init # writes truth.toml + .truth/, runs migrations
truth index . # index code/docs/config (re-run after big changes)
truth verify-turn "I added /v1/refund, set MAX_RETRIES to 5, removed /v1/checkout"
truth verify-turn "" --repo /path/to/repo --json
truth run -- cargo test # run + record a receipt; "tests pass" becomes checkable
truth stats # the lie ledger
```
`--repo` 会打开该仓库的 `.truth` 存储区并对该工作树进行 diff。如果没有此参数,truth 会从当前目录向上查找最近的 `truth.toml`/`.truth` 根目录(就像 git 那样),因此每个命令都可以在任何子目录下运行。`--json` 会输出稳定且机器可读的内容。
## 能检查与不能检查的内容
**检查项(状态声明):** 路由添加/删除/存在、**函数/符号添加/删除/存在**、配置值、命名常量(“将 X 从 3 改为 5”会检查 *5*)、重试次数、超时值、环境变量是否存在、依赖是否被使用、要求的版本、使用计数、错误是否仍然存在、作业上次成功状态、feature-flag 是否启用 —— 涵盖 **Rust / TypeScript / Python / Go** —— 均基于**代码 + git diff + 日志**进行核查,且在处理“我刚修改了 X”的声明时,diff 的优先级高于可能已过期的索引。
**检查项(diff 声明 —— 本次轮次修改的内容):** *“我编辑/创建/删除了 `src/auth.rs`”*(由 diff 的文件列表决定),*“我**只**修改了解析器”*(捕捉附带修改 —— 每一个被修改的路径都必须匹配),*“将 `parse_legacy` 重命名为 `parse_v2`”*(旧名称必须已消失且新名称已被添加),*“更新了 X 的全部 4 处调用点”*(修改过的行数)。空的 diff 会报告 **未知(已经提交了?)** —— 绝不给免费通行证。
**检查项(命令凭证):** *“测试通过”*、*“编译成功”*、*“clippy 无报错”* —— 均根据 `truth run -- cargo test`(或下文提到的 Claude Code hook)记录的运行情况进行核查。**只有在您最后一次编辑工作树之后**,存在匹配的退出代码为 0 的运行记录时,才判定为**成立**;失败的凭证与声明相矛盾;通过但已过期的凭证不能证明任何事,会被拒绝。
**拒绝项(设计使然):** 没有凭证的行动声明(*“我运行了测试”* —— 记录下运行过程即可变为可核查),以及主观判断声明(*“这样更简洁/更快”* —— 没有可衡量的主体)。拒绝 ≠ 已确认。
## 配置
行为配置 `truth.toml` 中(由 `truth init` 写入)。无需手动编辑即可进行调整 —— `truth settings` 会验证并保留文件的其余部分,因此用户*或 agent* 都能以编程方式更改配置项:
```
truth settings list # every knob, current value, help
truth settings set indexer.extractor mixed # turn on AST precision (symbols/routes)
truth settings set repo.include src,lib,app # what to index
truth settings set llm.enabled true # LLM fallback for phrasings regex can't parse (engine still decides)
truth settings get indexer.extractor --json
```
最有价值的配置项是 **`indexer.extractor`**:`mixed`(默认值 —— 对 Rust、TypeScript/JavaScript、Python 和 Go 提供 AST 级别精准的函数/结构体/路由定义,因此仅在注释中提及的符号不会与真实的定义混淆;其余部分使用正则表达式补全) · `ast` · `regex`(速度最快,与语言无关,但噪声较大)。更改后请重新运行 `truth index .`。
## 工作原理
```
agent message
→ segment into candidate claims (sentences, clauses)
→ claim extraction (deterministic regex first; optional LLM fallback only
for what regex refuses — never overrides a confident parse, never decides truth)
→ structured claim (unverifiable → Refused, never guessed)
→ query plan (safe templates only — the LLM never writes LogQL/SQL)
→ evidence: repo index + working-tree git diff (changed lines, file list,
untracked files) + command receipts (`truth run`) + log queries
→ deterministic verdict engine (fixed rules, source-authority order,
diff > stale index, receipts must postdate the last edit)
→ cited verdict: Supported / Contradicted / Refused
```
每次检查都会作为审计追踪(包含声明、运行的查询和判定)存储在 SQLite 中。日志样本在存储或显示之前会进行脱敏处理(电子邮件、JWT、UUID、IP、token)。
## 基准测试
质量标准是由仓库内的评估工具强制执行的,而不是在字里行间空口无凭 —— 以下每个数字都可以使用 `truth eval` 复现。最新运行(`truth 0.3.8`,extractor 为 `mixed`)情况:
| 测试集 | 用例数 | 通过数 | 衡量内容 |
|---|--:|--:|---|
| `agent_claims.yaml` | 13 | 13 | agent 口吻的声明:真相 → 成立,谎言 → 矛盾,主观判断 → 拒绝 |
| `extractor_corpus.yaml` | 42 | 42 | 使用多种方式表达相同事实(包括复杂的文本),涵盖值/路由/符号/依赖声明 |
| `basic.yaml` + `claims.yaml` | 7 | 7 | 端到端判定及声明文件格式 |
| **总计** | **62** | **62** | |
对于验证器而言,真正重要的数据是非对称的:**0 次误判**(没有谎言被判定为成立,没有模糊的声明得出确定性结果),并且在当前语料库上**0 漏报**。这种设计保证了*唯一*的失败模式就是拒绝过多 —— 绝不放过谎言。完整的表格(声明类型、支持的语言、误报/漏报行为)及复现步骤见:[`docs/BENCHMARKS.md`](docs/BENCHMARKS.md)。
## 局限性与威胁模型
`truth` 是一个关于信任的工具,因此它明确声明了自己的边界。简述如下:
- **“矛盾”判定非常强硬** —— 声明与 `truth` 直接读取的主要证据(代码、diff 或记录的运行情况)不一致。
- **“成立”判定在设计上稍弱** —— 意思是“与我能读到的证据相符”,而不是“在任何意义上都是绝对真实的”。它不能证明代码是*正确*的,只能证明它与声明相符。
- **“拒绝”判定是诚实的表现,而非缺陷** —— 对于无法验证的内容,`truth` 拒绝猜测。拒绝 ≠ 已确认。
- **最大的逃避方式就是含糊其辞。** 只报告主观判断(“我改进了错误处理”)的 agent 永远不会被抓住撒谎,因为它从不说任何可证伪的话 —— 尽管满屏的拒绝本身就是一种信号。
- **验证器之下的所有内容都是受信任的:** 工作树、git 历史、`.truth/` 存储区以及二进制文件本身。被入侵的主机可以击败任何本地工具。(这就是为什么 `install.sh` 会在安装前验证已发布的 SHA-256。)
完整的说明 —— 一个判定能证明什么和不能证明什么,以及 agent 仍然可以如何逃避它的编号列表 —— 位于 [`docs/THREAT_MODEL.md`](docs/THREAT_MODEL.md) 中。有关各声明类型的可核查性细分,请参见上方的[*能检查与不能检查的内容*](#what-it-can-and-cannot-check)。
## 其他命令
`truth` 构建在通用的声明/证据引擎之上;`verify-turn` 是 agent 的正门。该引擎也可以直接使用:
```
check Check a single natural-language engineering claim
run Run a command and record a receipt (makes "tests pass" verifiable)
record-run Record a receipt for a command that already ran (hooks, CI)
stats The lie ledger: claims checked, contradictions caught, runs recorded
hook Install agent-harness hooks (verification the agent can't skip)
usage Observed usage of a route/event/pattern (deterministic)
errors Error occurrences (deterministic)
config Search indexed config/code definitions
owners Who has worked on the code behind a subject
uses Find code references to a symbol/route/dependency
docs Is a subject documented, and consistent with code?
inspect Show exactly what was indexed (trust the evidence)
doctor Validate local setup and explain readiness
claims/report/ci/eval/diff claim files, reports, CI gates, regression diffs
```
运行 `truth --help` 获取详细信息。`truth serve` (Slack/HTTP) 只是一个信息占位符,且是有意不进行构建的 —— 本地验证器才是核心产品。
## 测试
```
cargo test --workspace
```
涵盖了提取器(Rust/TS/Python/Go 路由、常量、环境变量、依赖项、文件/范围/重命名/计数/命令声明)、git-diff 适配器(修改过的行、文件状态、未追踪文件)、判定规则和黄金测试集(包括凭证时效性:通过但已过期的运行绝不能放行)、声明分段、hook 设置合并、索引时效性警告、JSON 输出,以及针对示例仓库的端到端检查。`truth eval fixtures/eval/agent_claims.yaml` 是用于保证 agent 事实核查质量的测试工具。
### 衡量提取质量
`fixtures/eval/extractor_corpus.yaml` 是一个**诊断语料库**,而非关卡:它使用多种方式表达相同的基准事实,包括正则表达式提取器*预期*会漏掉的复杂 `H*` 边缘情况。运行它来衡量声明提取目前达到了什么水平,以及更好的提取器(agent 提供的 `claims`、本地 LLM 或 AST)能改善些什么:
```
truth eval fixtures/eval/extractor_corpus.yaml
```
返回 `inconclusive` 的 `T*`/`H*` 用例属于**召回缺失**(提取器太弱);返回 `supported` 的 `F*` 用例属于危险的**误判**;而返回具体判定结果的 `R*` 用例则是**幻觉**。这些分类区间让这三种情况都清晰可见,从而使得各项改动可以被精确衡量,而不是靠瞎猜。
标签:AI编程助手, MCP服务器, SOC Prime, 代码核查, 可视化界面, 开发工具, 通知系统