Wytness — the blackbox recorder for AI agents. Customer-held PII keys, per-event Ed25519 signing, audit-ready evidence packs. Built on Microsoft's Agent Governance Toolkit.
Project description
wytness
Wytness wrapper for Microsoft's Agent Governance Toolkit (AGT). Adds the two security properties AGT does not ship:
- Non-repudiation — per-event Ed25519 signature with a customer-held private key. Asymmetric verification: anyone with the public key can verify, no shared secret.
- Zero-knowledge PII — HMAC-SHA256 pseudonyms + X25519 + ChaCha20-Poly1305 token-map encryption. Wytness never sees raw PII.
These compose with AGT's own primitives (Ed25519 agent identity, SHA-256 Merkle hash chain). See docs/agt-wrapper-design.md §2.5 for the full layered model.
Mirrors wytness_ai (TypeScript) — same wire format, same init() / shutdown() lifecycle, same env-var contract.
Status
v1.0.0 — first stable release. Coordinated launch with wytness 1.0.0 (TypeScript). WytnessAuditSink, WytnessEventSink, WytnessTransport, init(), shutdown(), the Ed25519 envelope (envelope_version: 2 — signature covers data + envelope id/time/type), the X25519 + ChaCha20-Poly1305 PII token-map with auto-attach, the typed exception hierarchy (WytnessSDKError + subclasses), the top-level stats() / health() / wire_status() accessors, and the AGT AuditLog monkey-patch all ship as working code. agent-governance-toolkit[full]==3.7.0 is a hard dependency since the wrapper monkey-patches AGT's AuditLog symbol on init({auto_wire=True}) (the default) so every audit entry AGT chains is automatically forwarded into the Wytness envelope path with full 3-layer evidence (AGT identity + AGT Merkle chain + Wytness envelope).
Tests: 68 pytest green covering config validation (XOR PII pairing guard, signing-key prefix/length tolerance, env-var fallback), envelope signing + tamper-detection, PII pseudonymisation + per-sink token-map encryption + auto-attach, transport batching + retry + dead-letter file + jittered backoff, init/shutdown idempotency, stats/health pre-init safety, and end-to-end framework-adapter compatibility against AGT 3.7.0's 12 integrations (LangChain, CrewAI, LangGraph, MCP, etc.). Backend dual-accepts envelope_version 1 + 2 during the deprecation window — see CHANGELOG.md for the v1 → v2 wire-format migration.
Install
pip install wytness-ai
agent-governance-toolkit[full]==3.7.0 is a hard dependency — installed automatically. No extras to remember. Python >=3.11.
Hello world
from wytness_ai import init, shutdown, AuditLog
init(
api_key="wyt_...",
signing_key="...", # browser-generated Ed25519 (always required)
pii_pubkey="...", # browser-generated X25519 (optional, paired with pii_secret)
pii_secret="...", # browser-generated HMAC secret (optional, paired with pii_pubkey)
pii_fields=["customer.email"],
)
# AGT owns identity + Merkle chain. The wrapper has already monkey-patched
# AuditLog — every entry below also flows to Wytness.
audit = AuditLog()
audit.log(
event_type="tool_invocation",
agent_id="my-first-agent",
data={
"customer": {"email": "alice@example.com"},
"query": "best espresso",
},
)
shutdown()
AuditLog is re-exported from wytness_ai for convenience, so a single import line covers both lifecycle and audit. The original from agentmesh.governance.audit import AuditLog is identical and still works.
PII is pseudonymised before AGT computes its chain hash (so AGT's hashes commit to the redacted bytes — chain verification still works), the canonical-JSON envelope is signed with your Ed25519 key, and the batch lands at `api.wytness.ai/ingest`. Failed POSTs land in `~/.wytness/wytness-deadletter.jsonl`.
`init()` reads `WYTNESS_API_KEY` / `WYTNESS_SIGNING_KEY` / `WYTNESS_PII_PUBKEY` / `WYTNESS_PII_SECRET` / `WYTNESS_ENDPOINT` from the environment when kwargs aren't supplied. Browser-generated keys come from the [Wytness dashboard's Keys page](https://app.wytness.ai/keys) (Signing Key, PII Encryption Key, and PII HMAC Key cards); the dashboard never sees your private halves.
A complete runnable example lives at [`examples/hello-world/`](examples/hello-world/) — it generates ephemeral demo keys if no `WYTNESS_*` env vars are set, so you can `python examples/hello-world/main.py` immediately after install.
### Manual wiring (no monkey-patch)
If you'd rather wire explicitly, pass `auto_wire=False` and use the audit sink directly. The sink accepts AGT `AuditEntry` instances + dicts shaped like one.
```python
from wytness_ai import init, get_transport
from wytness_ai.sinks import WytnessAuditSink
config = init(auto_wire=False, signing_key="...", api_key="...")
transport = get_transport()
sink = WytnessAuditSink(transport=transport, config=config)
sink.write({
"event_type": "tool_invocation",
"agent_id": "agent-1",
"data": {"query": "…"},
})
Feature parity with wytness_ai (TypeScript)
Both SDKs ship the same wire format (snake_case canonical shape, identical envelope structure, byte-comparable for the same logical input). Behavioural surface differences:
| Surface | Python | TypeScript | Notes |
|---|---|---|---|
AGT AuditLog auto-wire |
✓ — patches agentmesh.governance.audit.AuditLog |
✓ — patches AuditLogger.prototype.log from @microsoft/agent-governance-sdk |
Both default auto_wire=True / autoWire: true. |
AGT GovernanceEvent auto-wire |
✓ — registers WytnessEventSink on GovernanceEventProcessor |
✗ — manual (getEventSink().emit(...)) |
AGT-TS 3.7.0 has no GovernanceEventProcessor registry. Tracked as V2-AGT-TS-EVENT-SINK; will wire automatically when Microsoft ships the registry. |
| Wire-format byte parity | ✓ | ✓ | Cross-language fixture in sdk-typescript-agt/tests/integration/wireFormat.parity.test.ts. |
| Ed25519 envelope signing | ✓ | ✓ | Identical canonical-JSON encoding + sig scope. |
| PII pseudonymisation | ✓ | ✓ | Identical HMAC + X25519 + ChaCha20-Poly1305 primitives. |
| Framework adapter compatibility tests | ✓ — 12 integrations × 3 axes (import / monkey-patch survival / PII scrub) | ✗ — AGT-TS ships zero framework adapters in 3.7.0 |
Wire format
Each POST batch is a JSON array of CloudEvents envelopes:
[
{
"specversion": "1.0",
"id": "<uuid>",
"source": "wytness",
"type": "AuditEntry",
"datacontenttype": "application/json",
"time": "2026-05-25T00:00:00.000Z",
"data": {
"timestamp": "2026-05-25T00:00:00.000Z",
"agent_id": "my-first-agent",
"event_type": "tool_invocation",
"entry_hash": "<AGT-supplied SHA-256 hex>",
"previous_hash": "<prior entry's hash>",
"data": { "query": "…", "customer": { "email": "EMAIL_<token>" } }
},
"wytness_envelope": {
"envelope_version": 1,
"key_id": "<16 chars base64url SHA-256(pubkey)>",
"signature_ed25519": "<base64 Ed25519 sig over canonicalJson(data)>",
"pseudonymization_version": "1"
}
}
]
Content-Type: application/vnd.wytness.agt+json — every envelope is signed. Wytness has no unsigned mode; signing is the product's value prop.
License
MIT. Built on agent-governance-toolkit (MIT, Microsoft).
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
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 wytness_ai-1.0.0.tar.gz.
File metadata
- Download URL: wytness_ai-1.0.0.tar.gz
- Upload date:
- Size: 147.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
284d35224751abec9333a771d222452c71acd8a8ac5f69cb7717292529be8e8f
|
|
| MD5 |
67afd602ade52da36d013ba40b4ccd9b
|
|
| BLAKE2b-256 |
026e0c5855ea8b37e87ecb51cb32173ab9c7da9930754b540647e4a9e5b40de4
|
Provenance
The following attestation bundles were made for wytness_ai-1.0.0.tar.gz:
Publisher:
publish-wrapper-sdk.yml on imwickkd/wytness
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wytness_ai-1.0.0.tar.gz -
Subject digest:
284d35224751abec9333a771d222452c71acd8a8ac5f69cb7717292529be8e8f - Sigstore transparency entry: 1655260160
- Sigstore integration time:
-
Permalink:
imwickkd/wytness@0eda66da0a6e33d0d37c09c5beed8a5c1b1ba795 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/imwickkd
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-wrapper-sdk.yml@0eda66da0a6e33d0d37c09c5beed8a5c1b1ba795 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file wytness_ai-1.0.0-py3-none-any.whl.
File metadata
- Download URL: wytness_ai-1.0.0-py3-none-any.whl
- Upload date:
- Size: 34.2 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 |
593dd8227042ab5df816c5d7df6e25b80b826eebe47f45a06ee44537ef134151
|
|
| MD5 |
3cfbde627663ac228d5776c07d1e6778
|
|
| BLAKE2b-256 |
5dd8412b96a30bfc848f794503a553c5627d4b9a08de9109688b539f3d71f2e2
|
Provenance
The following attestation bundles were made for wytness_ai-1.0.0-py3-none-any.whl:
Publisher:
publish-wrapper-sdk.yml on imwickkd/wytness
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wytness_ai-1.0.0-py3-none-any.whl -
Subject digest:
593dd8227042ab5df816c5d7df6e25b80b826eebe47f45a06ee44537ef134151 - Sigstore transparency entry: 1655260406
- Sigstore integration time:
-
Permalink:
imwickkd/wytness@0eda66da0a6e33d0d37c09c5beed8a5c1b1ba795 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/imwickkd
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-wrapper-sdk.yml@0eda66da0a6e33d0d37c09c5beed8a5c1b1ba795 -
Trigger Event:
workflow_dispatch
-
Statement type: