Reverify
A verifier for an AI’s claims about binaries: the model proposes, a deterministic toolkit checks the claim against the actual bytes, and what comes back is VERIFIED, REFUTED or INCONCLUSIVE with the evidence it read — the verdicts, not the prose, are what survives a reset.

What it is
A verification layer for coding agents working on binaries: a Python package with a CLI and an MCP server. Its own description is the clearest account of the idea — “it proposes, deterministic tools decide, every claim checked against ground truth with evidence”. A model proposes a claim; the tools check it against the actual bytes and answer VERIFIED, REFUTED or INCONCLUSIVE with the evidence they read. In the repository that deterministic half is code: verifier.py holds the claim kinds and the verdicts, binary.py and pe_parser.py parse PE, ELF and Mach-O, disasm.py disassembles, emulator.py emulates, behavior.py runs a reconstruction beside the original, semantic.py stands on angr, and backends.py reports the active engines. Install the pure-Python core with pip install reverify, add capstone, unicorn, lief and Z3 with pip install "reverify[full]", and angr with pip install "reverify[angr]"; then check a claim with reverify verify, triage a file with reverify auto sample.bin --json, or serve the MCP server with python reverify/mcp_server.py.
Who built itThe account that owns the repository wrote 74 of its 83 commits, 89% of the total; one outside contributor, IMGillusion, wrote five and dependabot three, with one commit carrying no linked account. Seventy-four commits carry a co-author trailer, and 71 of those name a Claude model — Fable 5.1 on 47, Opus 4.8 on 21, Sonnet 5 on 3.
How it is put together
The parts · 6A claim-and-verdict split with a deterministic toolkit as the judge, and three consequences that shape the whole repository. The first is where trust sits: the model may propose anything, but a fact is only what a tool reported, so every verdict carries the bytes it observed and a receipt — binary SHA-256, version, which engines judged — and the claim kinds are chosen to be checkable: typed reads, patterns, mnemonics, emulation, differential execution, a Z3 proof, angr-derived call edges. The second is graded strength rather than one word: proven above tested above observed, engine-derived semantic verdicts recorded at a DERIVED tier below VERIFIED, and INCONCLUSIVE — never a guess — when the capability is absent. The third is that state is derived from verdicts rather than from prose: the per-binary ledger keeps verified, observed, proved and refuted results and is keyed by content, so a fresh session or a new process resumes from the same grounded position, and the model’s own notes travel only when labelled unverified. Soundness is treated as a measurement rather than an assertion: a benchmark and a per-kind confusion matrix run in CI on three platforms and fail the build on a single false VERIFIED, with each run leaving a record of every file hash and verdict.
- reverify/
- The package: 23 files, 436 KB.
verifier.py(60 KB) holds the claim kinds and the verdicts;cli.py(39 KB) is the command surface;agent.py(28 KB) runs the propose-and-verify loop;rollover.py(27 KB) androllover_harness.py(97 KB) own the session hand-off;ledger.py(27 KB) keeps the per-binary state;mcp_server.py(21 KB) exposes the same tools over MCP.behavior.py,emulator.py,disasm.py,binary.py,pe_parser.py,semantic.py,exebench.pyandprotocol_parser.pyare the readers and the judges,sandbox.pybounds native execution,boundary_auditor.pyandfrida_bridge.pyare the two side utilities,backends.pyreports which engines are installed, andplugins/opencode/reverify-rollover.js(6.6 KB) is the one plugin, shipped as package data. - reverify/tests/
- Twenty-nine files, 244 KB — about 36% of the package’s Python by size. The largest is
test_rollover_harness.py(42 KB); the ones that carry the argument aretest_differential.pyandtest_oracle.py, which check the readers against lief, capstone, objdump and hand-verified vectors instead of written-out expectations, alongsidetest_verifier.py,test_probes.py,test_hardening.pyandtest_mcp.py. Run withpython -m unittest discover -s reverify/tests -p "test_*.py". - benchmarks/ and benchmarks/results/
- Nine benchmark files (65 KB) over a five-file corpus (19 KB) and fifteen committed run records (605 KB — by far the largest directory in the repository).
prologue_prior.py,hallucination_probes.pyandverifier_matrix.pyare the three gated measurements;reconstructions.pyandreexec_dataset.pyare the re-executability side;model_loop.pydrives a real model through an OpenAI-compatible endpoint; the corpus holds two C libraries plusreconstructions.jsonlandreexec_sample.jsonl; the results directory holds the JSON records with every file’s SHA-256, every verdict and the tool versions. - .github/
- Seven workflows (14 KB) and a 4.6 KB review script.
ci.yml(6 KB) runs the suite and both gated benchmarks on three platforms and fails on a single false VERIFIED;release.ymlpublishes to PyPI;angr.yml,model-eval.yml,fuzz.yml(20,000 malformed inputs nightly) andscorecard.ymlare the rest. Three issue templates include a dedicated false-VERIFIED report form, andcodex_review.pyis driven bycodex-review.yml. - Repository root
- Thirteen files, 95 KB — and the design lives here rather than in a design document.
README.md(26,462 characters) describes the verification loop, the ledger and the semantic layer;BENCHMARK.md(15 KB) is the measurement and its honest reading;ROADMAP.md(4.8 KB) names the two intended moats and orders the work;CONTRIBUTING.md(2.6 KB) states the one rule the project is built around;CHANGELOG.mdis 39 KB;pyproject.tomldeclares zero required dependencies and two entry points,reverifyandreverify-mcp. - docs/
- One file:
docs/demo.svg, 2.2 KB, the terminal recording embedded in the README. There is no architecture document anywhere in the repository — the design is in the README, the roadmap and the contributing guide — which is why this structure is read from the file tree and those documents rather than from a specification.
Choices, and what they beat
A pure-Python deterministic core, with the mature engines as optional extras over depending on capstone, unicorn, lief, Z3 or Ghidra from the start
Stated in the README and in the packaging: “Pure Python out of the box; installs clean with no Ghidra”,
pip install "reverify[full]"upgrades the toolkit in place, and when an engine is missing it falls back to the core — “Not installed? It falls back to the pure-Python core.” CONTRIBUTING keeps that load-bearing: “The pure-Python fallback must keep working with no compiled dependencies; CI checks that too.”pyproject.tomllists no required dependencies.Stand on angr for functions and cross-references and keep the project’s own part thin over writing its own function-boundary and CFG analysis, or letting the model guess
README: “Reverify does not build one. It stands on angr ... and keeps its own part thin: an engine-neutral view of functions, call edges, data references and reachability.” The honesty rule attached to it: CFGFast “is heuristic and can miss or split functions”, so semantic verdicts “name the engine and are recorded at a DERIVED tier below VERIFIED”, and without an engine the fallback knows only what is independently certain and answers INCONCLUSIVE “never a guess”.
Native execution is off unless an environment variable turns it on over letting the ExeBench claim compile and run a caller-supplied C source whenever it is asked
The maintainer’s reason on pull request 11: “behavior_equiv runs code under Unicorn; this one compiles and runs it on the host, so a claim’s c_source is arbitrary code — reachable by any agent through the MCP server. It now returns INCONCLUSIVE with a hint unless REVERIFY_ALLOW_NATIVE_EXEC=1 is set (never for an MCP server exposed to untrusted agents without a sandbox).”
Replace the session instead of summarizing it, and fail closed if the hand-off is missing over a model-written compaction summary of the transcript
README: “instead of a lossy auto-summary, reverify rollover hands the session off to a file and starts a fresh one”. The hand-off is “written while the model still has the whole context, into a file with a fixed shape, separated from verified facts (memory files, the ledger) — and the conversation that produced it is dropped, not paraphrased. Zero dependencies; the hooks fail open, the rollover fails closed.” The receipt that follows carries the transcript’s SHA-256 and the user’s verbatim first and latest messages.
Score a verified claim by what the binary says about it over counting verified claims, where “every claim verified” is the goal
README: “Every claim verified is trivially reachable: assert that the file starts with MZ and that .text exists.” So weight is “zero for claims that merely restate the fact sheet the model was shown, for duplicates ... otherwise measured from the binary itself — how often the expected content occurs in this file and how much entropy it has”, and a reconstruction is grounded only when nothing is refuted and the verified weight reaches
--min-information(default 1.0) — which the README says follows the CORE refinement of FActScore.
Read fromNo design document exists in the repository: docs/ holds a single file, docs/demo.svg, and no file in the 109-file tree is named for an architecture or a design. This description is therefore read from the tree and its directory sizes, from pyproject.toml, and from the prose that does exist — the README (26,462 characters: “What Reverify does”, “The verification loop”, “The ledger”, “The semantic layer” and the toolkit table), ROADMAP.md, CONTRIBUTING.md, BENCHMARK.md, benchmarks/README.md, EXAMPLE.md and the pull-request bodies.
Build log
6 stages- 01
Six days, eighty-three commits, fifteen releases
The repository was created on 2026-08-31. Its first commit — “Reverify v0.0.0 - verified reverse-engineering toolkit” — landed on 2026-09-02, and its last on 2026-09-07: a change pinning CI dependency versions, reviewed as pull request 18. All 83 commits fall inside September 2026 and all 15 releases fall inside three days, from
v0.1.0(“verification core”) at 14:15 on 2026-09-02 tov0.11.0(“lossless context rollover across Claude Code, Codex, Gemini CLI, OpenCode”) at 18:13 on 2026-09-04; av0.0.0tag exists with no release behind it. The commit signature is the part worth reading. The owner’s account wrote 74 of the 83; the outside contributor IMGillusion wrote five, dependabot three, and one commit has no linked account. Seventy-four commits carry a co-author trailer, 71 of them naming a Claude model — Fable 5.1 on 47, Opus 4.8 on 21 and Sonnet 5 on 3. Nothing has been pushed since 2026-09-07, and the repository stands at 1,252 stars and 237 forks. - 02
The claim is the unit of work, and the tools are the judge
reverify verifytakes a claim about a binary and returns VERIFIED, REFUTED or INCONCLUSIVE with the bytes the tools actually read; the claim is JSON,--claims-filebatches them, a claim can declaredepends_onso a refuted root invalidates what was built on it, and the command exits non-zero if anything is refuted, so a CI job can gate on a grounded reconstruction. The kinds map onto the deterministic core: typed reads (u16_at,u32_at,u64_at),pattern_present,string_present,instructions,emulate_result,behavior_equiv(run the original and a candidate over shared inputs),prove_equiv(Z3, for all inputs),protobuf_field,import_present,export_present,section_present, and the angr-backedfunction_at,calls,referencesandreachable_from_entry. Success is not “everything verified”: the README calls that condition trivially reachable — assert that the file starts withMZand that.textexists — so each result carries a weight measured from the binary itself, zero for restatements, duplicates and echoes of the tools’ own output, and a reconstruction counts as grounded only when nothing is refuted and the verified weight reaches--min-information.reverify reconstruct --samples Ndraws several proposals per round and lets the verifier, not the model’s confidence, choose among them. - 03
The proving ground the author chose: reverse engineering
Where the numbers come from is the author’s own framing, not an outside judgement: the README says binary reverse engineering is “the hardest place to prove the first point ... so that’s where the numbers come from”, and the repository’s one-line description ends with “Reverse engineering is the proving ground.” The probe applies a fixed model prior blind — “a language model asked what a function’s entry prologue looks like tends to answer the textbook frame-pointer prologue
push rbp ; mov rbp, rsp” — and only the verifier judges it. On 71 real Windows system files the prior was wrong 69 times, 97%, and the verifier marked 0 wrong claims VERIFIED; the same gate runs in CI on Linux, Windows and macOS on every push, “and fails the build if a single wrong claim is VERIFIED”. Those three runner datasets were wrong 40 of 40, 77 of 77 and 68 of 68, with zero false accepts, and pooled with the reference run and a contributor’s aarch64 run they come to 275 binaries across four formats, 0 false VERIFIED. The benchmark document is explicit about what that means — “0/71 means the rate is below about 5% with 95% confidence, not that it is zero” — and that this prior is one probe at entry points rather than a survey. - 04
A test suite that also checks the checkers
The project’s claim is that a deterministic tool can settle these questions, so the test layout is part of the argument. Of the 109 files in the tree, 29 are tests — 244 KB against the 436 KB of the package they cover, about 36% of the Python by size — and the largest of them,
test_rollover_harness.pyat 42 KB, mirrors the largest source file in the repository,rollover_harness.pyat 97 KB.verifier.py, the judge itself, is the biggest single module at 60 KB. The suite is not the only check: CONTRIBUTING asks for “a test that would fail without it” and prefers “a differential or known-answer test over a hand-written expectation” for anything touching a reader, and the README says the readers are checked “by independent judges, not by its own tests” — the pure parser against lief on real binaries, the disassembler against capstone, binutils objdump and hand-verified vectors, the emulator against Unicorn, the semantic engine against the export table — with CI running with and without the optional engines, on Python 3.9 and 3.13, and a nightly job that fuzzes 20,000 malformed inputs. The published test count is not current: the README’s status section still reads “Tested with 208 unit tests” atv0.9.0, whilepyproject.tomland the latest release are0.11.0; a pull request opened on 2026-09-11 reports “377 tests pass locally”, with 62 optional-engine skips. - 05
The other half: state that survives a reset
The second job is keeping an agent’s context honest, and it has the more unusual design.
v0.8.0began writing the loop’s state to disk as it happens:.reverify/ledger/<sha256>.json, one ledger per binary, content-keyed so a renamed copy shares its ledger, checkpointed after every round, with refutations kept as KNOWN FALSE so a fresh context does not re-propose the same wrong prior — and only what a tool verified, observed, proved or refuted is written, with the model’s own notes excluded on purpose.reverify rolloverapplies the same rule to an interactive session in Claude Code, Codex, Gemini CLI or OpenCode: built-in compaction is turned off, the model writes a hand-off file with fixed sections, a guard at the harness’s stop hook blocks one stop and demands it, and a receipt is written only after the guard has checked that the hand-off was really rewritten and is well-formed — carrying the transcript’s SHA-256 and the user’s verbatim first and latest messages.installwires four harnesses, each with a backup and a matchinguninstall;doctorreports receipts that no launcher consumed, which is the failure the documentation names: a session started outside the launcher “has no ceiling (one measured session reached 909k tokens before its owner noticed)”. - 06
What the issue tracker did to the design
Issue 14 is the tracker’s best round: an open-ended goal made the model drift off the structured kinds. On
/usr/bin/ls, asked to “find the dynamic import list”, it produced 14 verifiedimport_presentclaims; on/usr/bin/cat, asked for “the binary dynamically imports the close function from libc”, it produced no import claims at all and never finished, only raw byte reads. The cause was a RULES block inagent.pyrecommending only the raw kinds; the fix is one appended line, and the thread carries a before-and-after: 0 of 2 structured claims unpatched, 100% with the nudge. Pull request 11 shows the same standard from the maintainer’s side: he pushed the required changes onto a contributor’s branch rather than sending it back, one making native execution opt in. Against that, three reports about the verifier itself were unanswered at this record’s sampling: issue 22, where claims that assert nothing — an empty string, an all-wildcard pattern, zero bytes — come back VERIFIED and carry weight; pull request 21, the fix for it, open with only bot comments; and issue 23, whereimport_presentsilently degrades to a DLL-only check when the symbol field is misnamed and returns VERIFIED, reproduced the next day over MCP againstnotepad.exe. By the project’s own rule that is the most valuable report it can receive, and what its zero-false-accept number rests on.
Adjacent records
All records →No. 081
pgbot
A single static Go binary that connects to PostgreSQL read-only, reads the server’s own statistics views and prints a graded, findings-first health report — and, because every run saves a local baseline, tells you what changed since last time; the same deterministic findings are served to AI agents over MCP, and the optional AI layer may only explain them.
No. 080
HarnessRouter
The self-hosted, Apache-2.0 edition of HarnessRouter: it puts sixteen existing agent CLIs — Codex, Claude Code, Hermes, DeepSeek Harness and twelve more — behind one OpenAI Responses-compatible API, with sessions, streaming, files, cancellation and structured failures, and it carries the Unified Harness Protocol it implements together with the conformance suite that measures it.
No. 070
OpenChatCut
A local-first video editor whose editing surface is a conversation: the built-in agent and external Codex or Claude Code sessions call the same editing tools the interface itself uses, so every change lands on a real multi-track timeline as a clip, transition, caption, effect or audio item that can still be dragged, undone and exported. Projects and media stay on the machine, and preview and final render both come out of Remotion.