Observed since 20 Oct, 22:46 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
The open protocol for AI agent identity, trust, and notarization.
The open protocol for AI agent identity, trust, and notarization.
Peer-to-peer (everything below unless marked otherwise) — identities are
did:trust:agent:, receipts live with whoever holds them, and trust is a score
you compute from the receipts you have received. Nothing central to trust or pay
for. Run your own registry with pip install agentoath-registry if you want one.
Hosted Registry (agentoath.hosted) — a client for
registry.agentoath.com, a notarisation service
where you publish signed receipts about your own actions and any third party can
verify them without trusting the platform. Identities are did:agentoath: and
the wire format is different.
They are separate protocols. A receipt built for one is rejected by the other, by design. The same Ed25519 keypair can hold an identity in both.
The peer-to-peer layer has been in use since 0.2 and follows semantic versioning from 1.0 on: no breaking change without a major bump.
agentoath.hosted is provisional. The wire format it speaks is fixed —
it is pinned to the Registry's published spec at GET /api/v1/registry, and
the cross-language canonical fixtures in tests/ fail if either side drifts.
What may still move is the shape of this client: argument names, helper
functions, where things live. That is a deliberate exception to the guarantee
above, stated here rather than implied by the version number, because the
module is new and has had one real integration so far.
If you need it frozen, pin an exact version. If you build on it, the stable thing to build on is the wire format, not this client's signatures.
pip install agentoath
from agentoath import TrustAgent, TrustReceipt
# Create a new Agent identity
agent = TrustAgent.create(
name="My AI Assistant",
capabilities=["chat", "search"],
platform="custom",
)
# Save identity to disk
agent.save("my_agent.json")
# Load identity from disk
agent = TrustAgent.load("my_agent.json")
# Sign a trust receipt after an interaction
receipt = agent.sign_receipt(
to_agent="did:trust:agent:bbb...",
action="collaboration",
rating=9,
description="Built a great report",
)
# Verify a receipt
is_valid = receipt.verify_from_signature(other_agent.public_key)
# Calculate trust score
score = agent.calculate_trust_score(receipts)
print(f"Trust Score: {score.overall}")
The SDK includes a command-line tool:
# Generate a new Agent keypair
agentoath init --name "My Agent" --capabilities "chat,search"
# Display Agent info
agentoath info
# Sign a receipt
agentoath sign-receipt --to did:trust:agent:bbb... --rating 9
# Verify a receipt
agentoath verify-receipt receipt.json --from-key-file agent_key.json
# Compute trust score
agentoath trust-score --receipts receipts.json --target-did did:trust:agent:bbb...
Connect to a registry you run yourself (pip install agentoath-registry).
For the hosted Registry at registry.agentoath.com see Hosted Registry below —
it is a different protocol and this client cannot talk to it.
from agentoath import TrustAgent
from agentoath.registry_client import RegistryClient
agent = TrustAgent.create(name="My Agent")
client = RegistryClient("http://localhost:8500") # your own server
# Register with the Registry
resp = client.register(agent)
print(resp.data["identity_certificate"])
# Publish a receipt
receipt = agent.sign_receipt(to_agent="did:trust:agent:bbb...", rating=9)
client.publish_receipt(receipt)
# Query trust score
score = client.query_trust_score("did:trust:agent:bbb...")
print(score.data)
The client supports offline mode -- when the Registry is unreachable, it returns graceful fallback responses instead of crashing.
A client for registry.agentoath.com. Disabled by default — it sends nothing until you turn it on.
from agentoath.hosted import (
AgentOathIdentity, AgentOathClientConfig, AgentOathRegistryClient,
build_signed_receipt, verify_receipt_locally, sha256_json,
)
identity = AgentOathIdentity.generate()
print(identity.did) # did:agentoath:<sha256 of the raw public key>
print(identity.private_key) # keep this out of version control
client = AgentOathRegistryClient(AgentOathClientConfig(
base_url="https://registry.agentoath.com",
api_key="...",
enabled=True,
))
client.register_identity(identity, name="my-service")
receipt = build_signed_receipt(
identity,
receipt_id="verdict-1234",
action="compliance.verdict.red",
metadata={"schema": "v1", "content_digest": sha256_json(text)},
)
client.publish_receipt(receipt)
Three rules the Registry enforces. build_signed_receipt checks all three
locally, so you get a Python exception at the call site instead of an HTTP 422
somewhere else:
rating must be a JSON integer 0–10. Python prints 7.0 where
JavaScript prints 7, so a float makes the signature unverifiable."".metadata must always be present, and filled in before signing.Receipts are public and permanent, so metadata keys are checked against a
28-key blocklist — matched per underscore-separated segment, which means
prompt_hash and user_email are rejected. Use content_digest, actor_ref
and similar instead. Full guide: https://agentoath.com/integrate.
A signed receipt proves what. It does not prove when: the timestamp field is
whatever the signer put there, so anyone can sign a receipt dated three years
ago. And it does not prove the receipt still exists — it is a row in a database.
pip install "agentoath[timestamps]"
from agentoath.timestamps import stamp_receipt, verify, upgrade
proof = stamp_receipt(receipt) # only the hash is sent — never the receipt
report = verify(proof)
report["any_valid"] # a timestamp authority signed this hash and its own clock
report["bitcoin_confirmed"] # ...and it is committed into the Bitcoin blockchain
proof = upgrade(proof) # hours later: pending -> confirmed
Two mechanisms, because they fail differently:
Once you hold an OpenTimestamps proof and your own copy of the receipt, you can prove what happened and when even if every receipt in the Registry is deleted. It does not make the database append-only; it makes the database not matter.
stamp never raises. A timestamp authority being down must not break the thing
that was only trying to record a receipt — whatever failed lands in
proof["errors"] where you can see it.
There is no document receipt type. A document is an ordinary receipt with one metadata convention, so signing, the canonical form shared with JavaScript, the privacy blocklist and the Registry's validation all apply unchanged.
from agentoath.documents import build_document_receipt
receipt = build_document_receipt(
identity, "scans/book-0417.pdf",
refs={"source_ref": "isbn:9780000000001", "acquired_ref": "po-2026-0817"},
)
receipt["receipt_id"] # doc-<sha256 of the file> — attesting it twice is idempotent
The file never leaves your machine; only its sha256 goes into the receipt. A
digest proves "this is the same file" to whoever has the file and proves nothing
to anyone who does not — which is what you want when the thing you are attesting
is a scan you may not redistribute. Files are streamed, so a multi-gigabyte scan
does not have to fit in memory. Reference fields must end in _ref and stay
under 128 characters: receipts are public and permanent, and a pasted sentence
is not recoverable.
| Method | Description |
|---|---|
TrustAgent.create(name, capabilities, platform) | Create a new Agent with a fresh keypair |
TrustAgent.load(path, password) | Load an Agent from a key file |
agent.save(path, password) | Save the Agent's identity to disk |
agent.sign_receipt(to_agent, action, rating) | Sign a Trust Receipt |
agent.counter_sign_receipt(receipt) | Add a counter-signature |
agent.verify_receipt(receipt, from_public_key) | Verify a receipt's signature |
agent.calculate_trust_score(receipts) | Compute trust score |
agent.did | The Agent's DID |
agent.public_key_formatted | Public key as ed25519:{base64} |
| Method | Description |
|---|---|
TrustReceipt.create(from_agent_did, from_private_key, to_agent_did) | Create and sign a receipt |
TrustReceipt.from_dict(data) | Create from a dictionary |
receipt.counter_sign(to_private_key) | Add counter-signature |
receipt.verify_from_signature(public_key) | Verify initiator's signature |
receipt.verify_counter_signature(public_key) | Verify counter-signature |
TrustReceipt.verify(receipt_dict, from_public_key) | Static verification |
| Method | Description |
|---|---|
client.register(agent) | Register an Agent |
client.get_agent(did) | Look up an Agent by DID |
client.get_agent_card(did) | Get Agent's public profile |
client.search_agents(name, platform, capability) | Search for Agents |
client.publish_receipt(receipt) | Publish a signed receipt |
client.get_receipts(agent_did) | Get receipts for an Agent |
client.verify_receipt(receipt, from_public_key) | Online verification |
client.query_trust_score(agent_did) | Query trust score |
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run with coverage
pytest --cov=agentoath --cov-report=term-missing
Apache 2.0
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 2.0.0 | 21 Aug 2026 | 8 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 22:46 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:eb969fd3073f77035e3ca5ac861f75e4b9539656c3d9638e793ae4c7f67785f3