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.
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.
- Install Avow with its command (the
cliextra):
pip install "avow[cli]>=0.5.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.
- 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.
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
- Architecture: how receipts are built and checked, the package layout, the security model, and what a receipt does and does not prove.
- Explore the interactive architecture map, generated from
runtime.architecture.json. - Getting started for developers: from a fresh clone to your first pull request.
- Operations: distributing public keys, ledger recovery, error codes, replay protection, and key rotation.
- Quickstart: every CLI command, the JSON values Avow accepts, and how to test the built wheel.
- TypeScript package: using
@gainratio/avow. - CHANGELOG: what changed in each release.
- SECURITY.md: how to report a vulnerability privately.
- PROVENANCE.md: where this repository's history came from.
- Questions and bugs: GitHub Issues.
License
MIT. See LICENSE.
Metadata
Release files for avow 0.5.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| avow-0.5.2.tar.gz | 23.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| avow-0.5.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 50.5 kB
Release files / avow-0.5.2.tar.gz
| Download URL | avow-0.5.2.tar.gz |
|---|---|
| Size | 23.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
561c9404b218948ac4229a1683ad21c21e2809211fdfaf956d9cb315c7d94aa0
|
|
BLAKE2b-256 checksum How to use checksums |
d3c586bee1bcf2aec4e5e3587eec02bfcf34b943ac12b863a6401184e11be56c
|
| 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 2, 2026.
Transparency logRelease files / avow-0.5.2-py3-none-any.whl
| Download URL | avow-0.5.2-py3-none-any.whl |
|---|---|
| Size | 27.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ffbc8d733fbd851b2652f63d2599f8b636b35617d49cf5d66a8cc7eb308cee84
|
|
BLAKE2b-256 checksum How to use checksums |
f8b653db122c111b8e3db57cd315c6fa5db8635210360b26684f6c06ccfc0c69
|
| 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 2, 2026.
Transparency log