Skip to content
SciProofv0.3.2

Record an experiment once. Let anyone check the evidence.

SciProof records a command, its inputs, outputs and environment in one JSON manifest, and later verifies it with an explicit verdict: PASSFAIL or INCONCLUSIVE. Local-first, offline, no runtime dependencies.

pipx install sciproof

Alpha software. The idea is unproven with real users; the docs say so openly.

See it work

The quick start from the README, replayed. Without JavaScript, or with reduced motion enabled, the whole session is shown at once.

Quick start, 5 steps

Capture

$ sciproof capture --name baseline \

--input examples/experiment.py --input examples/params.json \

--output examples/out/results.json \

--output-numeric examples/out/convergence.csv --rtol 1e-9 \

-- python examples/experiment.py

Evidence written to baseline.sciproof.json

command exit code: 0

inputs recorded: 2

outputs recorded: 2

Note: stdout/stderr are stored in the manifest; check them for secrets before sharing it.

Inspect

$ sciproof inspect baseline.sciproof.json

SciProof manifest: baseline

format: sciproof.manifest 1.0

captured: 2026-10-17T18:47:12+00:00

Command (recorded, NOT executed by 'inspect'):

python examples/experiment.py

...

Outputs (2):

examples/out/results.json sha256:723d792e1b1ad975... 69 bytes compare: exact hash

examples/out/convergence.csv sha256:131eb2551a942bb9... 89 bytes compare: numeric (rtol=1e-09, atol=0.0)

Verify integrity

$ sciproof verify baseline.sciproof.json

[PASS] input examples/experiment.py: unchanged (SHA-256 matches)

[PASS] input examples/params.json: unchanged (SHA-256 matches)

[PASS] output examples/out/results.json: unchanged (SHA-256 matches)

[PASS] output examples/out/convergence.csv: unchanged (SHA-256 matches)

note: scope: artifact integrity only. The recorded command was NOT executed, so this does not show that the results can be reproduced.

basis: PASS because all 4 performed checks succeeded; this covers only the checks listed above, not what is under 'not checked'

not checked: reproducibility: the recorded command was not executed

not checked: scientific validity: a matching result is not shown to be correct

not checked: files that were not declared as inputs or outputs

not checked: authenticity: manifests are unsigned, so who produced this evidence is not verified

RESULT: PASS

Verify by re-execution

$ sciproof verify baseline.sciproof.json --rerun --yes

...

[PASS] exit code: 0, same as recorded

[PASS] rerun output examples/out/results.json: identical to the recorded output (exact SHA-256)

[PASS] rerun output examples/out/convergence.csv: numerically equivalent (rtol=1e-09, atol=0.0)

RESULT: PASS

A modified output is detected:

$ sciproof verify baseline.sciproof.json

[FAIL] output examples/out/results.json: modified since capture (SHA-256 differs)

basis: FAIL because 1 (output examples/out/results.json) check(s) contradict the evidence; one failed check is enough

...

RESULT: FAIL

Source: the “Quick start” section of README.md. Outputs contain “...” where the README shortens them.

How it works

One command records the evidence. Two ways of checking it give three possible verdicts.

How SciProof worksInputs and a command go into capture, which writes an evidence manifest. Verify checks the integrity of the files; verify with rerun re-executes the command and compares the results. Both end in PASS, FAIL or INCONCLUSIVE.Inputs + commandfiles · argvcaptureruns it onceEvidence manifest (JSON)NAME.sciproof.jsonhashes · environment · logsverifyintegrity · runs nothingverify --rerunre-executes after confirmation, comparesPASSFAILINCONCLUSIVE
  1. capture runs your command once and writes a manifest next to your files.
  2. The manifest holds the command, SHA-256 hashes of declared inputs and outputs, the environment and the logs.
  3. verify checks that every file still matches. Nothing recorded is executed.
  4. verify --rerun runs the recorded command again, after confirmation, and compares the results exactly or within the tolerance you declared.
  5. The verdict is PASS, FAIL orINCONCLUSIVE (evidence missing or a check could not run; never treated as success).

What it proves, and what it does not

You have a script that produced a table or a figure. Months later, a reviewer, a collaborator or you yourself ask: which code and data made this, in which environment, and does it still come out the same? SciProof records the answer in a single JSON evidence manifest and can later verify it with an explicit verdict: PASS, FAIL or INCONCLUSIVE.

The four levels of “reproducible”, from the README.
LevelQuestionSciProof
IntegrityAre the files what was recorded?SHA-256 checks
Execution reproducibilityDoes the command still produce the recorded results?opt-in rerun; environment differences are reported, not fixed
Numerical equivalenceEqual within a declared tolerance?--output-numeric with rtol/atol for .json, .csv, .tsv and (with NumPy) .npy
Scientific validityIs the result correct?Not addressed. A reproducible result can still be wrong.

Bitwise reproducibility across different hardware or platforms is not promised. A PASS never means the science is right. More in Concepts.

Tolerances, made visible

Outputs declared with --output-numeric are compared with a relative (rtol) and an absolute (atol) tolerance that you choose at capture time. Try the rule SciProof uses. The defaults are the ones of sciproof capture: rtol=1e-9, atol=0.

|recorded − found|
rtol · max(|recorded|, |found|)
atol
allowed = max(relative, atol)
The rule, from src/sciproof/numeric.py
def _numbers_close(a: float, b: float, rtol: float, atol: float) -> bool:
    if math.isnan(a) or math.isnan(b):
        return math.isnan(a) and math.isnan(b)
    if math.isinf(a) or math.isinf(b):
        return a == b
    return abs(a - b) <= max(rtol * max(abs(a), abs(b)), atol)

SciProof cannot tell you which tolerance is scientifically appropriate. NaN only matches NaN and infinities must match exactly; integers and booleans are compared exactly. See thetutorial for choosing values.

Look inside a manifest

This manifest was produced while building this page by running sciproof capture --name baseline --input examples/experiment.py --input examples/params.json --output examples/out/results.json --output-numeric examples/out/convergence.csv --rtol 1e-9 -- python examples/experiment.py. Select any field to see what it means, as documented in Manifest format.

Select a field

Each line of the tree is a field of the JSON manifest.

Who it helps

Scenarios, not testimonials: SciProof is new and has no public users to quote yet.

PhD students

Before submitting, capture the script that produced a figure and keep the manifest with the thesis repository. Months later, sciproof verify tells you whether the data and outputs are still the ones you reported, and --rerun whether the figure still comes out of the same command.

Getting started →

Reviewers and artifact evaluators

Given a manifest, run sciproof inspect first: it shows the command, environment and hashes without executing anything. Re-run only if you trust the command, ideally in a disposable VM, and read the verdict, including what was not checked.

Threat model →

ML engineers

Declare model metrics as numeric outputs with an explicit rtol/atol, so a re-run on slightly different numerics is judged by a tolerance you wrote down, and an unrelated change shows up as a FAIL instead of a shrug.

NumPy & pandas tutorial →

CI pipelines

A job can run sciproof verify --json and fail on exit code 1 (FAIL) or 2 (INCONCLUSIVE). Integrity checks execute nothing; re-execution belongs only in trusted pipelines.

Using SciProof in CI →

How it relates to other tools

Recording a command with its hashes is not new. These notes keep the wording of the project's own comparison, including where an existing tool already does the job.

Related tools, from the README (links go to the tools' own documentation).
ToolRelation to SciProof
DVCPipelines with hashes of dependencies and outputs; heavier, more powerful. If you already use it you largely have integrity checking.
MLflow TrackingExperiment tracking for ML with parameters and metrics, optional UI.

The full analysis, including what could not be confirmed, is in thecomparison page. Its differentiation claim is described there as an unproven hypothesis.

Limitations and threat model

Warning: sciproof verify --rerun executes the command recorded in the manifest, with your permissions and without a sandbox. A manifest you did not create is as untrusted as a script from the same source.inspect and plain verify never execute it.
  • A manifest contains a command and must be treated as untrusted. inspect and plain verify never execute it; --rerun runs it with your permissions, unsandboxed. Only rerun manifests you trust, ideally in a disposable VM or container. See SECURITY.md.
  • Manifests can be signed with OpenSSH and checked against an explicit allowed-signers file; see docs/SIGNING.md. A signature shows that the holder of an allowed key vouched for those exact manifest bytes; it does not show that the experiment is correct, that it was run as described, when it was signed, or that the key and trust file were not compromised. Without a signature, hashes do not stop someone who can rewrite both the manifest and files from fabricating consistent evidence.
  • Only declared files are tracked. Undeclared inputs, network, time and system libraries are invisible. SciProof reports environment differences but does not recreate environments.
  • stdout/stderr and the command line are stored in the manifest; review them for secrets.
  • Numeric comparison supports .json, .csv and .tsv (standard library only) and .npy arrays (pip install 'sciproof[numpy]'; numeric, boolean and complex dtypes, never unpickled).
  • The environment is probed from the command's interpreter only if the command is a Python interpreter; otherwise the interpreter running SciProof is described (and the manifest says so).
  • Linux, Windows and macOS are tested in CI (Python 3.11-3.13).
  • The unit tests that check symlink escapes need symlink support (they run in Linux CI and are skipped where symlinks are unavailable).

Full threat model: Security & threat model (also available as SECURITY.md in the repository).

Community

SciProof is an open-source project. These numbers are read from GitHub; they were captured when the site was built and refresh in your browser if GitHub's API answers.

5stars
9forks
18open issues and PRs
v0.3.2latest release
0.3.2on PyPI

Updated .Your browser contacts api.github.com to refresh them; no cookies are set and nothing else is sent.

Contributors

Maintainers

How to contribute ·Issues ·Discussions