Multi-agent workflows are now standard: Agent A researches, Agent B writes, Agent C reviews. Your HMAC audit chain proves those events were not modified. But it cannot prove who sent what to whom, whether the handoff was acknowledged, or if the task was swapped in transit. air-trust v0.6.0 solves this with Ed25519 signed handoff records.
handoff_request (Agent A signs), handoff_ack (Agent B signs), and handoff_result (Agent B signs).pip install air-trust[handoffs]==0.6.0. Fully backward compatible with v0.5.0 chains.HMAC-SHA256 uses a shared secret, which means any party with the key can create a valid signature. In a multi-agent system where Agent A delegates work to Agent B, the HMAC chain proves each record was not modified after it was written, but it cannot prove which specific agent wrote it. Any agent with access to the shared key could have authored any record in the chain.
Imagine Agent A (a researcher) hands off findings to Agent B (a report writer). Agent A calls handoff_request(), publishing a record that says: "I am sending this research package to Agent B." The record is HMAC-signed and chained. Later, an auditor asks: "Did Agent A actually send this? Could someone else have forged it?" Under the v0.5.0 chain, the answer is: probably. HMAC proves the record was not tampered with after creation, but it does not prove authorship.
This gap is critical for EU AI Act Article 12 (record-keeping for high-risk AI systems). When multiple agents operate the same system, regulators need to know which agent was responsible for each decision, which agent handed off to which, and whether all parties agreed on what was being handed off. The NIST RFI on AI Agent Security (Docket NIST-2025-0035) names agent identity continuity as an open problem for exactly this reason.
The core problem: HMAC proves integrity. It does not prove identity. For cross-agent handoffs, you need asymmetric signatures where only the sender can sign and anyone can verify.
Ed25519 is an elliptic curve signature scheme where each agent generates a keypair: a private key for signing and a public key for verification. Unlike HMAC's shared secret, only the agent holding the private key can produce a valid signature, while anyone with the public key can verify who signed it. air-trust v0.6.0 layers Ed25519 signatures on top of the existing HMAC chain without replacing it.
HMAC-SHA256 remains unchanged. Every record, including the new handoff records, is still chained via HMAC. If someone modifies a record after it is written, the hash breaks. The chain integrity check is identical to v0.5.0 and earlier. Nothing about the existing model changes.
Ed25519 is added for handoff identity. When an agent writes a handoff record, it includes five new fields:
The HMAC still covers all of these new fields, so they are tamper-evident just like everything else in the chain. You get two layers: HMAC for integrity and Ed25519 for identity.
A complete handoff consists of three records, each signed by the responsible agent. Together they form a cryptographic proof that the handoff happened, both sides agreed on the payload, and the outcome is attributed to the correct agent. If any record is missing or the signatures do not verify, the chain flags it.
Agent A publishes this record to declare it is sending a task to Agent B. The record includes a type of "handoff_request", an interaction_id (UUID linking all three records), a counterparty_id (Agent B's fingerprint), a payload_hash (SHA-256 of the task data), a nonce, Agent A's public_key, and an Ed25519 signature over those fields.
Agent B receives the request, verifies the payload hash matches what it actually received, then publishes an acknowledgment. It uses the same interaction_id, includes Agent A's fingerprint as the counterparty_id, repeats the payload_hash, and signs with Agent B's private key. If the payload hash from the request does not match what Agent B received, the ack is not published and a mismatch alert is logged. This proves the payload was not swapped in transit.
After processing, Agent B publishes its output. The record uses the same interaction_id, includes a result_hash (SHA-256 of Agent B's output), and is signed by Agent B. All three records link via interaction_id, and the verifier confirms signatures, hash matches, and counterparty consistency across the triplet.
The verification process runs three passes over the audit chain. Pass 1 checks integrity (unchanged from v0.5.0): replay the HMAC chain from genesis and confirm no hashes are broken. Pass 2 checks completeness (from v0.5.0): look for gaps in session sequence numbers. Pass 3 is new: handoff identity verification across every request/ack/result triplet.
For each handoff triplet, the verifier confirms six things: the Ed25519 signature on each record is valid, all three records are present, the interaction_id matches across all three, the counterparty_id in the request matches the public key fingerprint in the ack, the payload_hash in request matches the ack, and each nonce is unique.
The verifier output is structured JSON:
{
"integrity": {
"valid": true,
"records": 52
},
"completeness": {
"sessions_checked": 3,
"sessions_complete": 3
},
"handoffs": {
"handoffs_checked": 2,
"handoffs_valid": 2,
"issues": []
}
}
When issues are found, the severity levels are clear:
| Issue | Severity | What it means |
|---|---|---|
| Signature invalid | FAIL | Ed25519 signature does not verify. Identity is forged. |
| Missing handoff_ack | WARN | Request sent but no acknowledgment. Did Agent B receive it? |
| Payload mismatch | WARN | Request and ack disagree on payload_hash. Payload was swapped. |
| Counterparty mismatch | WARN | Request says Agent B, but ack is from Agent C. Routing error or forgery. |
| Duplicate nonce | WARN | Same nonce used twice by one agent. Possible replay attack. |
| Missing handoff_result | INFO | Request and ack present but no result yet. Handoff in progress. |
Install air-trust with handoff support using pip install air-trust[handoffs]==0.6.0. This brings in PyCA/cryptography for Ed25519. Then generate a keypair for each agent (one-time setup) and use the handoff API in your agent code. The full protocol runs in under 20 lines of Python.
from air_trust.events import Event, AgentIdentity
from air_trust.chain import AuditChain
from air_trust.keys import generate_keypair, compute_payload_hash, generate_nonce
# Create identities and generate keypairs
agent_a = AgentIdentity(agent_name="researcher", owner="[email protected]")
agent_b = AgentIdentity(agent_name="writer", owner="[email protected]")
generate_keypair(agent_a.fingerprint)
generate_keypair(agent_b.fingerprint)
chain = AuditChain()
iid = "handoff-001-2026-04-10"
task_data = "research EU AI Act trends in 2026"
task_hash = compute_payload_hash(task_data)
# Agent A sends handoff request
chain.write(Event(
type="handoff_request",
framework="raw_python",
identity=agent_a,
interaction_id=iid,
counterparty_id=agent_b.fingerprint,
payload_hash=task_hash,
nonce=generate_nonce(),
))
# Agent B receives and verifies payload matches
received_hash = compute_payload_hash("research EU AI Act trends in 2026")
assert received_hash == task_hash, "Payload mismatch!"
# Agent B acknowledges
chain.write(Event(
type="handoff_ack",
framework="raw_python",
identity=agent_b,
interaction_id=iid,
counterparty_id=agent_a.fingerprint,
payload_hash=task_hash,
nonce=generate_nonce(),
))
# Agent B does the work and publishes result
result_data = "EU AI Act Articles 9-15 now require..."
result_hash = compute_payload_hash(result_data)
chain.write(Event(
type="handoff_result",
framework="raw_python",
identity=agent_b,
interaction_id=iid,
counterparty_id=agent_a.fingerprint,
result_hash=result_hash,
nonce=generate_nonce(),
))
# Verify the chain
result = air_trust.verify()
print(result["handoffs"]["handoffs_valid"]) # 1
Or use the high-level handoff API for cleaner code:
from air_trust.handoffs import handoff_request, handoff_ack, handoff_result
# Agent A
handoff_request(
interaction_id="task-123",
counterparty=agent_b,
payload=research_findings
)
# Agent B
handoff_ack(interaction_id="task-123", payload=research_findings)
# ... do work ...
handoff_result(interaction_id="task-123", result=report)
# Human-readable output
python3 -m air_trust verify
# JSON output for CI/CD
python3 -m air_trust verify --json
# Filter to handoff records only
python3 -m air_trust verify --handoffs-only
Signed handoffs prove identity for handoffs that flow through the audit chain, but they have five explicit limits documented in the SPEC.md v1.2 threat model. Being transparent about what a security primitive does not cover is as important as explaining what it does.
payload_hash proves the payload was not tampered with. It does not prove the payload is correct, useful, or safe. Hash matching is necessary but not sufficient for trust.For handoffs that flow through the chain, v0.6.0 can cryptographically prove which agent sent the request, which agent acknowledged it, whether both sides agreed on the payload, and which agent published the result. It cannot prove the keys were never compromised, the agents were not colluding, or that the payload itself is correct.
Yes. v0.6.0 is fully backward compatible with v0.5.0 and earlier chains. Handoff records are optional and only appear when agents explicitly use the handoff API. Ordinary event records do not include Ed25519 fields. The HMAC chain is unchanged, session completeness checks still work on v1.1 records, and mixed chains with integrity, completeness, and signed handoffs all verify together. There are no breaking changes to the Event model.
The only new dependency is the cryptography library, which is optional. Install the base package with pip install air-trust (no Ed25519) or install with handoff support using pip install air-trust[handoffs].
v1.2 is unilateral signing: Agent A signs "I am sending this" and Agent B signs "I received it." Future work (v1.3) would add bilateral co-attestation: both agents sign a single joint handoff record, proving they both witnessed the exchange simultaneously. This closes the collusion gap but requires both agents to be online at the moment of handoff.
We are not building co-attestation yet. Real demand drives prioritization. If multi-party signatures are something you need, open a discussion on GitHub - that signal influences the roadmap.
HMAC uses a shared secret, so any party with the key can create a valid signature. In multi-agent systems, HMAC proves a record was not modified after it was written, but it cannot prove which specific agent wrote it. Ed25519 asymmetric signatures solve this because only the agent with the private key can sign, and anyone with the public key can verify who signed it.
The three record types are: handoff_request (Agent A signs to declare it is sending a task to Agent B), handoff_ack (Agent B signs to confirm receipt and that the payload hash matches), and handoff_result (Agent B signs to publish its output). Together, they form a complete cryptographic proof of the handoff lifecycle.
The handoff_request includes SHA-256(task_data). The handoff_ack includes the same hash. If the task is modified between request and acknowledgment, the hashes will not match, and verification fails. This proves the payload was not swapped in transit and that both agents agreed on what was being handed off.
No. If a private key is stolen, an attacker can forge valid signatures that are indistinguishable from legitimate ones. If two agents collude, they can forge a fake handoff exchange. Signed handoffs prove identity only if keys remain secure and agents are not collaborating. The SPEC.md v1.2 threat model documents these limits explicitly.
Yes. Handoff records are optional and only appear when agents use the handoff API. The HMAC chain is unchanged, v0.5.0 records still verify, session completeness checks still work, and mixed chains with integrity, completeness, and signed handoffs all verify together. No breaking changes to the Event model.
Add cross-agent identity proof to your multi-agent AI audit chain.
pip install air-trust[handoffs]==0.6.0
Last updated: April 17, 2026. This article is reviewed and updated to reflect the latest air-trust releases and specification changes.