Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openwright_core-0.7.0.tar.gz (109.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openwright_core-0.7.0-py3-none-any.whl (137.9 kB view details)

Uploaded Python 3

File details

Details for the file openwright_core-0.7.0.tar.gz.

File metadata

  • Download URL: openwright_core-0.7.0.tar.gz
  • Upload date:
  • Size: 109.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for openwright_core-0.7.0.tar.gz
Algorithm Hash digest
SHA256 07af42c7440aba48d2be64a74cc2dff40a1ac3fad06eb165641e5d4a3dcff679
MD5 a9bc2e93140a21c98db9ecb475f96b57
BLAKE2b-256 adc935c12b95c6e9becb64675cafb9fce6d08c4985db12fba89fad52e29a9f44

See more details on using hashes here.

Provenance

The following attestation bundles were made for openwright_core-0.7.0.tar.gz:

Publisher: release.yml on allthingsN/openwright

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file openwright_core-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: openwright_core-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 137.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for openwright_core-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 dd81ebcd61e16f1b836ffc5e741e2020fd0e802f1598b200e1e052433f596624
MD5 7c23c4776f5a639eb5881aab1c5b0f0c
BLAKE2b-256 164fae293dcf7ba0d0b4a2eca1e3c919071b7885cabab683c8efc9ddb50b0dd9

See more details on using hashes here.

Provenance

The following attestation bundles were made for openwright_core-0.7.0-py3-none-any.whl:

Publisher: release.yml on allthingsN/openwright

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page