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.0.tar.gz (21.0 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.0-py3-none-any.whl (16.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: runseal-0.1.0.tar.gz
  • Upload date:
  • Size: 21.0 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.0.tar.gz
Algorithm Hash digest
SHA256 f2396aa857fb4d471e95411501152d6babfc1a2568870c1c896e517d739b5ecf
MD5 a25e323492eaec564bcf9935fa940d23
BLAKE2b-256 104f8f601ca8eb5beeb820b1c59e3950eeafc48f265b31ff0b5e672dd858ecb9

See more details on using hashes here.

Provenance

The following attestation bundles were made for runseal-0.1.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: runseal-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 16.5 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 51d2183d22427cabcfec81fbd44142833a8cc9bffeaccb39ad9e6044280dc442
MD5 02230fbbbc87c56a8a5c3c2b4ce7b335
BLAKE2b-256 8efe17eec7f555a4ff97b7c30f138558fca6c7118be0eb777dc0d8833f0346d8

See more details on using hashes here.

Provenance

The following attestation bundles were made for runseal-0.1.0-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

0.1.1

2 files

This release

0.1.0 This release

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