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 无法通过巧言令色改变判定结果。** ![verify_turn MCP 调用抓取 agent 虚假声明的演示](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/d46e86a75a105926.gif) 真实命令,真实输出: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, 代码核查, 可视化界面, 开发工具, 通知系统