Skip to main content

runseal

Prove which inputs produced a result — and that nothing changed since.

tests PyPI Python License: MIT

Content-addressed provenance for computational research. Four primitives, no required dependencies, no daemon, no server.

How runseal identifies and seals a run

pip install runseal            # hashing, merkle, registry
pip install runseal[signing]   # adds RSA-PSS artifact signing

Thirty seconds

from runseal import HashGenerator, ArtifactRegistry, Artifact

h = HashGenerator()
training_frame = {"rows": [1, 2, 3]}
config = {"window": 30, "seed": 7}

hashes = dict(
    source_hash=h.hash_data_snapshot(training_frame),
    code_hash=h.hash_code("src/"),
    config_hash=h.hash_config(config),
)

# A run is identified by what went into it, never by when you ran it.
run_id = h.compute_run_id(
    data_hash=hashes["source_hash"],
    config_hash=hashes["config_hash"],
    code_hash=hashes["code_hash"],
    env_hash=h.hash_environment(h.get_environment_manifest()),
)

registry = ArtifactRegistry("./provenance")
registry.register(Artifact(id=f"{run_id}/raw",   type="dataset", layer="ingest", **hashes))
registry.register(Artifact(id=f"{run_id}/model", type="model",   layer="train",
                           parent=f"{run_id}/raw", metrics={"auc": 0.71}, **hashes))

print(run_id[:32])
print(" -> ".join(a.id.split("/")[-1] for a in registry.get_lineage(f"{run_id}/model")))
print(registry.verify_integrity()["integrity_ok"])
45cd8972f036917e3a89ee3363c7119e
model -> raw
True

Re-run the same pipeline on the same inputs and run_id is byte-identical. Change one config value, one byte of data, or one line of code, and it is not.

What is in it

HashGenerator Content-addressed run IDs from data, config, code and environment. Deterministic across processes and machines.
MerkleTree Append-only log with root verification and per-leaf inclusion proofs.
ArtifactRegistry JSON-backed store with parent lineage, filtered queries and integrity checks.
SignatureManager RSA-PSS signing and verification of artifact records. Optional extra.

hash_config is order-insensitive, hash_data_snapshot handles dicts, sequences and numpy arrays by content, and hash_code walks a directory's .py files in sorted order.

What this is not

It is easy to pattern-match this to a pipeline tool. It is not one.

If you want Use
Data and model versioning with remote storage DVC
Experiment tracking with a UI and a server MLflow, Weights & Biases
Pipeline orchestration Airflow, Prefect, Dagster
A small library that answers "what produced this, and has it changed?" runseal

No service to run, no storage backend to configure, nothing to log into. It records and verifies; it does not schedule, execute, or store your data.

Why this exists

Extracted from a private research program where a wrong number that reconciles is more expensive than one that crashes. Writing the test suite surfaced two defects, both fixed here with regression tests named after them.

Merkle proofs verified only for leaf 0. get_proof returned bare sibling hashes with no record of which side each sibling sat on, while verify_proof always combined H(current + sibling). Parents are built as H(left + right), so any leaf that was a right child at any level failed to verify. On a four-leaf tree, three of four valid proofs were rejected. get_proof now returns (sibling_hash, side) pairs, verify_proof honours the side, and the odd-leaf self-pairing case is explicit. Covered for trees of 1–33 leaves.

Environment hashes were never stable. get_environment_manifest() embedded time.time(), so hashing the manifest gave a different digest on every call and compute_run_id produced a different RUN_ID for an identical environment — defeating the whole point of content addressing. The manifest is now deterministic, with wall-clock time left to Artifact.created_at where it belongs. Package enumeration also moved off the deprecated pkg_resources.

Scope and limits

Signing covers artifact identity and the provenance hashes — not mutable metrics or metadata, which are expected to be annotated after the fact. A test asserts that boundary so it stays explicit.

The Merkle implementation duplicates the final node on odd levels, the common convention, which carries the known second-preimage ambiguity between a tree of N leaves and certain smaller trees. That is fine for tamper-evidence inside one append-only registry and unsuitable as a general-purpose commitment scheme.

Tests

pip install -e ".[test]"
pytest -q

80 tests. The suite runs with or without cryptography — signing tests skip cleanly, and CI exercises both paths across Python 3.9–3.13.

Licence

MIT. See CHANGELOG.md and CONTRIBUTING.md.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

runseal-0.1.1.tar.gz (21.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

runseal-0.1.1-py3-none-any.whl (16.7 kB view details)

Uploaded Python 3

File details

Details for the file runseal-0.1.1.tar.gz.

File metadata

  • Download URL: runseal-0.1.1.tar.gz
  • Upload date:
  • Size: 21.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for runseal-0.1.1.tar.gz
Algorithm Hash digest
SHA256 c041b5d1036e19e879324db8a3a84101bb9ba325f9a3deb28469b1c69f7c6085
MD5 c976bff5a3df91a5fb418963065ee4ce
BLAKE2b-256 a792bd203532a07e021f7f765ffa9b4c596a33b72e1d2261cfaec6a4bb825434

See more details on using hashes here.

Provenance

The following attestation bundles were made for runseal-0.1.1.tar.gz:

Publisher: publish.yml on charlieyanhx/runseal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file runseal-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: runseal-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 16.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for runseal-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 212795de464ade7255c65db14ac045331cbbb2f00b98643f14e7cb6cd2dbf3d6
MD5 04dc0a4bc2b5d91bb4d40739f8964b60
BLAKE2b-256 2afd5d2f1d279e0ed6503f21c18f1cbcbe99c130306f43a43aadb38718ea95bf

See more details on using hashes here.

Provenance

The following attestation bundles were made for runseal-0.1.1-py3-none-any.whl:

Publisher: publish.yml on charlieyanhx/runseal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 files

0.1.0

2 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