Skip to main content

vda-witness (Python SDK)

Seal your AI agent's decisions into tamper-evident, Ed25519-signed, independently-verifiable evidence — the records EU AI Act Article 12 requires. Part of the Verified Digital Agents (VDA) platform; VDA Witness is its evidence layer.

  • Fail-open: sealing never raises and never blocks your agent.
  • Zero-config, zero-dependency: one import, set WITNESS_API_KEY, standard library only.
  • Independently verifiable: anyone can verify a record offline, without trusting VDA.

⚠️ Read this first — what you get out of the box (custody)

Out of the box, sealing goes to the hosted Witness service on the custodial / ephemeral (test) tier: records are signed by the Witness service, not by a key you control. Every such record honestly carries custody: "custodial" and says so in plain text.

This is for building and testing. It is NOT customer-controlled signing and is NOT compliance-grade EU AI Act Article-12 evidence — do not present ephemeral custodial records to an auditor as your own controlled evidence.

For compliance-grade evidence, use customer-managed signing — you control the private key, records carry custody: "customer-managed" ("customer-controlled signing"), and Witness never sees your key. That is the tier you put in front of an auditor.

Tier Who holds the key Record label Use for
Custodial (default/ephemeral) Witness service custodial build & test
Customer-managed You customer-managed compliance-grade evidence

Install

pip install vda-witness            # sealing — zero dependencies (standard library only)
pip install "vda-witness[verify]"  # + offline verification (adds cryptography + asn1crypto)

First seal (copy-paste — works as-is)

from vda_witness import Witness

witness = Witness()  # reads WITNESS_API_KEY

witness.seal(
    decision={"agent": "Refund Agent", "inputs": {"amount_eur": 150},
              "verdict": "PASS", "reasoning": "<= 200 and account in good standing"},
    governing_rule={"ruleId": "refund.auto",
                    "ruleText": "Agents MAY auto-approve refunds up to EUR200 where the account is in good standing."},
)

Decorate an existing agent (code unchanged beyond the decorator)

@witness.witnessed(
    to_decision=lambda args, kwargs, result: {
        "agent": "Refund Agent", "inputs": kwargs,
        "verdict": result["verdict"], "reasoning": result["why"],
    },
    rule={"ruleId": "refund.auto", "ruleText": "Agents MAY auto-approve refunds up to EUR200 ..."},
)
def decide(**request):
    ...  # your agent, untouched — sealed automatically after it returns (fail-open, bounded)

Framework adapters

from vda_witness import witness_openai
witness_openai(client, witness, {"ruleId": "assistant.sop", "ruleText": "..."})  # seals each chat.completions.create

Anthropic, LangChain, CrewAI, and the Vercel AI SDK use the same wrap-and-seal pattern (witness.witnessed(...)); typed adapters ship per release.

Verify a record offline — the moat (v1.0)

Independent, three-state verification with zero calls to a Witness server (needs the [verify] extra). It checks the Ed25519 signature + hash-chain + the historical DID key, and the anchor against public infrastructure (Sigstore Rekor + an RFC-3161 TSA). Pure Python — no openssl shell (cryptography + asn1crypto).

verdict = witness.verify_offline(record, chain, did_document, anchor=anchor)  # mode="bundled" | "live-public"
# verdict["state"] is one of:
#   "ANCHORED_VALID" — signed, chained, and the head is anchored (Rekor + >=1 TSA)
#   "SIGNED_PENDING" — signed + chained, honestly not-yet-anchored (within cadence)
#   "BROKEN"         — verdict["reason"] in {signature, chain, key, anchor, malformed}
if verdict["state"] == "ANCHORED_VALID":
    ...  # trust it
  • Modes: mode="bundled" (air-gappable — verifies the captured Rekor SET + TSA token with no network) or mode="live-public" (re-fetches the Rekor inclusion from rekor.sigstore.dev directly). Neither ever contacts a Witness endpoint; did_document is always supplied in the bundle.
  • Anchor quorum: Rekor (required) + >=1 TSA — DigiCert is pinned; Sectigo is not yet pinned, so DigiCert satisfies the TSA leg today.
  • Verdicts are byte-for-byte identical to the JS SDK on the same input.

Deprecated: witness.verify(record=...) (boolean, server round-trip) is now an alias of witness.verify_via_server(...) and requires the Witness server — not independent verification. Migrate to verify_offline. A boolean can't express SIGNED_PENDING without overclaiming or false-alarming.

Options

Witness(api_key=None, base_url="https://witness.getvda.ai", timeout=3.0, fire_and_forget=False, on_error=None). Set fire_and_forget=True for zero added latency (seal on a background thread).

Honest scope: Witness produces the evidence (Art. 12 record-keeping), not a compliance certificate. The Article 12 Evidence Report is generated from your sealed trail; Compliance Officer attestation makes it a regulatory artefact.

License

Apache-2.0 licensed — see LICENSE.

Metadata

Release files for vda-witness 1.0.0

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

Source distribution (sdist)

Source distribution for vda-witness 1.0.0
File Size Uploaded
vda_witness-1.0.0.tar.gz 21.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for vda-witness 1.0.0
File Interpreter ABI Platform
vda_witness-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 40.9 kB

Release files / vda_witness-1.0.0.tar.gz

Download URL vda_witness-1.0.0.tar.gz
Size 21.2 kB
Tags Source
SHA-256 checksum
How to use checksums
2949e35749af477e4f8df9299bb50765d19d85524283828acb0440eab1e70297
BLAKE2b-256 checksum
How to use checksums
f76e387c4100187ef6820c9c1a910f6d762c3a040701e7a2e282aba2fc887f25
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.10

Release files / vda_witness-1.0.0-py3-none-any.whl

Download URL vda_witness-1.0.0-py3-none-any.whl
Size 19.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c60f9b21dd00aec2d94bba0a2d2ffd2c7aed68d6f9fb163da27538fd325fd70c
BLAKE2b-256 checksum
How to use checksums
9ec44ca774152ac8fd5af27713e8afdaa1eb88cf6d530520a7ee829b33b57a7c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.10

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

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