Skip to main content
In the next ten minutes you’ll install Refactron, verify a real change against a real test suite, and read your first SAFE / UNSAFE / UNPROVEN verdict.

Install

Requires Node.js ≥ 18.
That puts two binaries on your 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):
For CI or a headless box, export a token instead of the browser flow:
An unauthenticated run exits 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 own git diff.
1

Capture a change as a diff

From a Python project with a test suite:
2

Verify it

Run verify-diff from inside the project you just captured the diff from:
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.
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.
What just happened:
  • 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 earn SAFE.
    • 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.
  • 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.
Add --json for the full reproducible report. See Verdicts for the complete model.
Coverage is Python-only (via coverage.py). A TypeScript or mixed-language diff can never reach SAFE today; it returns UNPROVEN (“coverage of the changed code could not be determined”). The gates still run; only the coverage half is Python-only.

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:
The agent proposes an edit (as full-file contents or a unified diff), calls 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:
The CLI is then 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.