
Honestcode
io.github.Fengrru由 GitHub 帳號 Fengrru 發布v0.5.1更新於 Oct 25, 2026
Deterministic verification for AI coding agents: catches invented APIs and wrong calls.
概覽
一個本機 MCP 伺服器,把 AI 編碼代理剛寫的程式碼對照儲存庫中真實存在的符號,找出憑空捏造的 API 與錯誤呼叫。
- 可以做什麼
- 驗證剛寫入的檔案,回傳附證據、修正建議與文字摘要的結構化結果,或用舊版掃描取得同類問題加一份普通清單。建立或重用專案符號索引,並從 requirements 或 pyproject 清單載入相依套件 API。檢查某個符號是否已定義、某個函式庫 API 呼叫是否存在,並做結構化型別檢查。啟用完整工具集後,可透過呼叫圖、死程式碼與程式碼搜尋工具瀏覽已索引的專案。
- 適用情境
- 當 AI 編碼代理在真實儲存庫中撰寫 Python 程式碼,希望在代理繼續下一步前找出捏造的方法、未定義名稱與參數個數錯誤時,適合安裝。它可作為確定性的離線檢查,與 linter 和型別檢查器並用,而非取代它們。
- 執行需求
- 以本機程序執行;README 使用 uvx(需先安裝 uv)或從程式碼檢出後以 pip 安裝,需要 Python 3.10 或更新版本。不需網路、API 金鑰或帳號;README 稱完全在本機執行且不收集遙測。完整工具集透過 HONESTCODE_TOOLS 環境變數啟用。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Honestcode,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
HonestCode
The deterministic verification layer for AI coding agents.
Catch invented APIs, undefined symbols, wrong calls, and other code hallucinations before your agent moves on.
The problem
AI coding agents hallucinate. They invent function names, fabricate library APIs, and call methods that do not exist.
HonestCode is the layer that checks what the agent just wrote against the repository it is supposed to be grounded in.
No LLM calls. No network. Pure AST + symbol resolution.
Demo
The agent was asked to "add authentication using the existing UserClient."
It generated:
The real project only has:
HonestCode catches it deterministically:
Run it yourself:
Why not just use Ruff / Pyright?
HonestCode is not a replacement — it is a verification layer that answers a specific question: did the agent's code actually come from this repository?
The key difference is repository grounding. Ruff checks the file. Pyright
types the call. HonestCode checks whether the call resolves to a real symbol
that exists in the codebase the agent is editing. (HonestCode does not do full
type inference — its structural checks catch mismatched arities, iterating
None, and calling constants, not general type errors.)
What a call site is checked against depends on how the receiver's type is known:
an annotation (client: UserClient), a constructor assignment
(client = UserClient()), self/cls, and an inline constructor
(UserClient().refresh()) are all resolved. A receiver produced by a factory
function (make_client().refresh()) is not judged — function signatures
carry no return type in the surface model, and guessing there would trade a
missed finding for a false one.
Install
One line — no clone, no virtualenv:
uvx fetches the server into an isolated environment on first use; install
uv first if you do not have it. From a checkout
(to hack on the code, or if you prefer not to use uv):
Cursor / VS Code / Claude Desktop: the honestcode install command probes
those clients' config files and registers the server for you:
Requires Python >= 3.10. 100% local.
30-second setup with Claude Code
Or add it manually to your Claude Code config (~/.claude.json on
macOS/Linux, %USERPROFILE%\.claude.json on Windows):
Restart Claude Code. You now have two verification tools available:
scan_file(path)— legacy tool, returnsissuesplus the new evidence shape.verify_file(path)— agent-facing tool, returnsstatus,findingswithevidence, and a human-readabletextsummary.
Try prompting Claude:
HonestCode auto-discovers the project root from the file path, indexes the codebase, and returns grounded evidence.
Making it automatic (no prompt discipline required)
MCP tools only run when the model chooses to call them. To make verification
unconditional, wire the hook in scripts/claude_hook.py into Claude Code's
PostToolUse event — every .py file the agent writes is verified, and a
finding blocks the edit with the evidence fed straight back into the
conversation:
Put that in ~/.claude/settings.json (all projects) or
.claude/settings.json (one project). The hook never blocks on its own
failures: unreadable input, non-Python files, and verification crashes all
exit silently, so it can never turn into a wall that blocks every edit.
Real example
Agent output protocol
verify_file returns evidence an agent can act on directly, not just an error
message:
How it works
- Auto-index the project (or reuse the cached symbol index).
- Parse the target file with the standard-library
astmodule. - Resolve every call site to a concrete symbol:
- infer the receiver type from annotations, constructors, and imports;
- reconstruct the class's member surface from the repository AST;
- mark the surface as unknown when a base class cannot be resolved or the
class defines
__getattr__.
- Emit findings with
kind,owner,evidence,confidence, andaction.
The loop is deterministic and auditable.
Scope and limitations
The verifier stays silent wherever it cannot prove absence — that is the feature, but it means detection has known boundaries:
- Decorated classes are not judged for invented members. Any class
decorator (including
@dataclass) may add or rewrite members, so invented method calls on such classes are not reported. Undecorated classes are fully checked. - Standard-library member calls are not checked.
from typing import TypeVarr(an invented import) is caught, butos.path.joinn()(an invented call on a real module) is not — third-party and project members are the covered surface. - Factory-function receivers are not judged.
make_client().refresh()is skipped; annotations, constructor assignments,self/cls, and inline constructors (UserClient().refresh()) are resolved. undefined_symbolcarriesconfidence: high, notdeterministic. Only member-surface claims (invented APIs on a fully enumerated class) are provable from the repository; name absence rests on the syntactic binding model and keeps the lower confidence. Variables reassigned across types in one scope are treated as unknown and never judged.- Graph tools are anchored to the last indexed project.
scan_file/verify_fileresolve the project root per file (including monorepo sub-projects);find_dead_code,explore_call_graph,search_codeand friends operate on the project most recently passed toindex_project. check_apiimports the base package on demand — but only when it is genuinely installed (or stdlib). A bare file dropped into the workspace is never imported, so agent-authored code cannot be executed server-side through this tool.
MCP tools
By default scan_file and verify_file are exposed. Set HONESTCODE_TOOLS=all
to enable the full set, including:
Dependency manifests (requirements.txt, pyproject.toml) are declared
automatically on the first scan, so imports from a dependency that is not
installed in the MCP server's interpreter are trusted rather than reported as
invented. Set HONESTCODE_AUTO_DEPS=0 to disable that.
See the old tool reference below for the complete list.
Crash-safe side effects
verify_file checks code before it runs. guards/ covers what happens after:
an agent that retries a tool call can charge a card twice, and no durable
execution engine prevents it — Temporal and Restate both guarantee deterministic
replay of orchestration and leave exactly-once external effects to the
application.
The interesting part is what scope does. Pass it and the effect's identity
comes from the scope rather than the session — which is the difference between a
retry being recognised and a customer being charged twice, because a restart is
a new session id. Pass nothing and the guard stays session-scoped.
Refusing is the default direction: an unrecognised action is treated as
irreversible rather than idempotent, and irreversible effects need explicit
approval. A run that dies between the call and the record leaves the effect
executing, and the next attempt reports the outcome as unknown instead of
guessing — which is what stops the retry. Scoped effects are recovered with
guard.recover(scope=durable_scope(...)), and guard.effects(scope=...) /
guard.summary(scope=...) report them; the records live under a namespace
derived from the scope so a restart can still find them.
For a framework, integrations/ binds the guard to pydantic-ai, where a
committed effect replaces the tool result instead of re-running the tool. See
honestcode/integrations/README.md.
Benchmark
HonestCode includes four benchmark suites that run automatically in CI on every
push and pull request to main:
Agent-accuracy benchmark
benchmarks/agent_accuracy/ is a deterministic, LLM-free benchmark that
measures how well HonestCode catches common agent hallucinations (recall).
Each task is a tiny agent episode: the agent writes a broken file, HonestCode verifies it, then the file is replaced with the fix and verified again.
Current results (6 tasks, deterministic verification):
Summary: precision 1.0, recall 1.0, F1 1.0, false-positive rate 0.0, median verify time 4–7 ms on a laptop.
The per-task milliseconds above are one run's output, not a guarantee — they move a few tens of percent between runs on the same machine. What is stable, and what the benchmark is gating on, is the first four columns plus the summary's counts.
The summary line is python benchmarks/agent_accuracy/run.py verbatim rather
than a figure copied into this file, because a timing quoted here goes stale the
moment the code gets faster — as one did. Reproduce it with --format markdown.
The cross_file_new_symbol task pins the agent-session flow (write a module,
then a file importing it — the index must be fresh, never stale); the
dep_alias_and_pypi_name task pins dependency grounding through aliased
submodules and PyPI-named requirements (PyYAML → yaml).
Real-world false-positive benchmark
benchmarks/realworld_fp/ measures precision on real code: it scans a
vendored snapshot of psf/requests (19 files, ~6.4k LOC, Apache-2.0) and
asserts HonestCode reports zero findings. Real code exercises the
constructs synthetic tasks never do — stdlib imports, keyword-call style,
@staticmethod members, classes inheriting stdlib ABCs, compat re-export
modules — and any finding on this corpus is, by construction, a false
positive.
The same run also scans benchmarks/realworld_fp/regressions/: one tiny
project per false-positive class found in the wild (a receiver rebound across
types, with ... as bindings, monorepo sub-project imports, local binding
forms). Each scenario fails the benchmark by name if the regression returns.
The finding count is the claim; the elapsed time is indicative, and varies with the machine.
Value-drift benchmark
benchmarks/value_drift/ asks a different question: when a formatting-tolerant
edit matcher resolves a search string, did the edit land on the region the
caller named, or silently on a near-miss sibling that carries a different value?
It runs ten scenarios across a guarded matcher cascade and an unguarded one, and
classifies each edit as correct, silent_drift, no_match, or wrong_span.
The guarded matcher must produce the intended edit on every scenario; a
no_match is a refusal, not a pass.
Performance benchmark
scripts/benchmark.py measures the latency of core operations (index, scan,
graph, dead code detection, similarity search) on the repository itself.
All four benchmarks run in CI (.github/workflows/ci.yml) as separate jobs:
benchmark-accuracy, benchmark-realworld, benchmark-value-drift, and
benchmark-performance. The accuracy job gates on precision and recall staying
at 1.0, the real-world job on any finding or failed scan, and the value-drift
job on every guarded scenario landing correctly. The performance job reports
numbers rather than gating on them.
See benchmarks/agent_accuracy/README.md for the dataset format and how to
add new accuracy tasks.
Architecture
verify_file is the agent interface. scan_file is exposed alongside it by
default and returns both the new evidence shape and the legacy issues list.
Two of those directories answer a different question from the rest. Everything
above guards/ asks is this code consistent with the repository. guards/
asks did this effect already happen — an agent that retries a tool call after
a crash can charge a card twice, and durable-execution engines leave exactly-once
external effects to the application. integrations/ binds the guard to a
framework; pydantic-ai's wrap_tool_execute is the first, and a tool result is
replaced rather than re-run when the effect has already been committed.
guards/ is deliberately stdlib-only and does not depend on this package's
protocols, so it can be extracted into its own distribution. tests/test_guards.py
enforces that with an AST import check.
Roadmap
v0.1 — Repository grounding (done)
- symbol / API / function / class / method / import / call verification
- invented API detection with structured evidence
- auto-index on
scan_file
Beyond the roadmap — crash-safe side effects (now)
Not a verification layer, so it has no place in the v0.2/v0.3 sequence below:
guards/ makes an effect idempotent across a crash, and integrations/ binds
it to pydantic-ai. It answers "did this already happen", which is a runtime
question rather than a static one.
v0.2 — Semantic contract verification
- function expects
UserID, agent passesUser→ suspicious
v0.3 — Execution verification
- static verification → tests → runtime evidence
v1.0 — Verification Runtime for Coding Agents
Development
Run benchmarks locally:
See CONTRIBUTING.md for pull request guidelines.
Security
See SECURITY.md for vulnerability reporting.
Telemetry
HonestCode collects no telemetry. There are no analytics libraries, no background services, and no phone-home endpoints.
License
MIT - Copyright (c) 2026 HonestCode Team
MCP Registry: mcp-name: io.github.Fengrru/honestcode
來源:README.md,提交 972bf91
工具
0版本歷史
1- v0.5.1最新Oct 25, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分