ProvBind
Bind AI and research artifacts to the exact source bytes that produced them.
ProvBind is a small, local-first provenance verifier for AI agents, research pipelines, coding agents, and automated reports. It creates a closed JSON manifest that binds an artifact to one or more source files using SHA-256 digests and an independently recomputable binding_id.
The goal is deliberately narrow: if an agent says “this output was based on these sources,” ProvBind makes that claim concrete and machine-verifiable.
ProvBind proves byte identity and binding. It does not prove that a source is true, that an agent reasoned correctly, that a person authored a file, or that a timestamp is externally trusted.
Why
Agent workflows increasingly read files, Git repositories, documents, and research inputs before producing code or reports. A normal output file does not preserve enough evidence to answer basic questions later:
- Was this the exact source file the agent used?
- Did a GitHub source come from a fixed commit, or from a branch that later moved?
- Did the source change after the output was produced?
- Did someone edit the provenance record itself?
- Can CI fail closed when the evidence shape is unknown?
ProvBind turns those questions into deterministic checks.
Quick start
Requires Python 3.10+. For the source release:
git clone https://github.com/yunying24/provbind.git
cd provbind
pip install .
After the first PyPI release, the package will also install as pip install provbind.
Create an artifact and a source:
printf 'source bytes\n' > source.txt
printf 'derived output\n' > report.md
Seal the binding:
provbind seal report.md --source source.txt -o provbind.json
Verify later:
provbind verify provbind.json
Expected output:
PASS artifact:report.md — artifact bytes match
PASS local_file:source.txt — source bytes match
VERIFIED
Change either file and verification fails with a non-zero exit code.
Exact GitHub sources
GitHub sources must use an exact 40-hex commit SHA. Branches, tags, and abbreviated SHAs are rejected.
provbind seal report.md \
--github-source openai/openai-python@0123456789abcdef0123456789abcdef01234567:README.md \
-o provbind.json
For private repositories, set GITHUB_TOKEN in the environment. ProvBind fetches the file through the GitHub Contents API at the exact commit recorded in the manifest.
This is intentional:
main -> rejected
v1.2.3 -> rejected
abc1234 -> rejected
40-hex commit SHA -> accepted
A provenance record should bind immutable source identity, not a mutable name.
Commands
provbind seal
Create a new manifest.
provbind seal ARTIFACT \
--source LOCAL_SOURCE \
--github-source OWNER/REPO@COMMIT:PATH \
--root . \
-o provbind.json
Both --source and --github-source are repeatable. At least one source is required.
provbind verify
Recompute artifact and source digests and compare them with the sealed claims.
provbind verify provbind.json --root .
provbind verify provbind.json --root . --json
Exit codes:
0: verified2: invalid manifest, unavailable evidence, or byte mismatch
provbind inspect
Inspect a manifest without fetching or re-reading its sources.
provbind inspect provbind.json
provbind diff
Compare two valid manifests.
provbind diff old.json new.json
The diff reports artifact changes and source additions, removals, or changes.
Manifest model
A v1 manifest looks like this:
{
"schema_version": "provbind-manifest-v1",
"binding_id": "...",
"created_at": "2026-08-08T01:00:00Z",
"artifact": {
"path": "report.md",
"sha256": "...",
"size": 15
},
"sources": [
{
"kind": "local_file",
"path": "source.txt",
"sha256": "...",
"size": 13
}
],
"producer": "provbind/0.1.0"
}
binding_id is the SHA-256 of ProvBind's canonical JSON encoding of:
schema_version + artifact claim + ordered source claims
created_at is intentionally excluded from binding_id, so the same artifact/source claim has the same binding identity even if the manifest is regenerated at a different time.
The JSON Schema is published at schemas/provbind-manifest-v1.schema.json. Runtime validation is implemented without third-party dependencies and is stricter than simply parsing JSON.
Fail-closed design
ProvBind v1 intentionally accepts a small closed evidence model:
local_filegithub_file
Unknown top-level fields are rejected. Unknown fields inside artifact/source objects are rejected. Unknown source kinds are rejected. Duplicate source identities are rejected. Parent-directory traversal in local paths is rejected. GitHub mutable refs are rejected.
New source types should be introduced through a new reviewed schema/version rather than silently accepted by old verifiers.
GitHub Actions
This repository includes a composite Action:
- uses: yunying24/provbind@v0.1.0
with:
manifest: provbind.json
root: .
The action installs ProvBind from the checked-out action source and runs verification. A failing binding fails the workflow.
You can also install the CLI directly in any CI system:
- run: pip install provbind
- run: provbind verify provbind.json --root .
Threat model
ProvBind is designed to detect:
- source bytes changing after a manifest was created;
- artifact bytes changing after a manifest was created;
- provenance claim edits that are not accompanied by a recomputed binding;
- use of mutable GitHub refs in a byte-binding claim;
- malformed or unexpectedly widened manifest shapes.
ProvBind does not currently defend against an attacker who can replace the artifact, every source, and the manifest together. That requires an external trust anchor such as a signed release, transparency log, trusted CI attestation, or another independent publication channel. Those are roadmap items, not v0.1 claims.
Design principles
- Exact bytes over labels. A source name is not evidence of source identity.
- Immutable refs over mutable refs. GitHub bindings use exact commit SHAs.
- Closed schemas over permissive parsing. Unknown evidence shapes fail closed.
- Separate verification from correctness. Matching bytes do not make content true.
- Local-first verification. Local-file verification requires no service or account.
- Small trusted core. v0.1 has zero runtime Python dependencies.
Use cases
- bind an AI-generated research memo to its input corpus;
- bind a coding-agent patch/report to exact repository files;
- preserve source identity for automated market or technical reports;
- fail CI when evidence or generated outputs drift;
- attach a portable provenance manifest to releases or audit artifacts.
Example
See examples/basic for a complete local example with a pre-generated valid manifest.
provbind verify examples/basic/provbind.json --root examples/basic
Project status
ProvBind is alpha. The v1 format is intentionally small while the core invariants are tested and reviewed.
See ROADMAP.md for planned work, including signed attestations, Git tree/blob identity, HTTP content-addressed sources, reusable policy profiles, and integrations for coding/research agents.
Contributing
Issues, test cases, source adapters, security review, and integration examples are welcome. See CONTRIBUTING.md.
Security
Please report security-sensitive findings privately as described in SECURITY.md.
License
MIT. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file provbind-0.1.0.tar.gz.
File metadata
- Download URL: provbind-0.1.0.tar.gz
- Upload date:
- Size: 17.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38e2501777ca5af1daffb53be02eef03f61a2b27decacfb18afdb05b38eeed0a
|
|
| MD5 |
8c6084f265adea80d96bfb3bf8b403a0
|
|
| BLAKE2b-256 |
d3c23ae81b2d141d488f725d6a2d8f86410f8363cefdbc22365614d3711363eb
|
Provenance
The following attestation bundles were made for provbind-0.1.0.tar.gz:
Publisher:
publish.yml on yunying24/provbind
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
provbind-0.1.0.tar.gz -
Subject digest:
38e2501777ca5af1daffb53be02eef03f61a2b27decacfb18afdb05b38eeed0a - Sigstore transparency entry: 2377902779
- Sigstore integration time:
-
Permalink:
yunying24/provbind@6f2a6e2889cf414a267017615a30cd321727b50e -
Branch / Tag:
refs/heads/release/v0.1.0-bootstrap - Owner: https://github.com/yunying24
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6f2a6e2889cf414a267017615a30cd321727b50e -
Trigger Event:
push
-
Statement type:
File details
Details for the file provbind-0.1.0-py3-none-any.whl.
File metadata
- Download URL: provbind-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e351c35f7b5b1d41b37b3a99cc2415611867d9199e7750e30493d8d09042dd0e
|
|
| MD5 |
52c297853501a34d6e475ee162fa8927
|
|
| BLAKE2b-256 |
b0d5771f888768c39c8429bfa22c809e1329e3b14edaa48ab80ebdca0d136e9d
|
Provenance
The following attestation bundles were made for provbind-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on yunying24/provbind
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
provbind-0.1.0-py3-none-any.whl -
Subject digest:
e351c35f7b5b1d41b37b3a99cc2415611867d9199e7750e30493d8d09042dd0e - Sigstore transparency entry: 2377902906
- Sigstore integration time:
-
Permalink:
yunying24/provbind@6f2a6e2889cf414a267017615a30cd321727b50e -
Branch / Tag:
refs/heads/release/v0.1.0-bootstrap - Owner: https://github.com/yunying24
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6f2a6e2889cf414a267017615a30cd321727b50e -
Trigger Event:
push
-
Statement type: