Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

covalence

Python bindings for Covalence.

Layout

The package is a mixed one: hand-written Python in python/covalence, and the compiled extension module staged beside it as covalence._covalence. The compiled module is private; ordinary Python modules such as covalence.lib.hash name the public surface. This keeps that surface independent of the Rust module and leaves room for composition modules: covalence.cas combines the checked logic objects and userspace providers, while a later covalence.nucleus can do the same for the full stack.

There is one extension module for the whole project, not one per Rust crate. crates/ffi/python is where Covalence crates are composed into a Python API; the crates being wrapped never depend on it.

What is exposed

covalence-lib-hash: the fixed-width namespaces and the operations on them. Each namespace is its own class deriving from Obj — O256, Blake3, Sha256, ContextKey, Sha1, GitHash — so isinstance(value, Obj) asks the general question while two namespaces with matching bytes still compare unequal.

>>> import covalence
>>> from covalence.lib.hash import O256, COV_ROOT, git_blob
>>> covalence.lib.hash is not None
True
>>> O256.hash(b"abc")
O256.from_hex('6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85')
>>> COV_ROOT.tag(b"sexpr").tag(b"list")     # derive a child name
O256.from_hex('...')
>>> str(git_blob(b""))
'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391'

Everything is a thin wrapper: hashing, encoding, and derivation are implemented once, in the crate being wrapped. Malformed input raises InvalidLengthError, InvalidHexError, or InvalidBase64Error — all ValueError — and anything that is not bytes-like raises TypeError.

covalence.data.cbor.Cbor exposes the immutable shared CBOR data model. Its constructors keep representation-sensitive values explicit: arrays and ordered map entries return tuples, simple values retain their numeric code, and floats retain their original width and raw bits. Python integers are converted to the shared arbitrary-precision Rust Int without narrowing. Equality works directly against Python integers, booleans, None, bytes, strings, lists, and insertion-ordered dictionaries; no conversion call is required. The Cbor(value) constructor (also available as Cbor.from_python(value)) recursively converts those scalar types, lists, and dictionaries.

covalence.data.sexpr exposes the reusable owned S-expression reader. It can stream open, atom, and close events or fold those events into immutable Document and SExpr objects. Symbols, strings, byte strings, exact number spellings, keywords, and directives remain distinct. The reader and both AST directions are iterative and impose no arbitrary nesting limit. Parsed trees retain u64 byte spans; erase() produces the distinct ErasedDocument and ErasedSExpr types, whose nodes carry no source-position fields. SExpr.format() and Document.format() choose flat or indented layouts from a requested width while retaining atom kinds and binary values.

>>> from covalence.data.cbor import Cbor
>>> value = Cbor.array([Cbor.integer(2**256), Cbor.text("large")])
>>> value.kind
'array'
>>> value.value[0].value == 2**256
True

covalence.cas exposes the whole-object CAS LCF boundary. CasAssertion is ordinary unchecked data; check() hashes the complete blob in Rust before it can return the opaque CasFact. Stores are userspace policy. IndexCas assigns stable integer IDs, while get_checked() checks bytes returned by any duck-typed Python CAS. A provider with get_fact() may avoid rehashing, but the fact's address is still compared with the request.

>>> from covalence.cas import CasAssertion
>>> from covalence.lib.hash import O256
>>> blob = b"provided by Python"
>>> address = O256.hash(blob)
>>> fact = CasAssertion(address, blob).check()
>>> fact.hash == address and fact.blob == blob
True

CasRangeFact narrows that to a byte range, introduced by CasFact.range, by slice and fuse on an existing one, or by checking a RangeProof while holding none of the rest of the blob. An end of None runs to the end of the blob, which is the stronger claim: such a fact also knows the blob's length.

Above those sits an equality calculus. A BlobExpr is syntax — a digest, literal bytes, a run of zeros, a concatenation, or a slice — and BlobEq is the claim that two of them denote the same byte string in every model of the CAS. BlobFact is the checked form, built only by the rules and by the bridges to and from CasRangeFact. Its observations are three-valued: decide(), len_bytes and eval() answer None where the rules do not settle a question, so an expression has len_bytes rather than len(). left + right is concatenation and blob[3:7] is a slice, on a fact as well as an expression.

>>> from covalence.cas import BlobEq, BlobExpr, BlobFact
>>> from covalence.lib.hash import O256
>>> joined = BlobExpr.bytes(b"ab") + BlobExpr.bytes(b"c")
>>> BlobEq(joined, BlobExpr.bytes(b"abc")).decide()
True
>>> BlobFact.check(BlobEq(joined, BlobExpr.bytes(b"abc")))[0:2].prop.rhs.eval()
b'ab'
>>> BlobExpr.blake3(O256.hash(b"unresolved")).len_bytes is None
True

covalence.logic.hol exposes the one-based Ethane arena in two layers. Arena is mutable wire data and may contain unchecked rows. Kernel starts empty and can only grow through checked row and syntactic-fact rules. Both layers retain the low-level integer-index API. A kernel can additionally return opaque Kind, Ty, and Tm handles, while SynFact snapshots prevent evidence from being reused after its slot is overwritten or across kernels.

>>> from covalence.logic.hol import Kernel
>>> kernel = Kernel()
>>> star = kernel.star()
>>> bool_ty = kernel.bool_ty(star)
>>> truth = kernel.bool(bool_ty, True)
>>> kernel.tm(truth).reference == truth
True

Strategy instantiates a portable WASM component implementing the nucleus:proof/proof world once and may be called repeatedly. Its one portable operation applies a numeric tactic with small byte arguments to an optional checked Kernel; omitting the kernel lets the strategy choose its checked starting point. apply_tactic_name encodes a UTF-8 name as tactic one, and prove_addr encodes an address as tactic zero. The component source may itself be bytes or an O256. Address-based loading requires a CAS, and the same optional CAS is wired into later component calls. load_proof is the one-shot convenience which builds a Strategy and requests its default on a fresh kernel. Components receive no inherited filesystem, network, environment, or command-line capabilities.

>>> from covalence.logic.hol import Strategy, load_proof
>>> with open("proof.wasm", "rb") as source:
...     strategy = Strategy(source.read())
>>> kernel = strategy.apply_tactic(0)
>>> len(kernel) >= 0
True

The checked-in dictionary-backed provider is runnable directly:

glu python crates/ffi/python/examples/dict_cas.py

It deliberately stores raw bytes in a plain Python dict and performs the check only when resolving. Files, HTTP, SQLite, generated data, or any other Python logic can use the same protocol without becoming part of the trusted constructor boundary.

Path Contents
src/ The #[pymodule] and its bindings
python/covalence/ The importable package, py.typed, and .pyi
examples/ checked-in runnable API demonstrations
tests/ pytest suite, run against the staged package

Building and running

glu build python   # stage the package into target/python
glu python         # a REPL that can import covalence
glu python -c 'import covalence; print(covalence.__version__)'
glu test           # among other things, runs the pytest suite

glu build python compiles the extension and stages the importable package into target/python, outside the source tree so that a build output never lands in a directory Buck globs as a source. glu python runs whichever python3 is on PATH with that directory on PYTHONPATH.

Cargo compiles this crate rather than Buck's Rust rules; //:python is the genrule that wraps it. rust_library produces an rlib, so no Rust rule here can emit something an interpreter loads, and pyo3's build script needs links metadata Buck's prelude discards.

Installing into an environment

glu stages the package rather than installing it, so nothing in CI needs a packaging tool. To get Covalence into an environment of your own, use maturin:

python3 -m venv --system-site-packages .venv
. .venv/bin/activate
maturin develop -m crates/ffi/python/Cargo.toml   # editable install
maturin build   -m crates/ffi/python/Cargo.toml   # wheel into target/wheels

--system-site-packages keeps the pinned interpreter's packages — pytest, and whatever the test suite grows to need — visible inside the virtual environment, which is then the place for anything nixpkgs does not carry. Because glu uses the python3 on PATH, an activated environment is picked up without further configuration.

Supported Python

3.11 and later, on the stable ABI. PyO3 is built with abi3-py311, so one extension module loads into every interpreter in that range and a wheel does not have to be rebuilt per version. Widening the range means relaxing that feature in covalence-lib-python, which is also where the PyO3 version and the extension-module policy are pinned and explained.

Installing a wheel from a particular commit

Alpha releases are the easiest way to try Covalence on a supported platform:

python3 -m venv .venv
. .venv/bin/activate
python -m pip install --pre covalence

Pin the selected alpha in a dependency file when reproducibility matters, for example covalence==0.1.0a1. PyPI selects the compatible wheel and installs any declared Python dependencies automatically. At present Covalence has no third-party Python runtime dependencies.

Maintainers publish an immutable prerelease by tagging a green main commit with a PEP 440 development or alpha version:

git tag -a covalence-v0.1.0.dev1 -m 'Covalence Python 0.1.0.dev1'
git push origin covalence-v0.1.0.dev1
# Once distribution plumbing is established, publish alphas in the same way:
git tag -a covalence-v0.1.0a1 -m 'Covalence Python 0.1.0a1'
git push origin covalence-v0.1.0a1

The Publish Python prerelease workflow validates the tag, builds and tests the wheel through the ordinary wheel workflow, and publishes that exact artifact with a PyPI provenance attestation. Publishing uses OIDC trusted publishing; there is no repository token. The PyPI publisher is scoped to project covalence, owner imbrem, repository nucleus, workflow publish-python.yml, and GitHub environment pypi. PyPI versions and Git tags are immutable: use a new development or alpha number rather than moving or rebuilding a tag.

Successful main and pull-request runs of the Python wheels workflow build an experimental snapshot for Linux x86-64. The wheel uses the CPython 3.11 stable ABI and the manylinux_2_28_x86_64 platform tag: the same file supports ordinary CPython 3.11 and later, but only on compatible Linux x86-64 systems. Other operating systems, architectures, and free-threaded Python builds are not currently produced.

Choose a commit, not merely the newest main run. In GitHub's web interface, open Actions, select Python wheels, and select a successful run whose commit is the one required. At the bottom of its summary, download covalence-linux-x86_64-<full-commit-SHA>, unzip it, then verify and install it:

cd path/to/unzipped-artifact
sha256sum --check SHA256SUMS
WHEEL=$(find . -maxdepth 1 -type f \
  -name 'covalence-*-cp311-abi3-manylinux_2_28_x86_64.whl' -print -quit)
test -n "$WHEEL"
python3 -m venv .venv
. .venv/bin/activate
python -m pip install "$WHEEL"
python -c 'import covalence; print(covalence.__version__)'

Downloading an Actions artifact in the web interface generally requires a GitHub login, including for a public repository. The GitHub CLI makes selection by immutable source commit explicit. Substitute the required full commit SHA:

REPO=imbrem/nucleus
FULL_SHA=0123456789abcdef0123456789abcdef01234567
RUN_ID=$(gh run list --repo "$REPO" --workflow python-wheels.yml \
  --commit "$FULL_SHA" --status success --limit 1 \
  --json databaseId --jq '.[0].databaseId')
test -n "$RUN_ID"
gh run download "$RUN_ID" --repo "$REPO" \
  --name "covalence-linux-x86_64-$FULL_SHA" --dir wheels
sha256sum --check wheels/SHA256SUMS
WHEEL=$(find wheels -maxdepth 1 -type f \
  -name 'covalence-*-cp311-abi3-manylinux_2_28_x86_64.whl' -print -quit)
test -n "$WHEEL"
python3 -m venv .venv
. .venv/bin/activate
python -m pip install "$WHEEL"
python -c 'import covalence; print(covalence.__version__)'

Record the full commit SHA and the matching entry in SHA256SUMS when using a snapshot as a dependency. BUILD-METADATA.json also records the source commit and Actions run. Artifacts expire after 30 days, so retain the verified wheel and checksum when reproducibility is needed for longer.

These snapshots are not releases, and Python API compatibility is not yet guaranteed. A production consumer should ultimately depend on an immutable package-index version or release asset with exact hashes rather than on a finite-lived Actions artifact.

Metadata

Release files for covalence 0.1.0.dev1

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

Built distribution (wheel)

Table of built distributions (wheels) for covalence 0.1.0.dev1
File Interpreter ABI Platform
covalence-0.1.0.dev1-cp311-abi3-manylinux_2_28_x86_64.whl CPython 3.11 abi3 Linux glibc 2.28+ x86-64 Details

Release files / covalence-0.1.0.dev1-cp311-abi3-manylinux_2_28_x86_64.whl

Download URL covalence-0.1.0.dev1-cp311-abi3-manylinux_2_28_x86_64.whl
Size 7.3 MB
Tags CPython 3.11 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
4eb170e8fa8f3c400bada051df07e3a55b2d43deda8d5266ffcbe6ad8d2dfeba
BLAKE2b-256 checksum
How to use checksums
4bd262d88084894cfa6fa6d3f1dcb59e11650439277bbbf66432dccc751f66e2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 2, 2026.

Transparency log

Security for covalence 0.1.0.dev1

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 1 file in this release has been uploaded with provenance metadata.

Attestation for covalence-0.1.0.dev1-cp311-abi3-manylinux_2_28_x86_64.whl

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 Sep 2, 2026.

Transparency log

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

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