Skip to main content

Zanii Python SDK — verifiable identity and proof-of-action for AI agents

Project description

zanii

Verifiable identity and proof-of-action for AI agents. Give every agent a cryptographic identity (did:key), scope what it's allowed to do with signed delegation certificates, and emit a tamper-proof, hash-chained receipt for every action it takes — anchored in an RFC 6962 Merkle transparency log. Anyone can verify what an agent did, offline, without trusting the server that stored it.

Full protocol parity with the TypeScript SDK (@zanii/core / @zanii/sdk) — cross-language test vectors guarantee byte-identical hashes and signatures. The only runtime dependency is cryptography.

pip install zanii

Quickstart

from zanii import ZaniiAgent, fetch_and_verify_proof
from zanii.core import generate_keypair, create_cert

# 1. Identities. The owner delegates a scoped, expiring capability to the agent.
owner = generate_keypair()
agent = generate_keypair()
cert = create_cert(
    issuer=owner.did,
    subject=agent.did,
    scopes=["crm.*"],                 # this agent may only act within crm.*
    exp="2027-01-01T00:00:00Z",
    issuer_private_key=owner.private_key,
)

# 2. Instrument the agent. Every action is signed and hash-chained locally,
#    then batched to the log.
zanii = ZaniiAgent(
    server_url="https://ledger.zanii.agency",
    agent_did=agent.did,
    agent_private_key=agent.private_key,
    delegation=[cert],
    # api_key="zk_live_...",          # required when the log enforces write auth
)
receipt, receipt_hash = zanii.record(target="crm.lookup", payload={"email": "a@b.co"})
zanii.flush()                         # ship queued receipts to the log

# 3. Anyone can verify that proof — offline, zero trust in the server.
proof = fetch_and_verify_proof("https://ledger.zanii.agency", receipt_hash)
assert proof.ok

wrap_tool instruments an existing function so every call (sync or async) is recorded automatically — result on success, error on failure:

lookup = zanii.wrap_tool("crm.lookup", crm.find)   # crm.find is your own function
lookup("a@b.co")                                    # transparently receipted

zanii.core — pure verification, no network

Import from zanii.core when you only build or verify proofs and never touch the network (an auditor, a third-party verifier, an offline signer). Everything there is deterministic and does no I/O; the network client lives on the top-level zanii package.

from zanii.core import verify_audit_bundle

# A self-contained audit bundle (GET /v1/export/{agent_did}) is verified with no
# trusted party: signatures, delegation scope, Merkle inclusion, the per-agent
# hash chain, and on-chain anchor consistency.
report = verify_audit_bundle(bundle)
assert report.ok, [c for c in report.checks if not c["ok"]]

Fully typed — ships py.typed (PEP 561), so your type-checker sees every signature.

MCP proxy

Front any MCP server so every tool call is receipted — no changes to the agent or the upstream server. Install the extra:

pip install "zanii[mcp]"

Wrap a connected upstream ClientSession with a ZaniiAgent; serve the result in place of the real server. Tool lists pass through unchanged; each call is recorded as mcp.<tool> — result on success, error on failure.

from zanii import ZaniiAgent
from zanii.mcp_proxy import create_zanii_proxy

proxy = create_zanii_proxy(upstream_session, ZaniiAgent(...))

Or run it standalone over stdio, wrapping an upstream stdio MCP server:

ZANII_SERVER=https://ledger.zanii.agency ZANII_IDENTITY=./identity.json \
    python -m zanii.mcp_proxy -- npx some-mcp-server --its-args

Agent runtime — deterministic rails

The SDK above records proofs. zanii.runtime (optional) is the layer that governs the action itself: the model proposes, tested code disposes. It enforces the accountability rules that sit above the ledger — scoped authority, "no external receipt → no claim of success", a fixed status vocabulary, manifest validation, and a human confirmation gate for irreversible actions.

pip install "zanii[runtime]"   # pure logic, no extra deps — ships with base zanii too
from zanii import ZaniiAgent
from zanii.runtime import Runtime, Tool, ToolResult

def send_email(to, subject):
    provider_id = mail.send(to, subject)          # your real integration
    return ToolResult(ok=True, receipt_id=provider_id)   # the provider's receipt

rt = Runtime(ZaniiAgent(...), [
    Tool("email.send", scope="email.*", run=send_email, irreversible=True),
])

d = rt.propose("email.send", {"to": "a@b.co", "subject": "Hi"}, intent="follow up")
# → irreversible ⇒ d.status == "awaiting_confirmation"; nothing sent yet
d = rt.confirm(d.confirmation_id)                 # owner says yes (bound to this exact action)
# → d.status == "sent" (a provider receipt was returned) and it's recorded on the ledger

Status is earned: no receipt_idattempted (never sent); a matched read-back ⇒ confirmed; a thrown tool ⇒ failed. Out-of-scope or unknown tools are rejected before anything runs; low confidence returns clarify instead of guessing.

Links

More optional modules

  • zanii.webhooks — verify X-Zanii-Signature and dispatch typed webhook events: create_webhook_receiver(secret, on={...}). Stdlib only.
  • zanii.testingfake_ledger() context manager + make_identity / make_cert / make_receipt fixtures. Unit-test agents offline (no server, real Merkle proofs).
  • zanii.monitor — independent append-only + anchor watchdog. check_once(server), or the zanii-monitor CLI (zanii-monitor --server … --once).

Changelog

  • 0.3.0 — added zanii.webhooks, zanii.testing, and zanii.monitor (+ zanii-monitor CLI).
  • 0.2.0 — added zanii.runtime (deterministic agent rails).
  • 0.1.0 — initial release: the client SDK, the pure zanii.core verification namespace, verify_audit_bundle, py.typed, and the zanii.mcp_proxy (pip install "zanii[mcp]").

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

zanii-0.3.0.tar.gz (37.2 kB view details)

Uploaded Source

Built Distribution

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

zanii-0.3.0-py3-none-any.whl (35.0 kB view details)

Uploaded Python 3

File details

Details for the file zanii-0.3.0.tar.gz.

File metadata

  • Download URL: zanii-0.3.0.tar.gz
  • Upload date:
  • Size: 37.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.5

File hashes

Hashes for zanii-0.3.0.tar.gz
Algorithm Hash digest
SHA256 2ab06e0894901f7790fcf24c907b8be269b5d85f67f8991c4785c17da40dc572
MD5 7631d5c6fcb7056a6caba5104f1533a3
BLAKE2b-256 68e89df5d5da4c4709544bd2953ad81242cf8d5345ff2a8bc67c27bc0a6244b1

See more details on using hashes here.

File details

Details for the file zanii-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: zanii-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 35.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.5

File hashes

Hashes for zanii-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 85d583468d352d1d34fb6f59826b03974ee5e261373d40d98eca79b0e2e5f4d6
MD5 33e0fbf996c27201afc527a719e46739
BLAKE2b-256 9f8b5f71b3caf0e9b34dc6722b1cdb5ee650ac063c74f9c00ca3cc4179cd0966

See more details on using hashes here.

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