API Reference

Python

pip install qhermes-kernel qhermes-a2a

Two layers per package. qhermes.kernel and qhermes.a2a are the high-level APIs for application code, with named arguments, NamedTuple types, and automatic nonce management. qhermes_kernel and qhermes_a2a are the low-level extension modules with direct bindings to the Rust primitives.


qhermes.kernel

make_identity(master, deployment, context)

Derives an ML-DSA-65 identity from a 32-byte master seed via HKDF-SHA3-512. Different deployment or context values yield independent key material from the same master. Returns an IdentityIsland.

identity = make_identity(
    master=seed_32,
    deployment=b"prod",
    context=b"orchestrator",
)

derive_public_key(identity)

Returns the 1952-byte ML-DSA-65 public key for an identity.

root_pk = derive_public_key(identity)

make_policy(resources, actions, *, permissions, not_before, not_after, hours_valid, minutes_valid)

Builds a Policy. The standard form accepts two lists expanded as a cartesian product; every action is granted on every resource. For asymmetric permissions, supply explicit (resource, verb) pairs via permissions. The two forms are mutually exclusive. All time parameters are keyword-only.

# Standard form — cartesian product
policy = make_policy(
    resources=[b"/reports", b"/reports/archive"],
    actions=[b"GET"],
    hours_valid=1,
)

# Asymmetric form — different verbs on different resources
policy = make_policy(
    permissions=[
        (b"/source",    b"GET"),
        (b"/artifacts", b"PUT"),
    ],
    hours_valid=2,
)

issue_credential(identity, child_pk, policy, depth, role)

Issues a signed Credential. depth is the position in the chain: root issues at 1, each subsequent hop increments by one. role is "node" (may delegate further) or "leaf" (may not).

cred = issue_credential(
    identity=root_identity,
    child_pk=agent_pk,
    policy=policy,
    depth=1,
    role="node",
)

build_chain(chain)

Encodes a sequence of Credential objects to wire bytes.

wire = build_chain((root_cred, agent_cred))

verify_chain(root_pk, wire, now)

Verifies a wire-encoded chain against root_pk. Checks signatures, depth sequence, scope containment, and time bounds. Returns the credential count. Raises on any failure. now defaults to current Unix time.

decode_chain(wire)

Deserializes wire bytes into a tuple of Credential objects without verifying signatures. For inspection only. Call verify_chain before trusting any chain from an external source.

explain_credential(cred)

Returns a human-readable string summary of a credential.

parse_payload(cred)

Deserializes a credential payload into a dict with keys: child_pk, role, depth, perms, not_before, not_after.

credential_valid_at(cred, ts)

Returns True if the credential's time caveats permit ts. Fail-closed on invalid payload.


qhermes.a2a

derive_endpoint(dsa_seed)

Derives a KemEndpoint (ML-KEM-768 keypair) from a 32-byte seed. Passing the same seed used for a kernel identity binds both under the same root secret with domain separation.

endpoint = derive_endpoint(dsa_seed=seed_32)
ek = endpoint.encapsulation_key  # publish in Agent Card or discovery metadata

kem_offer(peer_ek, context)

Initiator side of the KEM handshake. Returns (offer_blob, Session). Embed offer_blob in message metadata via pack_metadata. context binds the session key to a domain; supply a stable task or session identifier.

kem_accept(endpoint, offer, context)

Responder side. Returns a Session. context must match the initiator's value exactly.

seal(session, plaintext, aad)

Encrypts with ChaCha20-Poly1305. Returns (blob, next_session). The previous session must not be reused. Pass next_session to subsequent calls.

open_blob(session, blob, aad)

Decrypts a blob produced by seal. Raises on authentication failure.

seal_auth(credentials)

Accepts a Sequence[Credential] in chain order (root first). Returns wire bytes for embedding in message metadata or any other field.

wire = seal_auth([root_cred, agent_cred])

verify_auth(root_pk, wire, now)

Verifies the full delegation chain. Returns the credential count on success. Raises on failure. now defaults to current Unix time.

n = verify_auth(root_pk=root_pk, wire=wire)

sign_agent_card(master, deployment, context, card_bytes)

Signs canonical Agent Card bytes with ML-DSA-65. card_bytes must be JCS-canonicalized (RFC 8785): keys sorted, no extra whitespace, signature field omitted. Returns a SIG_SIZE-byte signature.

verify_agent_card(root_pk, card_bytes, sig)

Verifies an Agent Card signature. Raises ValueError on failure.

agent_card_security_extension(root_pk, endpoint)

Returns the QHermes extension dict for embedding in discovery metadata. Contains signingKey (ML-DSA-65 public key) and encapsulationKey (ML-KEM-768), both base64url-encoded.

ext  = agent_card_security_extension(root_pk, endpoint)
card = {"name": "my-agent", "extensions": {"https://qhermes.dev/a2a/v1": ext}}

extract_agent_card_ek(card)

Extracts (root_pk, encapsulation_key) from a card dict containing the QHermes extension. Raises KeyError if the extension is absent.

pack_metadata(auth_wire, offer_blob, extra) / unpack_metadata(metadata)

Helpers for embedding and extracting QHermes fields in A2A message.metadata dicts. Fields are base64url-encoded under x-qhermes-auth and x-qhermes-offer.


Types

Credential

  • issuer_pk: bytes: 1952-byte ML-DSA-65 public key
  • signature: bytes: 3309-byte ML-DSA-65 signature
  • payload: bytes: signed payload bytes

Policy

  • scope_tlv: bytes: TLV-encoded permissions
  • caveats: bytes: time caveat records

KemEndpoint

  • encapsulation_key: bytes: publish in discovery metadata
  • dk_seed: bytes: keep secret

Session

  • key: ChaCha20-Poly1305 session key
  • counter: int: monotonic nonce counter, starts at 0

Constants

  • PK_SIZE = 1952: ML-DSA-65 public key, bytes
  • SIG_SIZE = 3309: ML-DSA-65 signature, bytes
  • EK_SIZE = 1184: ML-KEM-768 encapsulation key, bytes
  • KEM_OFFER_SIZE = 1088: KEM offer blob, bytes
  • NONCE_SIZE = 12: ChaCha20-Poly1305 nonce, bytes
  • TAG_SIZE = 16: ChaCha20-Poly1305 authentication tag, bytes

Next: Rust API reference