Agent Evidence Layer — turns AI-agent runtime behavior into signed, tamper-evident, control-mapped audit evidence.
Project description
OpenWright — the Agent Evidence Layer
Turn the runtime behavior of AI agents into signed, tamper-evident, control-mapped audit evidence — verifiable by anyone, offline.
OpenWright sits on top of your existing OpenTelemetry instrumentation, forks a copy of your agent's runtime behavior, and turns it into signed, append-only, tamper-evident records mapped to specific regulatory controls. The evidence is verifiable by a third party without access to your data or infrastructure, and the ledger holds only hashes — never prompts or PII.
It ships five built-in, primary-source-cited framework crosswalks — plus a
narrowed EU AI Act v1 review subset (eu-ai-act-v1) and deployer-profile
variants of Art. 14 (in-the-loop / on-the-loop) and Art. 27 (FRIA-gated). You can
also write your own:
| Crosswalk | Covers | Controls |
|---|---|---|
| EU AI Act (Reg. 2024/1689) | Art. 12, 13, 14, 26, 27, 73 (high-risk subset) | 6 |
| NIST AI RMF 1.0 | Govern / Map / Measure / Manage subset | 7 |
| ISO/IEC 42001:2023 | Annex A AI-management-system subset | 6 |
| GDPR (Reg. 2016/679) | Art. 5, 22, 25, 30, 33, 35 (accountability + automated decisions) | 8 |
| SOC 2 | Trust Services Criteria — Common Criteria + Processing Integrity | 7 |
These crosswalks are maintainer-authored and cited, but not yet legally reviewed — they produce evidence, not a compliance determination.
OpenWright produces evidence that controls were exercised. It does NOT assert legal compliance, certification, or an audit opinion — those are for qualified auditors and counsel. Every artifact carries this boundary.
Install
pip install openwright-core
The distribution is openwright-core; it imports as openwright. Requires Python 3.10+.
Try it (one command)
openwright demo
Runs a complete, self-hosted, no-network demo: it instruments a sample high-risk
agent, forks the telemetry into an evidence ledger, records human approvals and
risk classifications, produces a signed report (JSON + PDF + OSCAL + SARIF)
against the EU AI Act crosswalk, verifies it offline, and shows that tampering
fails verification. It then opens an interactive page in your browser that
walks through what happened and lets you verify the real signed report
yourself — offline, in-browser (WebAssembly) — including a "Tamper" button to
watch verification fail and a "Restore" button to watch it pass again. (Use
openwright demo --no-browser for headless/CI.)
It also prints where the artifacts landed and a command to verify them yourself:
openwright verify <report.json> --pubkey <public_key.pem> --deep
Use it in your code
from datetime import timedelta
from openwright.ledger import FileLedgerBackend, Ledger
from openwright.sdk import EvidenceClient
from openwright.signing import InMemoryKeySource # use FileKeySource in production
from openwright.crosswalk import evaluate
from openwright.crosswalk_loader import load_builtin
from openwright.report import build_report
from openwright.verify import verify_report
key = InMemoryKeySource()
ledger = Ledger(FileLedgerBackend("./ledger"), retention=timedelta(days=200))
client = EvidenceClient(ledger, agent_id="my-agent")
# Record the evidence telemetry can't infer — linked by task id.
with client.task("task-42", context_id="session-7"):
approval = client.record_human_approval(reviewer="me@example.com", rationale="looks good")
client.record_risk_classification("high", rationale="high-impact decision", fria="FRIA-1")
client.record_decision(
output="APPROVED",
risk_classification="high",
rationale="meets policy",
approval_ref=approval.event_id, # links the decision to the approval
control="art-14-human-oversight",
)
# Evaluate a crosswalk, build a signed report, verify it offline.
result = evaluate(load_builtin("eu-ai-act"), list(ledger.events()))
report = build_report(ledger, result, key, scope_description="my agent")
verdict = verify_report(report, trusted_public_key_raw=key.public_key_raw())
print({c["control_id"]: c["status"] for c in report["controls"]})
print("verified offline:", verdict.valid)
Collect from a live agent
Point your app's OTLP exporter at the collector; your existing backend keeps receiving telemetry unchanged while a copy is forked into the evidence ledger:
openwright collector --downstream http://your-existing-otlp-backend:4318
CLI
openwright demo Run the full end-to-end demo.
openwright collector --downstream URL Run the OTLP collector (gRPC+HTTP); fan out + fork to ledger.
openwright report LEDGER --key K Build a signed report (JSON/PDF/OSCAL/SARIF) from a ledger.
openwright verify REPORT --pubkey K Verify a signed report offline (--deep re-checks verdicts).
openwright gate REPORT -r CONTROL CI/CD gate: non-zero exit if a required control is unsatisfied.
openwright crosswalks List built-in crosswalks.
openwright connectors list List installed connectors (sources/forwarders/exporters/storage).
openwright export REPORT --to NAME Export a report to a sink (GRC/CI) via an installed exporter.
openwright keygen --out key.pem Generate an Ed25519 signing key you control.
openwright version
Connectors
OpenWright exposes a small, versioned connector contract (openwright.connectors,
v1.0): framework-capture sources, downstream forwarders, report exporters, and
pluggable ledger/checkpoint storage backends. Connectors are independently
installable openwright-<name> packages discovered via entry points — core never
depends on a connector, so adding one needs zero core change. Resolve storage by
URI (openwright collector --ledger-backend postgres://… --checkpoint-store s3://…)
and see what's installed with openwright connectors list.
Run openwright --help for the full list.
License
Apache-2.0.
Project details
Release history Release notifications | RSS feed
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 openwright_core-0.6.0.tar.gz.
File metadata
- Download URL: openwright_core-0.6.0.tar.gz
- Upload date:
- Size: 107.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61072d915e115af26e93f220e76e32bee8ab5f7fdc1e9caf62105f6e0145f9b1
|
|
| MD5 |
e3a34bc741c10036f30199d705bcc525
|
|
| BLAKE2b-256 |
295bb212a9b9aafd3f16aace204c00646687b9f33f3f460c5c3c5771d378d619
|
Provenance
The following attestation bundles were made for openwright_core-0.6.0.tar.gz:
Publisher:
release.yml on allthingsN/openwright
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
openwright_core-0.6.0.tar.gz -
Subject digest:
61072d915e115af26e93f220e76e32bee8ab5f7fdc1e9caf62105f6e0145f9b1 - Sigstore transparency entry: 1711933498
- Sigstore integration time:
-
Permalink:
allthingsN/openwright@7c014297539fc8dadccad0463784465ae51f1c9a -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/allthingsN
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7c014297539fc8dadccad0463784465ae51f1c9a -
Trigger Event:
push
-
Statement type:
File details
Details for the file openwright_core-0.6.0-py3-none-any.whl.
File metadata
- Download URL: openwright_core-0.6.0-py3-none-any.whl
- Upload date:
- Size: 134.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b3f748d457c8505b710a93a15fc2b9dc8cec301ef149012fd3404d26adf78a9
|
|
| MD5 |
89bfab2c8ff0e142089300a7ab74de11
|
|
| BLAKE2b-256 |
ac673dbf6bb46e717b7795e3d19f516d26d11c8296ebf84e7e79feb5cf3f7aeb
|
Provenance
The following attestation bundles were made for openwright_core-0.6.0-py3-none-any.whl:
Publisher:
release.yml on allthingsN/openwright
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
openwright_core-0.6.0-py3-none-any.whl -
Subject digest:
1b3f748d457c8505b710a93a15fc2b9dc8cec301ef149012fd3404d26adf78a9 - Sigstore transparency entry: 1711933523
- Sigstore integration time:
-
Permalink:
allthingsN/openwright@7c014297539fc8dadccad0463784465ae51f1c9a -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/allthingsN
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7c014297539fc8dadccad0463784465ae51f1c9a -
Trigger Event:
push
-
Statement type: