parityrun
Prove that a rewrite of your app behaves exactly like the original. parityrun records what your app does (every page, form answer, redirect, database row and file it writes) and then checks a new version against that recording: a port from PHP to JavaScript, TypeScript or Rust, a framework upgrade, or simply the next release. With your own AI tool, it can do the port too, turn by turn, until the new version matches.
Install
pip install parityrun
That needs Python 3.10 or newer. Without Python, one line installs everything. On Windows (PowerShell):
powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/arttujan/parityrun/main/install.ps1 | iex"
On macOS and Linux:
curl -LsSf https://raw.githubusercontent.com/arttujan/parityrun/main/install.sh | sh
The installer gets uv, which installs parityrun as a command of its own, with its own
Python. Run it again to update (or pip install -U parityrun). Your app still needs whatever it needs to run (for a
PHP app: php).
Use it
In your app's folder:
parityrun
That's the one command to remember. The first time, it finds how to start your app and every route in its code, and records what the app does. Every time, it shows where you are and the next command to run:
my-app: 1 of 1 scenario recorded
3/14 routes visited
Next: parityrun capture
use the app in your browser: 11 routes not visited yet
parityrun capture opens the app in your browser: use it as people do, then press Finish. Every page shows how
many of the app's routes you have visited, and http://127.0.0.1:8000/__parityrun lists the ones still to go. Your
app's own files are never changed.
When you have a new version of the app (or let your AI tool make one, below), tell parityrun how to start it in
parityrun/impls.json:
"node": {"cwd": "../my-app-js", "cmd": ["node", "server.js"]}
(it gets its port in the PORT environment variable) and check it:
parityrun check --impl node # every difference, and the parity %; exits 0 only at 100 %
parityrun coverage # the routes and lines of code no scenario has run yet
Let your AI tool port it
parityrun port --to ts # TypeScript; or js (JavaScript), rs (Rust)
parityrun writes the new app's starting point beside yours (../my-app-ts), adds it to impls.json and gives your AI
tool the task in PORTING.md. Then it goes turn by turn: the tool works, parityrun checks, and the differences of one
scenario at a time become the next turn's task, until parity is 100 %. A scenario that stays red is reported, never
hidden. By default the tool is Claude Code (claude on PATH, your own account);
for another one, give its command: --agent "yourtool --message-file {prompt_file}". The tool may not change your app
or the recordings: parityrun puts its own folder back after every turn and stops if your app changes.
What "the same" means
Pages are compared as a browser reads them (indentation and attribute order don't count, text and links do), along
with status codes, redirects, database rows and written files; with the built-in stubs, also every prompt sent to an
LLM and every call to an outside service. Random ids, tokens and times are normalised. A check proves the new version identical on the recorded scenarios, which visit the routes and
(for PHP) run the share of the code that parityrun coverage shows; a path no scenario takes is not proven, so
capture until coverage is where you want it.
init recognises PHP (plain, Laravel, Symfony, WordPress), Node.js, Python (Django, Flask, FastAPI) and Rust apps,
and PHP libraries: code with no pages, whose scenarios call its functions and classes (fn:, new:) instead of
visiting pages, and whose port gets a ready-made shim to fill in.
Everything else (settings, scenario files, databases, LLM and outside-service stubs, examples) is in
the wiki, and on one page in
docs/reference.md.
Licence
MIT. Copyright (c) 2026 Arttu Jantunen.
Metadata
Release files for parityrun 0.6.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| parityrun-0.6.1.tar.gz | 118.9 kB | With provenance | Details for parityrun-0.6.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| parityrun-0.6.1-py3-none-any.whl | Python 3 | none | any | Details for parityrun-0.6.1-py3-none-any.whl |
Total release size: 208.0 kB
Release files / parityrun-0.6.1.tar.gz
| Download URL | parityrun-0.6.1.tar.gz |
|---|---|
| Size | 118.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
00561fd369a97d3138cad3d144f5e7736cd7e26e5f4c28f8524f0abf578e0672
|
|
BLAKE2b-256 checksum How to use checksums |
b155e36b95500d4e22d1490797bf6a7e165b5f8f556f39c4697057e505bcb81c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.
Transparency logRelease files / parityrun-0.6.1-py3-none-any.whl
| Download URL | parityrun-0.6.1-py3-none-any.whl |
|---|---|
| Size | 89.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
623c1cf0dc18658d2196999e22eb4ab27e95883334ef726528596ac6900d6a45
|
|
BLAKE2b-256 checksum How to use checksums |
3d71186afdc049102db28e2fd1ead7e185e2d02bd7854f911afab3b3a6b2ece3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.
Transparency logSecurity for parityrun 0.6.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for parityrun-0.6.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.