Skip to main content

Avow

Avow signs a JSON record into a receipt, a file anyone can check offline to confirm the record is unchanged and who signed it.

Try it: pip install "avow[cli]>=0.5.1", then run the four commands under Try it.

CI License PyPI

Teams often have to show later what they decided: that a release was approved, that its tests passed, that a setting was what they say it was. Usually that record sits in a database or a log that only they control, so an auditor or customer has to take their word that nobody edited it. A plain checksum doesn't help much, because anyone who can change the record can recompute the checksum too.

Avow gives the record a signature. You keep a private key and hand out the matching public key once, ahead of time. Avow turns your JSON record into a receipt: the record, its fingerprint, and a signature, in one small file. Anyone with your public key can check the receipt on their own machine, with no server and no internet. If one word of the record changed, the check refuses it. There's a Python library and command, and a TypeScript package that reads and writes the same receipts.

Technical docs: Architecture · Getting started for developers · Operations · Quickstart

Try it

You need Python 3.12 or newer.

  1. Install Avow with its command (the cli extra):
pip install "avow[cli]>=0.5.1"
  1. Make a key pair, write a record, sign it, and check it. Run these in an empty folder:
avow keygen --out signing.key
echo '{"release": "checkout-api 2.4.1", "approved_by": "dana", "tests_passed": true}' > decision.json
avow sign --payload decision.json --key signing.key --out receipt.json
avow verify --receipt receipt.json --public-key signing.key.pub

It prints:

avow.keygen.ok
avow.sign.ok
avow.verify.ok

signing.key is your private key. Keep it to yourself. signing.key.pub is the public key you give to whoever will check your receipts. receipt.json is the receipt. It holds the record in plain text, plus the fingerprint, the signer's public key, and the signature:

{
    "payload": {"approved_by": "dana", "release": "checkout-api 2.4.1", "tests_passed": true},
    "payload_hash": "sha256:64a2594744910b829fe6f712750b05f87e08313a5f98af6ce2d170116d2a3fc5",
    "public_key": "47c7e14708f5e1acf35e998cc289997a19299ffef8fa86953fe99278c4ec6dd5",
    "schema": "avow.receipt/v1",
    "signature": "20e8b0a7310cbc640046ace3fedda22592fdb525d7bbf254036d61a184f6c9d7e6224187def7618791b9d5b0f39659ec8e8fe87e807307626b561d21150b4200"
}

Your keys and signature will differ; the fingerprint will match, because it depends only on the record.

  1. Now change who approved it, and check again:
sed 's/dana/mallory/' receipt.json > tampered.json
avow verify --receipt tampered.json --public-key signing.key.pub
echo "exit code: $?"

It prints:

avow.payload_hash_mismatch
exit code: 2

The record no longer matches the fingerprint that was signed, so Avow refuses it. Every refusal is a short, stable code like this one, so scripts can act on it. Checking a receipt against someone else's public key fails the same way, with avow.signer_mismatch.

From Python

The same thing from Python. This needs only pip install avow, not the cli extra:

from avow import generate_signing_key, public_key_hex, sign_payload, verify_receipt
from avow.errors import AvowError

private_key = generate_signing_key()      # stays with whoever signs
public_key = public_key_hex(private_key)  # handed to whoever checks, ahead of time
receipt = sign_payload({"service": "checkout-api", "decision": "approved"}, private_key)
verify_receipt(receipt, expected_public_key=public_key)
print("original:", receipt.payload, "-> verified")

altered = receipt.model_copy(update={"payload": {"service": "checkout-api", "decision": "rejected"}})
try:
    verify_receipt(altered, expected_public_key=public_key)
except AvowError as error:
    print("altered: ", altered.payload, "-> refused:", error.code)

Its real output:

original: {'service': 'checkout-api', 'decision': 'approved'} -> verified
altered:  {'service': 'checkout-api', 'decision': 'rejected'} -> refused: avow.payload_hash_mismatch

How it works

Avow first writes your JSON in one fixed form (sorted keys, no extra spaces, numbers spelled one way), so the same data always gives the same bytes. It takes a SHA-256 fingerprint of those bytes and signs them with your Ed25519 private key. To check a receipt, Avow recomputes the fingerprint, confirms the signer is the public key you supplied (it never trusts the key written inside the receipt), and checks the signature. All of this is local math on local files; Avow's code opens no network connection. If you need a history, the ledger (avow ledger append and avow ledger verify) chains receipts so a deleted, inserted, or reordered entry is caught. The details are in Architecture.

What it does not do

  • It does not prove the record is true. A receipt proves the record is unchanged and who signed it. It says nothing about whether the record is correct, complete, or current, and it carries no trusted timestamp.
  • It does not hide anything. A receipt is not encrypted. The record sits in it as plain text, so keep secrets out.
  • It does not stop replay. A valid receipt checks out every time someone shows it. If that matters, put a nonce, audience, or expiry inside your record and check them yourself; see replay protection.
  • It does not guard your key for you. The private key is an unencrypted file, protected only by file permissions. Avow refuses to sign with a key file other users can read, but there is no KMS or HSM support yet. Anyone who copies the file can sign as you. See key rotation.

When to use something else

If you need Use
To catch accidental corruption only A plain checksum such as sha256sum
To sign files for people who already use those tools GPG, minisign, or ssh-keygen -Y sign
Public, time-stamped signing of software releases Sigstore or a transparency log
Login or API tokens A JWT / JWS library
Signed JSON records that anyone can check offline, from Python or TypeScript, with no account or service Avow

A longer comparison is in Architecture.

Install

Python 3.12 or newer. This gives you the library and the avow command:

pip install "avow[cli]>=0.5.1"

If you only want the Python library and not the command, pip install avow is enough.

TypeScript, on Node.js 22.13 or newer:

npm install @gainratio/avow

0.5.0 is out on PyPI and npm, and it is the first release built from this repository. 0.5.1 makes the command optional: pip install avow is the library alone, and pip install "avow[cli]" adds the avow command. 0.5.2 only renames the npm package from @edgeproc/avow to @gainratio/avow; the Python package is unchanged apart from the version number. 0.5.3 fixes a break from 0.5.0: receipts sealed by 0.4.x and older, which have no schema field, verify again in Python and TypeScript. Python releases 0.1.0 through 0.4.1 came from an older repository and also installed stray assay/ and writ/ packages that overwrote another project's files. Those releases are yanked on PyPI, so pip skips them unless you pin one exactly; do not install them. If one of them broke assay-engine, run pip uninstall assay-engine && pip install assay-engine. See the CHANGELOG.

Develop

You need Python 3.12 or newer and uv; Node 22 and pnpm only for the TypeScript package.

git clone https://github.com/hseshadr/avow.git && cd avow
uv sync --frozen --all-groups

Then run the demo:

bash examples/run_evidence_loop.sh

It signs a sample deployment decision, checks it, and shows a changed copy being refused. To run the same checks as CI:

uv run poe gate && pnpm --dir ts gate

Getting started for developers walks through setup, the local traps we hit, a map of the code, a first change, and how to open a pull request.

More detail

License

MIT. See LICENSE.

Metadata

Release files for avow 0.5.3

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

Source distribution (sdist)

Source distribution for avow 0.5.3
File Size Uploaded
avow-0.5.3.tar.gz 23.7 kB Details

Built distribution (wheel)

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

Total release size: 51.8 kB

Release files / avow-0.5.3.tar.gz

Download URL avow-0.5.3.tar.gz
Size 23.7 kB
Tags Source
SHA-256 checksum
How to use checksums
e89250b114db09a6f2892f2e2af127ce11e90ae2836c1550866699199079e3c2
BLAKE2b-256 checksum
How to use checksums
4bdbab69193ed61fee1204f978eab58a11d210a9fce90f1bf40e9c391e48ba16
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 Oct 3, 2026.

Transparency log

Release files / avow-0.5.3-py3-none-any.whl

Download URL avow-0.5.3-py3-none-any.whl
Size 28.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
87cd606d5c7acf70275527347ece0cc5141575b715bdcc233960a0430c066f8d
BLAKE2b-256 checksum
How to use checksums
00ebdb79a4f709446dd79d174d5ade034d09725fce9a0becd9872cc666dfe577
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 Oct 3, 2026.

Transparency log
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