关于 honestcode
HonestCode 是一个本地 MCP 服务,用于依据代码库中的符号和 API 检查编码 Agent 编写的 Python 代码。它通过 AST 验证并返回可采取行动的证据,无需调用大模型或访问网络。
主要功能
- 01检测虚构 API 和错误调用
- 02依据代码库解析符号
- 03返回结构化问题与证据
- 04提供结构性类型检查
- 05防止重试造成外部副作用重复
适用场景
- 01在编码 Agent 继续工作前验证其代码
- 02查找项目中不存在的方法
- 03向 Agent 提供问题证据以便修复
- 04工具调用重试时避免重复执行副作用
MCP 相关
HonestCode 向 MCP 客户端提供 `scan_file`、`verify_file` 等代码验证工具。可选工具还包括项目索引、符号检查和结构性类型验证。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
2收录的工具列表 · 更新于 6 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| file_path | string | 是 |
详细介绍
问题
AI 编码 Agent 会产生幻觉。它们会虚构函数名、捏造库 API,并调用不存在的方法。
HonestCode 会将 Agent 刚刚编写的内容与其应当依据的代码仓库进行核对。
Agent
↓
writes code
↓
HonestCode
↓
evidence
↓
Agent fixes
↓
verified code
不调用大模型。不联网。纯 AST + 符号解析。
演示
要求 Agent “使用现有的 UserClient 添加身份验证”。
它生成了:
client.refresh_token()
实际项目中只有:
class UserClient:
def refresh(self): ...
def refresh_access_token(self): ...
HonestCode 会以确定性方式捕获问题:
✗ verification failed — 1 issue in app/login_broken.py
[invented_api] app/login_broken.py:9
`UserClient.refresh_token()` does not exist.
did you mean: refresh_access_token()?
available methods:
- refresh()
- refresh_access_token()
confidence: deterministic · action: revise
亲自运行:
cd demos/invented-api
python run.py
为什么不直接使用 Ruff / Pyright?
HonestCode 并非替代品——它是一个验证层,用于回答一个具体问题:Agent 编写的代码是否确实来自这个代码仓库?
| 错误 | Ruff | Pyright | HonestCode |
|---|---|---|---|
| 语法错误 | ✓ | ✓ | ✓ |
| 类型不匹配 | — | ✓ | 仅结构检查 |
| 未定义符号 | ✓ | ✓ | ✓ |
| 虚构的 API | 部分支持 | 部分支持 | 核心功能 |
| 错误的方法调用 | — | 部分支持 | 核心功能 |
| Agent 生成的 API 不匹配 | — | — | 核心功能 |
关键区别在于以代码仓库为依据。Ruff 检查文件。Pyright 检查调用的类型。HonestCode 检查该调用是否解析到 Agent 正在编辑的代码库中实际存在的符号。(HonestCode 不会进行完整的类型推断——其结构检查能够捕获参数数量不匹配、遍历 None 和调用常量等问题,但无法发现一般的类型错误。)
调用点会根据接收者类型的已知方式进行检查:注解(client: UserClient)、构造函数赋值(client = UserClient())、self/cls 以及内联构造函数(UserClient().refresh())都会被解析。由工厂函数生成的接收者(make_client().refresh())不会被判定——函数签名在表层模型中不包含返回类型,在这种情况下进行推测会以误报代替漏报。
安装
一行命令——无需克隆仓库,也无需虚拟环境:
claude mcp add honestcode -- uvx honestcode-mcp
uvx 会在首次使用时将服务下载到隔离环境中;如果尚未安装 uv,请先安装。从检出目录运行(用于修改代码,或如果你不想使用 uv):
git clone https://github.com/Fengrru/honestcode
cd honestcode
pip install -e .
claude mcp add honestcode -- honestcode-mcp
Cursor / VS Code / Claude Desktop: honestcode install 命令会探测这些客户端的配置文件,并为你注册服务:
honestcode install # all detected clients
honestcode install --client cursor --dry-run # preview without writing
需要 Python >= 3.10。100% 本地运行。
使用 Claude Code,30 秒完成设置
# Add HonestCode as an MCP server
claude mcp add honestcode -- honestcode-mcp
也可以手动将其添加到 Claude Code 配置中(macOS/Linux 上为 ~/.claude.json,Windows 上为 %USERPROFILE%\.claude.json):
{
"mcpServers": {
"honestcode": {
"command": "honestcode-mcp",
"args": []
}
}
}
重启 Claude Code。现在你可以使用两个验证工具:
scan_file(path)— 旧版工具,返回issues以及新的证据结构。verify_file(path)— 面向 Agent 的工具,返回包含evidence的status、findings,以及易于阅读的text摘要。
试着向 Claude 提示:
Add a login endpoint using the existing UserClient, then run verify_file on the
file you just wrote and fix anything it reports.
HonestCode 会根据文件路径自动发现项目根目录、为代码库建立索引,并返回有据可依的证据。
自动执行(无需规范提示词)
只有模型选择调用时,MCP 工具才会运行。若要确保无条件验证,请将 scripts/claude_hook.py 钩子接入 Claude Code 的 PostToolUse 事件——Agent 写入的每个 .py 文件都会经过验证,发现的问题会阻止编辑,并将证据直接反馈到对话中:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "python /absolute/path/to/honestcode/scripts/claude_hook.py"
}
]
}
]
}
}
将其放入 ~/.claude/settings.json(适用于所有项目)或 .claude/settings.json(适用于单个项目)。钩子自身发生故障时绝不会阻止操作:输入无法读取、文件不是 Python 文件以及验证崩溃时,都会静默退出,因此绝不会变成阻止每次编辑的障碍。
实际示例
# auth/client.py
class UserClient:
def refresh_access_token(self): ...
# auth/login.py
from auth.client import UserClient
def login(client: UserClient):
client.refresh_token() # invented API
>>> from honestcode.mcp.tools import verify_file
>>> verify_file("auth/login.py")
{
"status": "fail",
"file": "auth/login.py",
"findings": [
{
"line": 7,
"kind": "invented_api",
"symbol": "refresh_token",
"owner": "UserClient",
"message": "`UserClient.refresh_token()` does not exist.",
"evidence": {
"available_methods": ["refresh", "refresh_access_token"],
"did_you_mean": "refresh_access_token"
},
"confidence": "deterministic",
"action": "revise"
}
],
"text": "✗ verification failed — 1 issue in auth/login.py\n ..."
}
Agent 输出协议
verify_file 返回的是 Agent 可直接采取行动的证据,而不只是错误消息:
{
"status": "fail",
"file": "auth/client.py",
"line": 42,
"kind": "invented_api",
"symbol": "refresh_token",
"owner": "UserClient",
"message": "UserClient.refresh_token() does not exist.",
"evidence": {
"available_methods": ["refresh", "refresh_access_token"]
},
"confidence": "deterministic",
"action": "revise"
}
工作原理
- 自动索引项目(或复用缓存的符号索引)。
- 使用标准库
ast模块解析目标文件。 - 将每个调用点解析为具体符号:
- 根据注解、构造函数和导入推断接收者类型;
- 根据仓库 AST 重建类的成员范围;
- 当无法解析基类或类定义了
__getattr__时,将成员范围标记为未知。
- 生成问题发现结果,其中包含
kind、owner、evidence、confidence和action。
此流程具有确定性,且可审计。
范围与局限
在无法证明目标不存在时,验证器会保持静默——这是它的特性,但也意味着检测存在已知边界:
- 不会判断装饰类是否使用了虚构成员。 任何类装饰器(包括
@dataclass)都可能添加或重写成员,因此不会报告这类对象上的虚构方法调用。未装饰的类会进行完整检查。 - 不会检查标准库成员调用。
from typing import TypeVarr(虚构的导入)会被捕获,但os.path.joinn()(对真实模块进行的虚构调用)不会——检查范围涵盖第三方成员和项目成员。 - 不会判断工厂函数的接收者。
make_client().refresh()会被跳过;注解、构造函数赋值、self/cls和内联构造函数(UserClient().refresh())都会被解析。 undefined_symbol的置信度为confidence: high,而不是deterministic。 只有成员范围声明(针对已完整枚举的类所作的虚构 API 判断)才能通过仓库证明;名称不存在的判断依赖语法绑定模型,因此置信度较低。同一作用域内类型会发生变化的变量会被视为未知,绝不会进行判断。- 图工具以最近一次索引的项目为准。
scan_file/verify_file会逐个文件解析项目根目录(包括单体仓库中的子项目);find_dead_code、explore_call_graph、search_code等工具则会操作最近一次传入index_project的项目。 check_api会按需导入基础包——但仅限该包确实已安装(或属于标准库)的情况。直接放入工作区的文件绝不会被导入,因此 Agent 编写的代码无法通过此工具在服务端执行。
MCP 工具
默认情况下会公开 scan_file 和 verify_file。设置 HONESTCODE_TOOLS=all
可启用完整工具集,包括:
| 工具 | 用途 |
|---|---|
scan_file | 扫描文件,查找虚构的 API、未定义的调用和错误的参数数量。 |
verify_file | 返回面向 Agent 的结构化证据协议。 |
index_project | 构建或复用项目符号索引。 |
load_project_deps | 从 requirements.txt / pyproject.toml 加载依赖 API。 |
check_symbol | 验证符号是否已定义。 |
check_api | 验证库 API 调用是否存在。 |
validate_types | 进行结构类型检查。 |
依赖清单(requirements.txt、pyproject.toml)会在首次扫描时自动声明,因此,即使依赖未安装在 MCP 服务的解释器中,其导入也会被视为可信,而不会报告为虚构内容。设置 HONESTCODE_AUTO_DEPS=0 可禁用此功能。
完整列表请参阅下方的旧版工具参考。
崩溃安全的副作用
verify_file 会在代码运行前检查代码。guards/ 则处理运行之后的情况:如果 Agent 重试工具调用,可能会重复扣款;没有任何持久化执行引擎能防止这种情况——Temporal 和 Restate 都保证编排过程的确定性重放,并将外部副作用的恰好一次执行留给应用程序处理。
from honestcode.guards import EffectStore, SideEffectGuard, durable_scope
guard = SideEffectGuard(session_id="run-42", store_path=".agent/effects.db")
outcome = guard.run(
"charge",
target="cus_123",
payload={"cents": 4200},
execute=lambda: charge_card("cus_123", 4200),
approve_irreversible=True,
scope=durable_scope("order-4711", "charge", "cus_123"),
)
outcome.executed # False on the retry — a receipt, not a second charge
outcome.effect_id # stable across a restart, because the key is on disk
关键在于 scope 的作用。传入它后,副作用的身份由作用域而非会话决定——这就是重试会被识别,而不是导致客户被重复扣款的区别,因为重启意味着新的会话 ID。不传入任何内容时,防护机制仍按会话限定。
默认策略是拒绝:无法识别的操作会被视为不可逆,而非幂等;不可逆副作用需要明确批准。如果运行在调用完成、记录尚未写入时终止,该副作用会保留为 executing,下一次尝试会报告结果未知,而不是自行推测——这正是阻止重试的机制。可通过 guard.recover(scope=durable_scope(...)) 恢复限定作用域的副作用,并通过 guard.effects(scope=...) / guard.summary(scope=...) 查看;记录存储在由作用域派生的命名空间下,因此重启后仍能找到。
对于框架,integrations/ 会将防护机制绑定到 pydantic-ai,在此场景下,已提交的副作用会替代工具结果,而不是重新运行工具。请参阅 honestcode/integrations/README.md。
基准测试
HonestCode 包含四套基准测试,它们会在每次向 main 推送或提交拉取请求时,在 CI 中自动运行:
Agent 准确率基准测试
benchmarks/agent_accuracy/ 是一个确定性的、无需 LLM 的基准测试,用于衡量 HonestCode 捕获常见 Agent 幻觉的能力(召回率)。
每项任务都是一个微型 Agent 会话:Agent 编写一个有问题的文件,HonestCode 对其进行验证,然后用修复后的文件替换该文件并再次验证。
cd benchmarks/agent_accuracy
python run.py
当前结果(6 项任务,确定性验证):
| 任务 | 预期问题 | 检测到问题文件 | 修复后干净 | 问题文件耗时(毫秒) | 修复后耗时(毫秒) |
|---|---|---|---|---|---|
| invented_method | invented_api(UserClient.refresh_token) | 是 | 是 | 4.18 | 3.78 |
| invented_module_attr | invented_api(Connection.query) | 是 | 是 | 4.19 | 3.95 |
| undefined_import | undefined_symbol(delete_user) | 是 | 是 | 2.69 | 3.55 |
| wrong_signature | wrong_call(add()) | 是 | 是 | 3.56 | 3.35 |
| cross_file_new_symbol | invented_api(fly) | 是 | 是 | 3.85 | 2.45 |
| dep_alias_and_pypi_name | invented_api(toll) | 是 | 是 | 3.44 | 2.9 |
**摘要:**精确率 1.0、召回率 1.0、F1 1.0、假阳性率 0.0;在笔记本电脑上的中位验证耗时为 4–7 毫秒。
上方每项任务的毫秒数是某次运行的输出,并非保证值——同一台机器上不同运行之间会有几十个百分点的波动。基准测试实际稳定且作为门槛依据的,是前四列以及摘要中的计数。
摘要行直接取自 python benchmarks/agent_accuracy/run.py 的原样输出,而不是复制到此文件中的数值,因为此处引用的耗时会在代码变快的瞬间过时——之前就发生过这种情况。使用 --format markdown 即可复现。
cross_file_new_symbol 任务锁定 Agent 会话流程(先写入一个模块,再写入导入该模块的文件——索引必须是最新的,绝不能过时);dep_alias_and_pypi_name 任务锁定通过别名子模块和 PyPI 命名的依赖项进行依赖依据验证(PyYAML → yaml)。
真实场景假阳性基准测试
benchmarks/realworld_fp/ 用于衡量真实代码上的精确率:它扫描 psf/requests 的一份 vendored 快照(19 个文件,约 6.4k 行代码,Apache-2.0),并断言 HonestCode 报告的发现数为零。真实代码会用到合成任务从未涉及的结构——标准库导入、关键字调用风格、@staticmethod 成员、继承标准库 ABC 的类、兼容性重新导出模块——按定义,此代码库中的任何发现都属于假阳性。
同一轮运行还会扫描 benchmarks/realworld_fp/regressions/:每种在实际使用中发现的假阳性类型各对应一个微型项目(跨类型重新绑定的接收者、with ... as 绑定、monorepo 子项目导入、本地绑定形式)。如果回归问题再次出现,基准测试会按名称标出失败的场景。
python benchmarks/realworld_fp/run.py
# files: 25 findings: 0 elapsed: 0.7s (~26 ms/file)
发现数量才是要验证的主张;耗时仅供参考,且会随机器而变化。
值漂移基准测试
benchmarks/value_drift/ 关注另一个问题:当一个容忍格式差异的编辑匹配器解析搜索字符串时,编辑是否落在调用方指定的区域,还是悄无声息地落在带有不同值的近似匹配项上?该基准测试在有保护和无保护的匹配器级联中运行十种场景,并将每次编辑归类为 correct、silent_drift、no_match 或 wrong_span。有保护的匹配器必须在每种场景中都完成预期编辑;no_match 表示拒绝匹配,并不算通过。
python benchmarks/value_drift/run.py # human-readable
python benchmarks/value_drift/run.py --json # machine-readable (status on stderr)
性能基准测试
scripts/benchmark.py 测量核心操作(索引、扫描、图谱、死代码检测、相似性搜索)在仓库本身上的延迟。
python scripts/benchmark.py # text output
python scripts/benchmark.py --format markdown # table for README
python scripts/benchmark.py --repo psf/requests # benchmark a real-world repo
所有四项基准测试都会在 CI(.github/workflows/ci.yml)中作为独立作业运行:
benchmark-accuracy、benchmark-realworld、benchmark-value-drift 和
benchmark-performance。准确性作业要求精确率和召回率保持在 1.0,真实场景作业要求没有任何发现或扫描失败,价值漂移作业要求每个受保护场景都能正确命中。性能作业只报告数值,不会据此设定门槛。
数据集格式以及如何添加新的准确性任务,请参阅 benchmarks/agent_accuracy/README.md。
架构
honestcode/
├── verify/ # Evidence protocol + repository-grounded verification
├── mcp/ # MCP server layer
├── honest/ # Symbol index + project binding
├── graph/ # Persistent call graph (SQLite)
├── structure/ # AST extraction
├── sandbox/ # Sandboxed execution
├── guards/ # Crash-safe side effects (stdlib-only, extractable)
├── integrations/ # Framework bindings — pydantic-ai today
└── cli.py # Command-line interface
verify_file 是 Agent 接口。默认情况下,scan_file 也会与它一同开放,并同时返回新的证据结构和旧版 issues 列表。
其中两个目录回答的问题与其他目录不同。guards/ 以上的所有内容都在问:这段代码是否与仓库一致? guards/ 则在问:这个效果是否已经发生? Agent 在崩溃后重试工具调用,可能会重复扣款;而持久化执行引擎会将外部效果的恰好一次执行交给应用处理。integrations/ 将守护机制绑定到框架;pydantic-ai 的 wrap_tool_execute 是首个集成,如果效果已经提交,则会替换工具结果,而不是重新运行工具。
guards/ 有意仅依赖标准库,不依赖此软件包的协议,因此可以提取为独立发行包。tests/test_guards.py 通过 AST 导入检查确保这一点。
路线图
v0.1 — 仓库依据(已完成)
- 符号 / API / 函数 / 类 / 方法 / 导入 / 调用验证
- 检测虚构 API 并提供结构化证据
- 在
scan_file中自动建立索引
路线图之外 — 崩溃安全的副作用(当前)
这不是验证层,因此不属于下文 v0.2/v0.3 的迭代顺序:
guards/ 可确保效果在崩溃后仍具幂等性,integrations/ 则将其绑定到 pydantic-ai。它回答的是“这件事是否已经发生”,这是一个运行时问题,而非静态问题。
v0.2 — 语义契约验证
- 函数需要
UserID,Agent 却传入User→ 可疑
v0.3 — 执行验证
- 静态验证 → 测试 → 运行时证据
v1.0 — 面向编码 Agent 的验证运行时
Coding Agent
│
┌───────▼───────┐
│ HonestCode │
│ Verification │
│ Runtime │
└───────┬───────┘
│
┌──────────────┼──────────────┐
↓ ↓ ↓
Static Semantic Runtime
Verification Verification Verification
│ │ │
└──────────────┼──────────────┘
↓
Evidence
↓
Agent
开发
git clone https://github.com/Fengrru/honestcode.git
cd honestcode
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # macOS/Linux
pip install -e ".[dev]"
pytest
ruff check honestcode tests scripts
在本地运行基准测试:
# Accuracy benchmark
python benchmarks/agent_accuracy/run.py
# Performance benchmark
python scripts/benchmark.py
拉取请求指南请参阅 CONTRIBUTING.md。
安全
漏洞报告请参阅 SECURITY.md。
遥测
HonestCode 不收集任何遥测数据。 没有分析库、 后台服务或回传数据的端点。
许可证
MIT - 版权所有 (c) 2026 HonestCode Team
MCP Registry:mcp-name: io.github.Fengrru/honestcode
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。
