EvidenceBound Core
WebMCP Challenge: one human, one release, one capability
A release manager has a simple problem: an AI agent may need permission to perform a controlled release action, but that permission must not survive after the human decision or the evidence behind it changes.
EvidenceBound makes the human decision visible in the WebMCP capability surface itself. The agent starts with three safe tools. It can inspect release state and request approval, but it cannot approve, revoke, correct, or restore its own authority. When a human approves one exact release snapshot, a fourth tool — execute_authorized_release — appears. If the human corrects the security evidence or revokes approval, that tool disappears. Execution also re-checks current authority, so a stale retained capability cannot succeed after the decision changes.
Judge moment: 3 tools → human approval → 4 tools → human correction/revocation → 3 tools.
Live demo: https://evidencebound.org/webmcp/ · Judge guide: WEBMCP.md
The controlled demo records externalSideEffect=false; it does not claim to perform a real external deployment.
EvidenceBound is a framework-agnostic, LLM-independent runtime for binding agent outputs to evidence, provenance and policy; verifying protected state; computing dependency blast radius; and planning fail-closed selective recovery.
Created and maintained by Ruslan Vrublevskyi.
Status: GitHub source release
v0.3.0published 2026-08-17 from exact commit2477164acfbdca6a843bf7b2eac5fa21ce9901b2. The tagged source passed the full Python 3.10–3.13, clean-room, typing/build, benchmark and security CI gates before publication. Currentmaincontains additional Unreleased hardening, including provider-neutral signed receipts, durable persistence/restart support, and a real Google ADK 2.7.0 lifecycle compatibility lane. PyPI is not published. Pre-1.0 API compatibility is not guaranteed.
Why EvidenceBound?
Agent memory answers “what did the system remember?” EvidenceBound adds “what evidence supported it, which policy governed it, is the historical record intact, is it still applicable, and what must be recomputed if a dependency changes?”
It is not a vector database, RAG framework, tracing backend, LLM framework, truth oracle, or consensus system. A cryptographic digest or signature can bind/authenticate bytes under configured trust roots; neither can make a malicious upstream source truthful. A durable database row is likewise not automatically trusted state.
flowchart LR
A[Agent / workflow] --> B[thin adapter]
B --> C[EvidenceBound Core]
C --> D[Evidence + provenance binding]
D --> E[Deterministic verification]
E --> F[Policy/version binding]
F --> G[Trust graph + invalidation]
G --> H[Recovery plan + proof receipt]
H --> I{Action gate}
I -->|ALLOW| J[Application action]
I -->|REVIEW_REQUIRED| K[Review / reverify]
I -->|BLOCK| L[Fail closed]
Install
From a checkout:
python -m pip install .
No unconditional runtime dependency is required beyond Python 3.10+. The SQLite reference persistence provider uses Python's stdlib sqlite3 and therefore adds no third-party dependency.
Optional Ed25519 signed-receipt reference provider:
python -m pip install '.[crypto]'
5-minute quickstart
from evidencebound import (
EvidenceBound, EvidenceRecord, InvalidationReason,
PolicyBinding, ProvenanceRecord,
)
policy = PolicyBinding("research-policy", "1")
eb = EvidenceBound(policy=policy)
evidence = [EvidenceRecord(
evidence_id="paper-1",
payload={"claim": "observed"},
provenance=ProvenanceRecord("paper", "doi:10.0000/example"),
)]
research = eb.checkpoint(
agent="researcher",
evidence=evidence,
output={"summary": "supported"},
)
decision = eb.verify(research)
print(decision.action) # ALLOW for this complete/current snapshot
print(decision.receipt) # tamper-evident binding receipt
plan = eb.invalidate(
checkpoint_id=research.checkpoint_id,
reason=InvalidationReason.EVIDENCE_CHANGED,
)
print(plan.reusable)
print(plan.requires_verification)
print(plan.recompute)
Run the complete external acceptance scenario:
python examples/golden_acceptance.py
It proves the intended sequence: checkpoint → receipt → tamper detection → historical integrity retained while applicability requires review → exact invalidation → consequential action blocked until successful path-specific re-verification.
Trust semantics
Evidence state and record integrity are separate dimensions.
UNCHANGED: current evidence identity and digest match the protected snapshot.NEW: a supplied current evidence ID was absent from the protected snapshot.CHANGED: the digest differs. This does not mean REFUTED.STALE: validity horizon has elapsed when an explicit current time is supplied.MISSING: required current evidence is absent or its supplied identity does not match the protected record.REFUTED: an upstream verifier explicitly marks evidence refuted.
Current evidence mapping keys must match the contained EvidenceRecord.evidence_id; an identity mismatch fails closed rather than being accepted because payload bytes happen to match.
Possible outcomes:
- historical integrity
VERIFIED+ current applicabilityVERIFIED→ALLOW; - historical integrity
VERIFIED+ changed/stale/new/policy-drift applicability →REVIEW_REQUIRED; - integrity failure, missing/refuted evidence, identity mismatch, or required provenance loss →
BLOCK.
What a receipt proves
The base ProofReceipt binds a checkpoint to a deterministic SHA-256 digest under the versioned EBCJ-1 canonicalization domain. verify_receipt() validates receipt metadata and checkpoint binding; verify_verification_receipt() additionally binds the supplied historical verification result. Unsigned receipts remain tamper-evident when retained or anchored independently of mutable checkpoint state, but they do not authenticate an issuer.
Current main also exposes provider-neutral ReceiptSigner / ReceiptVerifier contracts plus SignedProofReceipt, sign_receipt() and verify_signed_receipt(). The optional Ed25519 provider lives under evidencebound.providers.ed25519 and is not imported by core. ACTIVE keys may create new signatures; RETIRED keys may verify historical receipts; REVOKED/UNKNOWN keys and unsupported algorithms fail closed. Legacy unsigned receipts remain explicitly UNSIGNED and are never silently upgraded.
A valid signature authenticates the signed receipt under the application's configured key identity/trust roots. It does not prove upstream truth, provenance honesty, secure key custody, secure time, or legal compliance. See docs/SIGNED_RECEIPTS.md.
Durable persistence and restart
Current main defines a provider-neutral PersistenceStore contract and a stdlib reference implementation at evidencebound.providers.sqlite.SQLiteStore.
from evidencebound.providers.sqlite import SQLiteStore
with SQLiteStore("agent-state.sqlite3") as store:
store.commit_bundle(checkpoint, verification_result)
# New process / later restart
with SQLiteStore("agent-state.sqlite3") as store:
graph, verification_by_id = store.load_recovery_state()
Checkpoint, receipt, verification state and an optional replay record are committed as one transaction. A pre-commit interruption rolls the bundle back. On reopen, persisted verification is not trusted because it was stored: EvidenceBound reconstructs the checkpoint/receipt/result and re-runs deterministic result binding before the state can feed recovery as reusable.
SQLiteReplayGuard preserves equal-payload duplicate detection and conflicting-payload rejection across restart. It remains an idempotency primitive, not an exactly-once guarantee. Unknown/incomplete persistence schemas fail closed; the alpha provider does not silently migrate trust-bearing history.
SQLite is not claimed immutable or authenticated. For attackers able to rewrite both checkpoint and receipt state consistently, use an independent receipt anchor and/or signed receipts with independently protected verification roots as appropriate to the threat model. See docs/PERSISTENCE.md.
Canonicalization
EBCJ-1 accepts null, booleans, integers, Unicode strings, lists, and string-keyed maps. Maps are sorted, JSON is compact UTF-8, and floats are rejected to avoid cross-runtime ambiguity. This is an EvidenceBound format, not a claim of RFC 8785 compliance. See SPEC.md.
Recovery
DependencyGraph validates IDs/dependencies, rejects cycles, provides deterministic topological ordering, and computes exact descendants.
plan_recovery() distinguishes:
recompute: checkpoints in the exact invalidation blast radius;reusable: unaffected checkpoints with anALLOWverification result cryptographically bound to the exact checkpoint currently in the graph;requires_verification: unaffected state that cannot yet be trusted for reuse;blocked: consequential actions that may not proceed.
Re-verification requirements are dependency-path-specific, so an unrelated invalidation does not contaminate an independent branch. ReplayGuard provides in-process idempotent duplicate detection; SQLiteReplayGuard can persist those semantics across restart. Neither claims exactly-once execution.
Adapters
Core never imports an agent framework. Included integration seams:
evidencebound.adapters.run_guarded— plain Python callable hook.evidencebound.adapters.google_adk.AdkCallbackAdapter— dependency-free Google ADK seam. Current Unreleasedmainalso includesadk_consequential_action_allowed(), a fail-closed application gate that requires explicit serialized EvidenceBoundALLOWcallback state.
The maintained compatibility CI currently installs exactly google-adk==2.7.0 on Python 3.13 in an isolated job after installing EvidenceBound without integration dependencies. A credential-free synthetic real ADK BaseAgent/Runner scenario proves runtime callback_context keyword invocation, persisted callback state on completed lifecycle, emitted state delta, and blocked consequential state when the async event stream is closed before after_agent_callback. This is evidence for the exact tested ADK version, not a blanket compatibility claim for other releases.
See docs/INTEGRATION.md.
Verify this checkout
python -m pip install -e '.[dev]'
pytest
python examples/golden_acceptance.py
python benchmarks/selective_recovery.py
python -m compileall -q src examples benchmarks compat
ruff check .
mypy src/evidencebound
python -m build
CI additionally performs an isolated clean-room installation, runtime-dependency assertion, pip-audit, Bandit scan, wheel reinstall/import, the benchmark acceptance scenario, and the isolated exact-version Google ADK compatibility lane. See .github/workflows/ci.yml and RELEASE_READINESS.md.
Security and non-goals
Read THREAT_MODEL.md before using EvidenceBound for consequential actions. The library helps detect unsupported/missing/stale/refuted evidence when that state is supplied or derivable; it cannot establish truthfulness of a malicious source, protect a compromised runtime, guarantee safe key custody/immutable storage, or guarantee legal/regulatory compliance.
Project documents
ARCHITECTURE.mdSPEC.mdTHREAT_MODEL.mdSECURITY.mdCONTRIBUTING.mdROADMAP.mddocs/SIGNED_RECEIPTS.mddocs/PERSISTENCE.mddocs/INTEGRATION.mdRELEASE_READINESS.mdFUNDING_READINESS.mdPREEXISTING_WORK.mdLICENSE_DECISION.md
License
Apache-2.0. See LICENSE_DECISION.md for the project-specific rationale and provenance boundary.
Metadata
Release files for evidencebound-core 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| evidencebound_core-0.4.0.tar.gz | 51.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| evidencebound_core-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 85.6 kB
Release files / evidencebound_core-0.4.0.tar.gz
| Download URL | evidencebound_core-0.4.0.tar.gz |
|---|---|
| Size | 51.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6117c86f69fb4515e41b32b694f6269b70ee5becd9b002ed5e81f28a1c1fdd50
|
|
BLAKE2b-256 checksum How to use checksums |
167ac966b05dd22d77a6de7f88b28b54cd5de720e0377c2896fb26ea7bb3e37b
|
| 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 5, 2026.
Transparency logRelease files / evidencebound_core-0.4.0-py3-none-any.whl
| Download URL | evidencebound_core-0.4.0-py3-none-any.whl |
|---|---|
| Size | 34.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
be254699027b5869755d9ba36351c3bd985669e9a566f6b0b7dc8c834812bdba
|
|
BLAKE2b-256 checksum How to use checksums |
5ca4a041d032c5390d09b4a1e1ff72df6999c459787cce3bcb61104fcc05be3f
|
| 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 5, 2026.
Transparency log