SAFE / UNSAFE / UNPROVEN verdict.
Install
Requires Node.js ≥ 18.PATH: refactron (the CLI) and refactron-mcp (the MCP server). To skip the install, run npx refactron <command> instead.
To earn a SAFE verdict end to end you also need a Python project with a passing pytest suite, plus coverage.py for the coverage measurement:
Prefer PyPI?
pip install refactron==0.3.0 installs a thin refactron shim that shells out to
the npm CLI. It is not a Node-free path: you still need Node.js ≥ 18 and npm install -g refactron. When the npm CLI is missing, the shim prints the exact matching install command
and exits non-zero. The shim provides the refactron command only; refactron-mcp comes from the
npm package.Authenticate
verify-diff is auth-gated. Log in once on this machine (this runs a device-code flow and opens your browser to approve a code):
7.
Verify a diff
Point Refactron at a repo and a unified diff. The diff can come from anywhere: an agent, a codemod, or your owngit diff.
1
Capture a change as a diff
From a Python project with a test suite:
2
Verify it
Run Refactron copies your project into an isolated shadow tree, applies the diff there,
runs the gates, and measures whether your tests exercise the changed lines. Your
real working tree is never modified.
verify-diff from inside the project you just captured the diff from:Coverage is Python-only, so only an all-Python diff can return
SAFE; a TypeScript or
mixed diff passes the gates and returns UNPROVEN. Form that expectation before the verdict
prints below.3
Read the verdict
One of three outcomes prints:
SAFE and UNPROVEN exit 0; UNSAFE exits 1, so it fails a CI job on its own.SAFE: the gates passed and your tests run the changed code (at least one changed line per file). Proven.UNPROVEN: the gates passed, but the change isn’t proven. Two causes, two responses:- A line is named in the output (
uncovered: calc.py:14): add a test that exercises it, then re-run to earnSAFE. - The reason is “coverage of the changed code could not be determined”: that’s the Python-only limit (a non-Python or mixed diff, or no
coverage.py). The gates still passed, but no added test changes the verdict today.
- A line is named in the output (
UNSAFE: a gate rejected the change. A tests-gate failure prints the failing-test tail; a syntax or imports failure prints that gate’s reason.
--json for the full reproducible report. See Verdicts for the complete model.
Give the gate to your agent (MCP)
The same engine is available as an MCP tool,verify_change, so an AI agent can verify a change before it lands it. Register the stdio server with your client. For Claude Code:
verify_change, and gets back the same SAFE / UNSAFE / UNPROVEN report, then decides whether to land it. Full setup, for every client, in the MCP tab.
Build from source (contributors)
Working on Refactron itself? Build the checkout instead of installing the published package:node dist/cli/index.js <command> and the MCP server is node dist/mcp/server.js. Every command on this page works the same way; substitute that invocation for refactron.
Next steps
Verify a diff
Every
verify-diff flag, exit code, and the JSON report shape.Safety model
The shadow tree, the three gates, and the atomic-write contract.