Skip to main content

SciProof

CI License: MIT

Record a computational experiment once, then let anyone check the evidence: are the files unchanged, and does re-running the command give the recorded results, exactly or within a tolerance you declared?

Status: alpha (0.1). Small, local-first, offline, no runtime dependencies. The idea is unproven with real users; see the competitive analysis for how it overlaps with existing tools (DVC, ReproZip, Sumatra, MLflow, RO-Crate).

The problem

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.

What it does and does not prove

Level Question SciProof
Integrity Are the files what was recorded? SHA-256 checks
Execution reproducibility Does the command still produce the recorded results? opt-in rerun; environment differences are reported, not fixed
Numerical equivalence Equal within a declared tolerance? --output-numeric with rtol/atol for .json, .csv and (with NumPy) .npy
Scientific validity Is the result correct? Not addressed. A reproducible result can still be wrong.

Bitwise reproducibility across different hardware or platforms is not promised. Details in docs/CONCEPTS.md.

Install

pipx install sciproof               # or: python -m pip install sciproof   (Python 3.11+)
sciproof --version

From source (for development):

git clone https://github.com/hayagrivai-labs/sciproof.git && cd sciproof
python -m pip install -e ".[dev]"

Quick start

The repository contains a small deterministic experiment (a seeded Monte Carlo estimate of pi). Run everything below from the repository root, or run python examples/demo.py to see the whole story in a temporary directory.

1. Capture the experiment. Declare the files that matter; everything after -- is the command (it is not run through a shell):

$ 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.

2. Inspect the evidence. This never runs the recorded command:

$ 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)

3. Verify integrity (nothing is executed):

$ 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.

RESULT: PASS

4. Verify by re-execution. Running the command is a deliberate act: it needs --rerun and either an interactive confirmation or --yes.

$ 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

5. A modified output is detected:

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

Exit codes: 0 PASS, 1 FAIL, 2 INCONCLUSIVE, 3 usage error or invalid manifest. A missing input, a missing numeric snapshot, a command that cannot be started, a timeout or a declined rerun are INCONCLUSIVE, never PASS.

A walkthrough with NumPy and pandas, including how to choose tolerances: docs/TUTORIAL_NUMPY_PANDAS.md.

Commands

sciproof capture --name NAME [--input P]... [--output P]... [--output-numeric P]...
                 [--rtol X] [--atol Y] [--timeout S] [--max-log-bytes N]
                 [--force] [--allow-nonzero] -- COMMAND [ARGS...]
sciproof verify  MANIFEST [--rerun] [--yes] [--strict-env] [--timeout S] [--json]
sciproof inspect MANIFEST
  • Paths must be inside the current directory; the manifest is written there as NAME.sciproof.json. Numeric outputs are also copied to NAME.sciproof.d/ (needed to compare with a tolerance; keep it next to the manifest).
  • Declared inputs must be read-only for the command; capture fails if the command changes one.
  • A command that exits with a nonzero status is still recorded (capture then exits with 1 unless --allow-nonzero).
  • --json prints the verification report as a single JSON object (same exit codes), for CI and scripts. Prompts and errors go to stderr, so stdout stays valid JSON.
  • --strict-env makes a rerun INCONCLUSIVE (without executing) if Python version, platform or recorded package versions differ.

Manifest format: docs/MANIFEST.md.

Threat model and limitations

  • 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 are not signed (a tested recipe using ssh-keygen -Y is in docs/DESIGN_SIGNING.md): hashes detect changes, they do not stop someone who can rewrite both 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 and .csv (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).
Tool Relation
DVC Pipelines with hashes of dependencies and outputs; heavier, more powerful. If you already use it you largely have integrity checking.
ReproZip Packs a Linux experiment with its files and dependencies so it can be rerun elsewhere. SciProof does not package anything.
Sumatra Electronic-lab-notebook style run records.
MLflow Tracking Experiment tracking for ML with parameters and metrics, optional UI.
RO-Crate A standard to describe research outputs; does not verify them. Mapping study: docs/DESIGN_RO_CRATE.md.

Full analysis, with what could not be confirmed: docs/COMPETITIVE_ANALYSIS.md.

Roadmap (decided by feedback, not by speculation)

Nothing below is promised. Each item is only worth doing if real users ask for it:

  1. Try it on real experiments of a few researchers; record what is awkward or missing.
  2. Based on that: more numeric formats (for example .npz), directory outputs, or a manifest export to RO-Crate for interoperability.
  3. Signing or timestamping of manifests, if integrity against a hostile party matters to users.

Contributing

See CONTRIBUTING.md. Quick checks: ruff check ., ruff format --check ., python -m pytest, python examples/demo.py.

Licence

MIT: short and permissive, so researchers and companies can use and embed it without legal review.

Metadata

Release files for sciproof 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sciproof 0.1.1
File Size Uploaded
sciproof-0.1.1.tar.gz 46.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sciproof 0.1.1
File Interpreter ABI Platform
sciproof-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 80.5 kB

Release files / sciproof-0.1.1.tar.gz

Download URL sciproof-0.1.1.tar.gz
Size 46.2 kB
Tags Source
SHA-256 checksum
How to use checksums
a4ad1af31c7d352904aa964e4b14d64c64ddaf8a70642df7bd74222e3f174a70
BLAKE2b-256 checksum
How to use checksums
b87f3cc5e4fbfc51df51076a799f10bbfa964ec5163c4da935aee5737cfea3d8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.1

Release files / sciproof-0.1.1-py3-none-any.whl

Download URL sciproof-0.1.1-py3-none-any.whl
Size 34.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
36e731ae8859c37c1a4430d5904663faee738ca8e6ae4468042722d052cb9cd3
BLAKE2b-256 checksum
How to use checksums
f292adebe39f68df8252acdfc70e594f0d2178306633b56a5d4f45c744ba2cf7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.1

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page