Repository navigation
Add the Kani agent plugin: verify-rust skill, helper scripts, and kani-mcp - #5059
Draft
feliperodri wants to merge 5 commits into
Draft
feliperodri wants to merge 5 commits into
feliperodri wants to merge 5 commits into
Conversation
- agent-plugin/: plugin manifest, MCP registration, compatibility.json (plugin 0.1.0 supports Kani >= 0.68.0, < 1.0.0), the verify-rust skill, and references for Kani, AutoHarness, contracts, Miri, rust-analyzer, and vacuity. - Scripts: summarize-results.py (compact --export-json summary), check-vacuity.py, check-assumptions.py, inspect-harness.py, and check-kani-version.py. - tools/kani-mcp: a minimal stdio-only MCP server with kani_get_version, kani_list_harnesses, kani_verify_harness, and kani_get_counterexample. It shells out to the installed Kani. MCP is optional; the skill falls back to the CLI. - Tests: Kani-free unit tests and a metadata validator (new Agent Plugin workflow), plus an `agent-plugin exec` suite in kani-regression.sh that runs the workflow end to end against a fixture crate, with and without MCP.
feliperodri
force-pushed
the
agent-plugin-v1
branch
from
October 23, 2026 20:40
535f05d to
4a70012
Compare
Contributor
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
No open issues 🎉
What changed in this PR
Adds a Kani agent plugin plus a minimal MCP server (kani-mcp) to make Kani verification workflows accessible to coding agents, with helper scripts and CI/smoke tests to validate behavior and compatibility.
Changes:
- Introduces
kani-mcp(stdio JSON-RPC/MCP server) with tools for version, harness listing, verification summaries, and counterexamples. - Adds Python helper scripts and tests for summarizing
--export-json, vacuity/assumption checks, and plugin metadata validation. - Adds CI workflow + regression suite hooks and end-to-end smoke tests for CLI fallback and MCP tool parity.
| File | Description |
|---|---|
| tools/kani-mcp/src/summary.rs | Rust implementation of compact RFC0015 export summary (mirrors Python script) + unit test fixture coverage |
| tools/kani-mcp/src/main.rs | MCP stdio server implementing kani_get_version, kani_list_harnesses, kani_verify_harness, kani_get_counterexample |
| tools/kani-mcp/Cargo.toml | New kani-mcp crate definition and dependencies |
| Cargo.toml | Adds tools/kani-mcp to workspace members |
| tests/agent-plugin/version-check/test.sh | Smoke test for version enforcement and error clarity |
| tests/agent-plugin/version-check/config.yml | Registers version-check smoke test |
| tests/agent-plugin/mcp/test.sh | End-to-end MCP tool exercise + parity check vs CLI summary |
| tests/agent-plugin/mcp/config.yml | Registers MCP smoke test |
| tests/agent-plugin/cli-fallback/test.sh | End-to-end skill workflow through CLI-only (export, summary, vacuity/assumptions, playback, autoharness) |
| tests/agent-plugin/cli-fallback/config.yml | Registers CLI-fallback smoke test |
| scripts/kani-regression.sh | Adds agent-plugin exec suite to regression |
| .github/workflows/agent-plugin.yml | New path-filtered workflow to validate plugin + run unit tests |
| agent-plugin/plugin.json | Plugin manifest (name/version/paths/metadata) |
| agent-plugin/mcp.json | Registers local stdio MCP server command (kani-mcp) |
| agent-plugin/compatibility.json | Supported Kani range + required unstable features |
| agent-plugin/README.md | Plugin documentation, installation, tools/scripts overview |
| agent-plugin/tests/validate_plugin.py | Validation for manifests, versions, skill frontmatter, and reference/script presence |
| agent-plugin/tests/test_scripts.py | Unit tests for Python scripts using JSON fixtures + Rust source fixtures |
| agent-plugin/tests/smoke-lib.sh | Shared harness for smoke tests (temp fixture crate, build kani-mcp, helpers) |
| agent-plugin/tests/mcp_client.py | Minimal MCP stdio client used by smoke tests |
| agent-plugin/tests/fixtures/rust/assumptions.rs | Rust text fixture for assumption scanner tests |
| agent-plugin/tests/fixtures/crate/Cargo.toml | Fixture crate used by end-to-end smoke tests |
| agent-plugin/tests/fixtures/crate/src/lib.rs | Fixture crate code + proof harnesses (good/failing/vacuous) |
| agent-plugin/scripts/kani_plugin_lib.py | Shared text-scanning utilities for plugin scripts |
| agent-plugin/scripts/summarize-results.py | Python compact summary implementation of RFC0015 export |
| agent-plugin/scripts/check-vacuity.py | Python vacuity checker over RFC0015 export |
| agent-plugin/scripts/check-assumptions.py | Python assumption checker over Rust source text |
| agent-plugin/scripts/check-kani-version.py | Python Kani version-range validator |
| agent-plugin/scripts/inspect-harness.py | Python harness structure inspector |
| agent-plugin/skills/verify-rust/SKILL.md | Skill orchestration workflow/policy for agents |
| agent-plugin/skills/verify-rust/references/kani.md | Reference guidance for harness writing/running Kani |
| agent-plugin/skills/verify-rust/references/vacuity.md | Reference guidance for vacuity/sanity checks |
| agent-plugin/skills/verify-rust/references/contracts.md | Reference guidance for contracts |
| agent-plugin/skills/verify-rust/references/autoharness.md | Reference guidance for autoharness usage |
| agent-plugin/skills/verify-rust/references/miri.md | Reference guidance for Miri complementing Kani |
| agent-plugin/skills/verify-rust/references/rust-analyzer.md | Reference guidance for using rust-analyzer in verification workflows |
Review effort: Lite
Copilot stopped reviewing on behalf of
feliperodri due to an error
October 23, 2026 21:17
Make it hard for an agent to get a green result by weakening the proof: - summarize-results.py and kani_verify_harness report `weakened_checks` (disabled checks, raw CBMC arguments) and, per harness, the stubs and stub_verified contracts the result relies on. - check-specs.py checks specifications with Kani itself, in a temporary copy of the crate: harness end reachable, preconditions satisfiable, clauses that constrain nothing, and whether a changed precondition is stronger or weaker than a baseline. Checks that cannot run are reported as unchecked, never as passing. - check-proof-diff.py compares harnesses, contracts, and code with a pinned baseline and flags removed assertions or covers, new assumptions, stubs, should_panic, lower unwind bounds, changed contracts, and any change to the code under verification. - check-witness.py confirms a defect (its concrete playback witness fails) or a fix (the witness fails before and passes after). - evidence.py records the run behind a reported result and re-checks it. - The verify-rust skill pins the agreed property, forbids silent code changes, requires evidence for every claim, and gains a strategy reference (one harness for small targets, contracts bottom-up along the call graph from rust-analyzer's call hierarchy for larger ones). - kani_list_harnesses accepts extra_args, so crates with contracts can be listed with -Z function-contracts. - New proof-integrity smoke test; more unit tests.
Parsing and proof diff:
- Walk back over attributes by matching brackets, so multi-line
attributes such as `kani::ensures(|r| { ... })` are seen.
- Count assumptions, inputs, and assertions in the Kani-only helpers a
harness calls (and its stub replacements); list a new harness's
assumptions; treat files included through `#[cfg(kani)] mod x;` as
Kani-only; normalize multi-line attribute arguments.
- Loose files are no longer attributed to an enclosing package.
Checks:
- check-vacuity.py: without descriptions, unreachable assertion-class
checks are warnings (they may be built-in checks the solver folded
away); `--log` classifies them from Kani's console output.
- check-specs.py: check contracts on methods and associated functions
through generated predicates in an inherent impl; accept
`--kani-arg -Z`; keep the crate copy in target/ so dependencies are
built once; report `harness-fails` for failing harnesses.
- check-witness.py: `--cargo-arg` pass-through, retry with `--lib` when
test targets do not build under cfg(kani), and report witnesses of
stubbed harnesses that pass on the real code as spurious.
- evidence.py: hash every package source and the workspace manifests,
resolve workspace-relative export paths, record a hash of `git diff`
and of untracked files.
- check-kani-version.py and kani_get_version verify a trivial harness,
so a missing CBMC or goto-cc is reported up front.
- inspect-harness.py: `--summary`, `--flagged-only`, and `--list-json`
to report harnesses the scan cannot see (macro-generated).
kani-mcp:
- `timeout_s` (default 1800 s; kills Kani's process group),
`harness_timeout_s`, `jobs`, `export_path`, `log_path`, and MCP
progress notifications; return the command line for evidence.
- kani_get_counterexample separates failure and cover witnesses, names
omitted ones, and warns that playback ignores stubs.
- kani_list_harnesses returns a summary by default, with `filter`.
Docs: re-snapshot the baseline once a harness is approved, bound every
run, --jobs requires terse output, playback ignores stubs, rustup
auto-installs pinned toolchains, and drop glue/recursion performance.
Tests: smoke tests must end with smoke_pass, so a script that stops
early fails; new unit and smoke tests for every fix.
Toolchain: - The scripts and kani-mcp run Kani with RUSTUP_TOOLCHAIN pinned to an installed toolchain (Kani's own, else rustup's default) and RUSTUP_AUTO_INSTALL=0. rustup's cargo proxy otherwise installs the toolchain a project pins in rust-toolchain.toml before Kani starts. kani_get_version and check-kani-version.py print the `cli_env` to use for direct CLI runs. Checks: - check-vacuity.py: parse property names with spaces; classify by location: assertions in the harness are errors, in callees or contracts warnings, in Kani or std library code info. - check-witness.py: a defect is reproduced only when the replay panics with the reported failure (`different-failure` otherwise); leftover concrete values mean spurious; when the crate's tests do not build under cfg(kani), replay in a copy without them; keep the doc comment of the witness. - check-proof-diff.py: flag a harness that loses #[kani::proof]; resolve helpers by path (never into kani/std, never method calls); treat any_where predicates as assumptions; describe an added ensures as added; cfg(kani) impl blocks are Kani-only. - check-specs.py and check-witness.py: mirror external path dependencies in their work copies. - evidence.py: hash untracked files correctly; warn when sources changed after the Kani run started. - inspect-harness.py: recognize any_array and Type::any() generators; flag harnesses with branches and fewer than two covers. kani-mcp: - On timeout, return the harnesses that finished, read from Kani's output. - Counterexample note handles TIMEOUT/OUT_OF_MEMORY verdicts. - kani_list_harnesses drops --target-dir, which `kani list` rejects, and checks contracts without harnesses against proof_for_contract targets in the source. Docs: toolchain pinning for CLI runs, covers in every harness branch, witness verdicts, inplace playback in workspace members.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds the Kani agent plugin. The goal is to make Kani easy to try and adopt from the coding agents Rust developers already use (Kiro, Claude Code, Copilot/VS Code, Cursor, Codex). An agent can verify a property, write or improve a proof harness, run Kani, explain a counterexample, and check that a passing proof is not vacuous, without the user first learning every Kani command.
What's included
agent-plugin/skills/verify-rust/: the orchestration skill. Steps: pin down the property, check Kani is installed, write the harness, run Kani with--export-json, get a counterexample via concrete playback, check vacuity and assumptions, and report exactly what was proven, with its bounds and stubs. Detailed guidance lives inreferences/(Kani, AutoHarness, contracts, Miri, rust-analyzer, vacuity).agent-plugin/scripts/(Python 3 only, JSON output):summarize-results.py: a compact summary of an RFC 0015 export.check-vacuity.py: unreachable assertions and unsatisfiable covers.check-assumptions.py: contradictory, pinned, or success-assumingkani::assume, andrequires(false).inspect-harness.py: harness structure.check-kani-version.py: checks the installed Kani against the plugin's supported range.summarize-results.py(andkani_verify_harness) reportweakened_checks(disabled checks, raw CBMC arguments) and, per harness, the stubs andstub_verifiedcontracts the result relies on.check-specs.pychecks specs with Kani itself, in a temporary copy of the crate: is the end of each harness reachable, are contract preconditions satisfiable, does a clause constrain nothing, and is a changed precondition stronger or weaker than the baseline's. A check that cannot run is reported asunchecked, never as passing.check-proof-diff.pycompares harnesses, contracts, and code with the baseline the user approved. It flags removed assertions or covers, new assumptions, stubs,should_panic, lower unwind bounds, changed contracts, and any change to the code under verification.check-witness.pyconfirms a defect (its concrete playback witness fails) or a fix (the witness fails before the fix and passes after).evidence.pyrecords the run behind a reported result, and re-checks it later.strategy.mdreference covers when to write one harness and when to prove contracts bottom-up along the call graph, which comes from rust-analyzer's call hierarchy.tools/kani-mcp: a minimal MCP server, stdio only, with no new dependencies. It has four tools:kani_get_version,kani_list_harnesses,kani_verify_harness, andkani_get_counterexample. It shells out to the user's installed Kani. MCP is optional: the skill falls back to the CLI, which covers every feature, including AutoHarness.compatibility.jsonsays plugin 0.1.0 supports Kani >= 0.68.0, < 1.0.0; 0.68.0 is the first release with--export-json. Both the script and the MCP tool enforce this range.Testing
agent-plugin/tests/validate_plugin.pychecks manifests, skill frontmatter, and links.agent-plugin/tests/test_scripts.pyhas 48 unit tests over the existing RFC 0015 fixtures and Rust samples, and needs no Kani.cargo test -p kani-mcpruns 16 unit tests.Agent Pluginworkflow.agent-plugin execsuite inkani-regression.shruns end to end against a fixture crate with one good proof, one real overflow, and one vacuous proof. It checks:kani_verify_harnessmatchessummarize-results.py;kani-mcpover stdio by hand on sample files. The suite passes locally through compiletest on macOS.Field testing
A trial run on two real crates found one real defect in each, and a list of false results and usability problems in the scripts and MCP server. All of them are fixed in this PR:
cfg(kani), and failures caused only by stubs are reported as spurious;A second round on three crates confirmed most of those fixes and found more, now also fixed:
RUSTUP_TOOLCHAINto an installed toolchain and disables auto-install);#[kani::proof]and resolves helpers by path;Not done yet
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.