Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/microsoft/agent-governance-toolkit/llms.txt

Use this file to discover all available pages before exploring further.

Every autonomous agent that calls tools, browses the web, or delegates to sub-agents needs a cryptographic identity. Without it, you cannot answer the incident-response question: “Which agent did this?” In a multi-agent system where five agents share a single API key, “an agent did it” is not accountability. AgentIdentity gives every agent a unique did:mesh: decentralised identifier backed by an Ed25519 key pair. Credentials are signed with the private key and can be verified by any peer with only the public key. Delegation chains enforce scope narrowing — a child agent’s capabilities can only be a strict subset of its parent’s, and the chain depth is bounded to prevent Sybil attacks.

Import

from agentmesh.identity.agent_id import AgentIdentity, AgentDID, IdentityRegistry
from agentmesh.trust.levels import trust_level_for_score

AgentDID

AgentDID represents a decentralised identifier in the did:mesh: method.
# Generate a new DID (128 bits of randomness)
did = AgentDID.generate(name="research-agent", org="acme")
print(str(did))   # "did:mesh:a3f8c2d1e4b7..."

# Parse a DID string
did = AgentDID.from_string("did:mesh:a3f8c2d1e4b7...")
print(did.unique_id)   # "a3f8c2d1e4b7..."
print(did.method)      # "mesh"
method
str
default:"mesh"
Always "mesh" for AgentMesh DIDs.
unique_id
str
128-bit (32 hex character) cryptographically random unique identifier. The previous 8-byte construction was replaced with 128 bits to prevent brute-force guessing.

AgentIdentity Fields

AgentIdentity is a Pydantic BaseModel with the following public fields.
did
AgentDID
required
The agent’s decentralised identifier.
name
str
required
Human-readable agent name. Must not be empty.
description
str | None
default:"None"
Optional free-text description of the agent’s purpose.
public_key
str
required
Base64-encoded Ed25519 public key (32 bytes raw, ~44 characters base64).
verification_key_id
str
required
Key identifier in the format key-{sha256_prefix}. Referenced in the DID document’s verificationMethod array.
sponsor_email
str
required
Human sponsor email address. Every agent must be accountable to a human. Must contain @.
sponsor_verified
bool
default:"False"
Whether the sponsor’s identity has been verified by the AgentMesh CA.
organization
str | None
default:"None"
Optional organization name.
organization_id
str | None
default:"None"
Optional organization identifier.
capabilities
list[str]
default:"[]"
List of capability strings this agent is authorised to exercise (e.g. "read:data", "write:crm", "*" for wildcard). Delegation can only narrow this list, never expand it.
created_at
datetime
UTC timestamp when the identity was created.
updated_at
datetime
UTC timestamp of the last status change (revocation, suspension, or reactivation).
expires_at
datetime | None
default:"None"
Optional identity expiration time. is_active() returns False after this time.
status
str
default:"active"
Identity lifecycle status: "active", "suspended", or "revoked".
revocation_reason
str | None
default:"None"
Reason for revocation or suspension, when applicable.
parent_did
str | None
default:"None"
DID string of the parent agent, when this identity was created via delegate(). Must match did:mesh: format.
delegation_depth
int
default:"0"
Depth in the delegation chain (0 = root agent). Must be ≥ 0. The class constant MAX_DELEGATION_DEPTH = 10 is the hard ceiling.
max_initial_trust_score
int | None
default:"None"
Lineage-bound trust cap: the child’s initial trust score cannot exceed this value (Invariant 6 — Sybil resistance). Set by the parent during delegate().

Methods

AgentIdentity.create() — Factory

@classmethod
def create(
    cls,
    name: str,
    sponsor: str,
    capabilities: list[str] | None = None,
    organization: str | None = None,
    description: str | None = None,
) -> AgentIdentity
The primary factory method for creating governed agents. Generates a fresh Ed25519 key pair, derives a did:mesh: DID, and returns a fully initialized identity. The private key is stored in memory on the returned object and never serialized.
name
str
required
Human-readable agent name. Must not be empty.
sponsor
str
required
Sponsor email address (accountability contact). Must contain @.
capabilities
list[str] | None
default:"None"
Initial capability list. None → empty list (no capabilities).
organization
str | None
default:"None"
Optional organization name.
description
str | None
default:"None"
Optional description.
from agentmesh.identity.agent_id import AgentIdentity

identity = AgentIdentity.create(
    name="research-agent",
    sponsor="alice@example.com",
    capabilities=["read:data", "web_search"],
    organization="Acme Corp",
    description="Summarises research papers",
)

print(str(identity.did))        # "did:mesh:a3f8c2..."
print(identity.public_key)      # "base64-encoded Ed25519 public key"
print(identity.is_active())     # True

sign() — Sign data with private key

def sign(self, data: bytes) -> str
Signs data with the agent’s Ed25519 private key. Returns the signature as a base64-encoded string.
data
bytes
required
Raw bytes to sign.
Raises ValueError if the private key is not available (e.g., for identities loaded from a serialized form without the private key).
message = b"authorize:delete:users"
signature = identity.sign(message)
print(signature)  # "base64-encoded Ed25519 signature"

verify_signature() — Verify a signature

def verify_signature(self, data: bytes, signature: str) -> bool
Verifies signature against data using the agent’s Ed25519 public key. Returns True if valid, False otherwise. Verification failures are logged at DEBUG level only — using WARNING would enable log flooding by adversarial peers.
data
bytes
required
The original bytes that were signed.
signature
str
required
Base64-encoded Ed25519 signature.
# Verify a credential from a remote peer
is_valid = remote_identity.verify_signature(
    data=b"authorize:delete:users",
    signature=received_signature,
)
if not is_valid:
    raise ValueError("Signature verification failed — rejecting request")

delegate() — Create a child agent

def delegate(
    self,
    name: str,
    capabilities: list[str],
    description: str | None = None,
    max_initial_trust_score: int | None = None,
) -> AgentIdentity
Creates a child AgentIdentity with narrowed capabilities. Enforces two security invariants:
  • V01 — Maximum delegation depth (MAX_DELEGATION_DEPTH = 10). Prevents unbounded chain growth.
  • V02 — Wildcard capability "*" cannot be delegated. Capabilities must be explicitly listed.
  • Child capabilities must be a subset of the parent’s capabilities.
name
str
required
Name for the child agent.
capabilities
list[str]
required
Capabilities to delegate. Each must appear in the parent’s capabilities list. Cannot include "*".
description
str | None
default:"None"
Optional description for the child agent.
max_initial_trust_score
int | None
default:"None"
Upper bound on the child’s initial trust score (Sybil resistance). Typically set to the parent’s current trust score.
Raises ValueError if capabilities are not a subset of the parent’s, the chain depth exceeds MAX_DELEGATION_DEPTH, or a wildcard is present in capabilities.
parent = AgentIdentity.create(
    name="coordinator-agent",
    sponsor="alice@example.com",
    capabilities=["read:data", "write:reports", "web_search"],
)

# Delegate a subset of capabilities to a child
child = parent.delegate(
    name="report-writer",
    capabilities=["read:data", "write:reports"],
    description="Writes monthly reports",
    max_initial_trust_score=500,
)

print(child.parent_did)         # "did:mesh:..."  (parent's DID)
print(child.delegation_depth)   # 1
print(child.capabilities)       # ["read:data", "write:reports"]

revoke() / suspend() / reactivate()

identity.revoke(reason="Compromised credentials")
identity.suspend(reason="Under security review")
identity.reactivate()                               # fails if status == "revoked"
identity.reactivate(override_reason=True)           # required for security suspensions
revoke() sets status = "revoked" (permanent). suspend() sets status = "suspended" (temporary). reactivate() raises ValueError if called on a revoked identity, or if the identity was suspended for security reasons without override_reason=True.

is_active() — Liveness check

def is_active(self) -> bool
Returns True only if status == "active" and the identity has not passed expires_at.

has_capability() — Capability check

def has_capability(self, capability: str) -> bool
Returns True if capability appears in capabilities, or if a wildcard "*" is present, or if a prefix-wildcard matches (e.g. "read:*" matches "read:data").
identity.capabilities = ["read:*", "write:reports"]

identity.has_capability("read:data")     # True  (matched by "read:*")
identity.has_capability("read:logs")     # True  (matched by "read:*")
identity.has_capability("write:reports") # True
identity.has_capability("delete:users")  # False

verify_delegation_chain() — Chain validation

@staticmethod
def verify_delegation_chain(
    identity: AgentIdentity,
    registry: IdentityRegistry | None = None,
    _visited: set[str] | None = None,
) -> bool
Walks the parent_did chain, checking at each level that:
  1. The parent exists in registry (if supplied).
  2. The child’s capabilities are a subset of the parent’s.
  3. Delegation depth is consistent.
  4. No circular references exist.
Returns True when the chain is valid. When registry is None, only the leaf identity’s structural consistency is validated.
registry = IdentityRegistry()
registry.register(parent)
registry.register(child)

valid = AgentIdentity.verify_delegation_chain(child, registry=registry)
assert valid  # True

to_did_document() — W3C DID Document export

def to_did_document(self) -> dict
Returns a W3C-format DID Document suitable for publishing at a .well-known/did.json endpoint.
doc = identity.to_did_document()
# {
#   "@context": ["https://www.w3.org/ns/did/v1"],
#   "id": "did:mesh:a3f8c2...",
#   "verificationMethod": [{
#     "id": "did:mesh:a3f8c2...#key-abc123",
#     "type": "Ed25519VerificationKey2020",
#     "controller": "did:mesh:a3f8c2...",
#     "publicKeyBase64": "..."
#   }],
#   "authentication": ["did:mesh:a3f8c2...#key-abc123"],
# }

JWK / JWKS Export and Import

# Export as JWK
jwk = identity.to_jwk()                          # public key only
jwk_with_private = identity.to_jwk(include_private=True)

# Export as JWK Set
jwks = identity.to_jwks()

# Import from JWK
restored = AgentIdentity.from_jwk(jwk_with_private)

# Import from JWK Set
restored = AgentIdentity.from_jwks(jwks, kid="key-abc123")

IdentityRegistry

IdentityRegistry is an in-memory store for AgentIdentity objects. In production it would be backed by a database and the AgentMesh CA; the in-memory version is suitable for testing and single-process deployments.
from agentmesh.identity.agent_id import IdentityRegistry

registry = IdentityRegistry()
registry.register(identity)

# Look up by DID
agent = registry.get("did:mesh:a3f8c2...")
agent = registry.get(identity.did)  # also accepts AgentDID

# Check trust
registry.is_trusted("did:mesh:a3f8c2...")   # True for active identities

# Revoke (cascades to child agents)
registry.revoke("did:mesh:a3f8c2...", reason="Policy violation")

# List
active = registry.list_active()
by_sponsor = registry.get_by_sponsor("alice@example.com")
require_attestation
bool
default:"False"
When True, register() rejects identities that lack a verified attestation. Used in production environments where the CA must sign off on every registration.

Trust Tiers

Trust scores run from 0 to 1000. The trust_level_for_score() helper converts a numeric score to a canonical label.
from agentmesh.trust.levels import trust_level_for_score

trust_level_for_score(950)  # "verified_partner"
trust_level_for_score(800)  # "trusted"
trust_level_for_score(600)  # "standard"
trust_level_for_score(400)  # "probationary"
trust_level_for_score(200)  # "untrusted"
Score RangeLabelMeaning
900–1000verified_partnerHighest tier — fully attested, long operational history
700–899trustedSolid track record, no violations
500–699standardNew or neutral agents (default starting score)
300–499probationaryRecent violations or new agent under observation
0–299untrustedHigh risk — blocked from sensitive resources
The thresholds are defined in agentmesh.constants:
from agentmesh.constants import (
    TRUST_SCORE_DEFAULT,          # 500
    TIER_VERIFIED_PARTNER_THRESHOLD,  # 900
    TIER_TRUSTED_THRESHOLD,           # 700
    TIER_STANDARD_THRESHOLD,          # 500
    TIER_PROBATIONARY_THRESHOLD,      # 300
    TRUST_REVOCATION_THRESHOLD,       # 300
)

Complete Example: Identity Creation and Delegation Chain

from agentmesh.identity.agent_id import AgentIdentity, IdentityRegistry
from agentmesh.trust.levels import trust_level_for_score

# 1. Create the root orchestrator identity
orchestrator = AgentIdentity.create(
    name="orchestrator",
    sponsor="alice@acme.com",
    capabilities=["read:*", "write:reports", "web_search", "crm:read"],
    organization="Acme Corp",
)
print(f"Orchestrator DID: {orchestrator.did}")
print(f"Active: {orchestrator.is_active()}")

# 2. Delegate a sub-agent with narrowed capabilities
researcher = orchestrator.delegate(
    name="researcher",
    capabilities=["read:papers", "web_search"],
    description="Searches and summarises research papers",
    max_initial_trust_score=500,
)
print(f"Researcher DID: {researcher.did}")
print(f"Delegation depth: {researcher.delegation_depth}")  # 1

# 3. Register in the trust registry
registry = IdentityRegistry()
registry.register(orchestrator)
registry.register(researcher)

# 4. Verify the delegation chain
valid = AgentIdentity.verify_delegation_chain(researcher, registry=registry)
print(f"Chain valid: {valid}")  # True

# 5. Sign and verify a credential
credential = b"authorize:web_search:2025-01-15"
signature = orchestrator.sign(credential)
verified = orchestrator.verify_signature(credential, signature)
print(f"Signature valid: {verified}")  # True

# 6. Check capability access
print(researcher.has_capability("web_search"))     # True
print(researcher.has_capability("write:reports"))  # False (not delegated)

# 7. Trust tier lookup
score = 650
print(f"Trust level: {trust_level_for_score(score)}")  # "standard"

See Also

Build docs developers (and LLMs) love