Every A2A task state transition becomes a verifiable witness anchor. Build an immutable chain of custody across agent boundaries without modifying agent logic.
Who this is for: Agent platform developers, multi-agent system architects, and compliance engineers building A2A ecosystems where every delegation, state transition, and context handoff must produce independently verifiable evidence. Assumes familiarity with the Google A2A protocol v1.0.
The accountability gap: A2A reached v1.0 stable with 150+ member organizations. The protocol defines how agents discover and delegate tasks to each other. It does not define how to produce an audit trail. CSA MAESTRO identifies repudiation and diffused accountability as top threats in multi-agent systems. Gartner reports 52% of companies cannot track what data their AI agents access. SWT3 closes this gap by witnessing every task state transition as a cryptographic anchor.
The A2A protocol solves agent-to-agent communication. It does not solve agent-to-agent accountability. When Agent A delegates a financial analysis task to Agent B, and Agent B sub-delegates data retrieval to Agent C, the following questions have no answer in the protocol itself:
These are not hypothetical concerns. The CSA MAESTRO threat model identifies repudiation (an agent denying it performed an action) and diffused accountability (no single party responsible for a multi-agent outcome) as structural risks in agentic systems. The Five Eyes "Careful Adoption" guidance explicitly calls for cryptographic agent identity and continuous behavioral monitoring across agent boundaries.
SWT3 addresses this by treating each A2A task state transition as a witnessable event. The witness layer sits beneath the A2A protocol, records every transition, and produces independently verifiable anchors. No modifications to agent logic are needed. The witness adapter observes state changes through the A2A task object and mints anchors automatically.
The A2A protocol defines a task state machine with seven states. Each state transition represents a consequential moment in the agent delegation lifecycle. SWT3 witnesses each transition as an AI-A2A.1 anchor.
| State Transition | Witness Event | What Is Recorded |
|---|---|---|
submitted |
Task created and delegated to remote agent | Task ID, delegator agent ID, target agent ID, task description hash |
working |
Remote agent accepted and began processing | Acceptance timestamp, agent capabilities confirmed |
input-required |
Agent paused, requesting additional input from delegator | Input type requested, pause duration, context preserved |
completed |
Task finished successfully with result | Result hash, total duration, artifacts produced |
failed |
Task terminated with error | Error category, failure point, partial results (if any) |
canceled |
Delegator or system canceled the task | Cancellation source, reason, work completed before cancel |
rejected |
Remote agent declined the task | Rejection reason, capability mismatch details |
Three procedures cover the A2A witnessing surface. Each procedure captures different evidence through three factor fields (fa, fb, fc) that feed into the SWT3 fingerprint formula.
| Procedure | Name | Factor A | Factor B | Factor C |
|---|---|---|---|---|
AI-A2A.1 |
Task Lifecycle | Task ID and delegator agent ID | Current state (submitted, working, completed, failed, canceled, rejected, input-required) | Target agent ID and task description hash |
AI-A2A.2 |
Agent Card Discovery | Discovering agent ID | Discovered agent URL and card hash | Capabilities matched and governance coverage from card |
AI-A2A.3 |
Context Chain | Source agent ID and context hash | Destination agent ID and context size (bytes) | Context type (full, partial, filtered) and clearing level applied |
The fingerprint for each anchor is computed as SHA256("WITNESS:{tenant}:{proc}:{fa}:{fb}:{fc}:{ts_ms}").hex()[:12]. This formula is locked across all seven SDK languages.
from swt3_ai import Witness
witness = Witness(
endpoint="https://sovereign.tenova.io",
api_key="axm_live_...",
tenant_id="ACME_DEFENSE",
agent_id="orchestrator-v3",
)
# Witness a task state transition
witness.witness_task_lifecycle(
task_id="task-7f3a",
state="submitted",
target_agent="financial-analyst-agent",
description_hash="e3b0c44298fc...",
)
# Produces: AI-A2A.1 anchor with state=submitted
# Later, when the task completes
witness.witness_task_lifecycle(
task_id="task-7f3a",
state="completed",
target_agent="financial-analyst-agent",
result_hash="a9f2b8d1c4e7...",
duration_ms=1843,
)
# Witness the discovery of a remote agent's capabilities
witness.witness_agent_card_discovery(
discovered_url="https://agents.example.com/.well-known/agent.json",
card_hash="b7c9d2e4f1a8...",
capabilities_matched=3,
governance_coverage=0.94,
)
# Witness context being passed between agents
witness.witness_context_chain(
destination_agent="financial-analyst-agent",
context_hash="d4e5f6a7b8c9...",
context_size=24576,
context_type="filtered",
)
from swt3_ai.adapters.a2a import wrap_a2a
# Wrap the agent client to auto-witness every send()
witnessed_agent = wrap_a2a(my_a2a_client, witness=witness)
# All task lifecycle transitions are now witnessed automatically
result = witnessed_agent.send({"text": "Analyze Q3 revenue trends"})
# Mints AI-A2A.1 (submitted) on send, AI-A2A.1 (completed/failed) on response
import { Witness } from "@tenova/swt3-ai";
const witness = new Witness({
endpoint: "https://sovereign.tenova.io",
apiKey: "axm_live_...",
tenantId: "ACME_DEFENSE",
agentId: "orchestrator-v3",
});
// Witness a task state transition
await witness.witnessTaskLifecycle({
taskId: "task-7f3a",
state: "submitted",
targetAgent: "financial-analyst-agent",
descriptionHash: "e3b0c44298fc...",
});
// When the task completes
await witness.witnessTaskLifecycle({
taskId: "task-7f3a",
state: "completed",
targetAgent: "financial-analyst-agent",
resultHash: "a9f2b8d1c4e7...",
durationMs: 1843,
});
await witness.witnessAgentCardDiscovery({
discoveredUrl: "https://agents.example.com/.well-known/agent.json",
cardHash: "b7c9d2e4f1a8...",
capabilitiesMatched: 3,
governanceCoverage: 0.94,
});
await witness.witnessContextChain({
destinationAgent: "financial-analyst-agent",
contextHash: "d4e5f6a7b8c9...",
contextSize: 24576,
contextType: "filtered",
});
import { wrapA2A } from "@tenova/swt3-ai";
const witnessedAgent = wrapA2A(myA2AClient, { witness });
// All task lifecycle transitions witnessed automatically
const result = await witnessedAgent.send({ text: "Analyze Q3 revenue trends" });
The SWT3 MCP server exposes three tools for A2A witnessing. Any MCP client (Claude Desktop, Cursor, Windsurf, or a custom agent) can call these tools directly.
| MCP Tool | Procedure | Parameters |
|---|---|---|
witness_task_lifecycle |
AI-A2A.1 | task_id, state, target_agent, description_hash or result_hash |
witness_agent_card_discovery |
AI-A2A.2 | discovered_url, card_hash, capabilities_matched, governance_coverage |
witness_context_chain |
AI-A2A.3 | destination_agent, context_hash, context_size, context_type |
// MCP tool call example (from any MCP client)
{
"tool": "witness_task_lifecycle",
"arguments": {
"task_id": "task-7f3a",
"state": "completed",
"target_agent": "financial-analyst-agent",
"result_hash": "a9f2b8d1c4e7..."
}
}
The MCP server is installed as @tenova/swt3-mcp and runs as a stdio or streamable HTTP transport. See the MCP Connect guide for setup.
A2A task lifecycle witnessing maps to regulatory and industry frameworks across jurisdictions. The evidence produced by AI-A2A.1, AI-A2A.2, and AI-A2A.3 satisfies specific articles, controls, and recommendations.
| Framework | Requirement | SWT3 Procedure | Evidence Produced |
|---|---|---|---|
| EU AI Act | Art. 25 (deployer liability for delegated systems) | AI-A2A.1 | Complete delegation chain with state transitions |
| EU AI Act | Art. 13 (transparency of AI system operation) | AI-A2A.3 | Context chain proving data flow between agents |
| NIST AI RMF | GOVERN 1.5 (supply chain governance) | AI-A2A.2 | Agent card discovery with governance verification |
| NIST AI RMF | MAP 3.5 (third-party AI risk) | AI-A2A.1 | Task lifecycle anchors proving delegation oversight |
| Five Eyes | Accountability chain (agent attribution) | AI-A2A.1 + AI-A2A.3 | End-to-end provenance from delegation to completion |
| OWASP Agentic | Excessive Agency (agent scope control) | AI-A2A.1 | Scope recorded in task description hash per transition |
| Singapore IMDA | A.I. Verify (accountability and transparency) | AI-A2A.1 + AI-A2A.2 | Agent discovery and task lifecycle evidence |
| ISO 42001 | 6.1.2 (AI risk assessment for third-party components) | AI-A2A.2 | Governance coverage verified before delegation |
SWT3 clearing levels control what evidence survives in the witness ledger. Higher levels strip more identifying data while preserving the cryptographic proof that witnessing occurred.
| Level | Name | What Survives | What Is Stripped |
|---|---|---|---|
| 0 | Analytics | All factors, task IDs, agent IDs, context hashes, timestamps | Nothing stripped |
| 1 | Standard | Agent IDs, state transitions, duration, result hashes | Raw task descriptions, context payloads |
| 2 | Sensitive | State transitions, duration, hashed agent IDs | Plaintext agent IDs, task descriptions, context details |
| 3 | Classified | Anchor fingerprint and timestamp only | All factor values (proof of witnessing survives, details do not) |
Jurisdiction, legal basis, and purpose class (CJT fields) survive all clearing levels. This means regulatory attribution is preserved even at Level 3, where operational details are fully redacted.
When multiple agents participate in a workflow, each agent mints its own anchors. Linking these anchors into a coherent chain of custody is accomplished through the contextId field, which is shared across all agents in a single workflow.
contextId (or uses the A2A task ID) when initiating a workflowcontextIdcontextId, creating a tree structurecontextId reconstructs the full chain# Query all anchors in a delegation chain
chain = witness.query_chain(context_id="task-7f3a")
# Returns ordered list:
# 1. AI-A2A.2 - orchestrator discovered financial-analyst (t=0ms)
# 2. AI-A2A.1 - task submitted to financial-analyst (t=12ms)
# 3. AI-A2A.3 - context passed: 24KB, type=filtered (t=15ms)
# 4. AI-A2A.1 - financial-analyst state=working (t=45ms)
# 5. AI-A2A.1 - financial-analyst state=completed (t=1843ms)
# 6. AI-A2A.3 - result context returned: 8KB (t=1850ms)
Each anchor in the chain is independently verifiable. An auditor can take any single anchor, recompute its fingerprint from the recorded factors, and confirm it matches the ledger entry. The chain provides ordering and context; the anchors provide integrity.
A complete chain has an AI-A2A.1 anchor for every state transition. If an agent processes a task but does not produce anchors, the gap is visible: the chain will show submitted followed by completed with no working state in between. These gaps are findings during assessment, indicating unwrapped agents in the delegation path.
Records every state transition in an A2A task. Each transition produces an anchor capturing the task ID, current state, delegating agent, and target agent. Terminal states (completed, failed, canceled, rejected) include outcome-specific data such as result hashes or error categories.
Query AI-A2A.1 anchors by task ID. The sequence should show submitted, working, and exactly one terminal state. Missing intermediate states indicate unwrapped agents. Multiple terminal states for the same task ID indicate a state machine violation.
Records the moment one agent discovers another agent's capabilities through its Agent Card. Captures the card URL, a hash of the card contents, the number of capabilities matched, and the governance coverage advertised in the card's swt3 extension.
Verify that AI-A2A.2 anchors precede AI-A2A.1 (submitted) anchors in the same context. A delegation without a preceding discovery event means the agent bypassed capability verification. Check governance_coverage values against your organization's minimum threshold.
Records data flowing between agent boundaries. Each anchor captures the source agent, destination agent, a hash of the context payload, the payload size, and the context type (full, partial, or filtered). This proves what data crossed each boundary and whether appropriate filtering was applied.
Cross-reference context_type with the data classification of the workflow. If classified data appears in a context_type=full anchor (no filtering), that is a finding. The context_hash allows verification that data was not modified in transit between agents.