Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.emergence.ai/llms.txt

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

A2A Protocol Primer

Google’s A2A protocol (now under the Linux Foundation) is the communication standard that connects all agents on CRAFT. Understanding A2A is prerequisite knowledge for every agent author, regardless of which framework you choose — it defines the contract your agent must honour at its network boundary.

What A2A Is

A2A is an open, vendor-neutral protocol for agent-to-agent communication. Key properties:
  • Transport: JSON-RPC 2.0 over HTTP, with Server-Sent Events (SSE) for streaming responses
  • Discovery: Agent Cards served at a well-known URL describe capabilities
  • Framework-agnostic: works with Google ADK, Pydantic AI, LangGraph, or any custom implementation
  • Task-centric: every interaction creates a Task with a defined lifecycle
A2A defines the protocol, not the implementation. CRAFT agents are free to use any framework internally; they must speak A2A at their boundary.
The current production protocol version on CRAFT is 0.2.6 / 0.3. The a2a Python library (pip install a2a-sdk) provides the canonical types and server utilities (A2AStarletteApplication, DefaultRequestHandler, AgentCard, etc.).

Agent Cards — Identity and Discovery

An Agent Card is a JSON document that describes what an agent does, what it can accept, and how to reach it. Every CRAFT agent publishes its card at:
GET <base-url>/.well-known/agent-card.json
This endpoint is unauthenticated — any orchestrator can fetch it to understand the agent’s capabilities before invoking it.

Agent Card Structure

{
  "name": "Insights Agent",
  "description": "Main analytics agent — plans queries, coordinates sub-agents, analyzes data.",
  "url": "https://<insights-agent-host>",
  "version": "1.4.0",
  "protocolVersion": "0.2.6",
  "provider": {
    "organization": "EmergenceAI",
    "url": "https://emergence.ai"
  },
  "capabilities": {
    "streaming": true,
    "pushNotifications": false,
    "stateTransitionHistory": false
  },
  "skills": [
    {
      "id": "data_query",
      "name": "Data Query",
      "description": "Query databases using natural language",
      "tags": ["sql", "query", "database"],
      "examples": [
        "Show me Q4 revenue by region",
        "What are the top 10 customers by sales?"
      ]
    },
    {
      "id": "data_analysis",
      "name": "Data Analysis",
      "description": "Analyze data, generate charts, and produce insights",
      "tags": ["analysis", "insights", "charts"]
    }
  ],
  "defaultInputModes": ["text", "data", "file"],
  "defaultOutputModes": ["text", "data", "file"],
  "securitySchemes": {
    "bearer": { "type": "http", "scheme": "bearer" }
  },
  "security": [{ "bearer": [] }]
}

Capabilities

CapabilityEffect when true
streamingAgent supports message/stream (SSE); callers may use real-time streaming
pushNotificationsAgent supports webhook push for task completion
stateTransitionHistoryAgent returns full task state transition history in responses
Clients should read capabilities from the Agent Card before calling methods that depend on them. Calling message/stream against an agent with streaming: false returns UnsupportedOperationError.

Skills

Skills are discrete capability declarations within an Agent Card. They help orchestrators understand what tasks the agent can handle and inform LLM routing decisions.
# Pydantic AI / a2a SDK — define skills in code
from a2a.types import AgentSkill

skill = AgentSkill(
    id="data_analysis",
    name="Data Analysis",
    description="Performs data analysis tasks related to semiconductors.",
    tags=["semiconductor", "data analysis"],
    examples=["analyze wafer data", "predict defect rates"],
)
Claude Agent SDK and LangGraph also require explicit skill authoring — add AgentSkill objects to your AgentCard regardless of framework:
# Claude Agent SDK / LangGraph — same AgentSkill definition
from a2a.types import AgentSkill

skill = AgentSkill(
    id="enterprise-analysis",
    name="Enterprise Data Analysis",
    description="Answers business questions by querying governed data sources and generating SQL.",
    tags=["analytics", "sql", "enterprise"],
    examples=["What is our MRR by region?", "Show top 10 customers by revenue last quarter"],
)
Google ADK and to_a2a(): ADK’s to_a2a() constructs a minimal Agent Card from the agent’s name, description, and instruction — but does not populate AgentSkill definitions. For production CRAFT registrations, author explicit AgentSkill objects even when using ADK, to give orchestrators rich capability descriptions for routing decisions. Claude Agent SDK — Wrapping as an A2A Agent: The Claude Anthropic SDK does not natively produce A2A AgentSkill definitions. Wrap a Claude call inside a standard A2A server:
from a2a.types import AgentSkill
import anthropic

client = anthropic.AsyncAnthropic()

skill = AgentSkill(
    id="data-analysis",
    name="Data Analysis",
    description="Analyzes enterprise data using Claude and CRAFT's data catalog.",
    tags=["analytics", "sql", "enterprise"],
    examples=["What is our MRR by region?", "Identify anomalies in yesterday's orders"],
)

# The A2A server calls the Claude API when tasks arrive — see streaming-idioms.mdx
# for the full TaskUpdater pattern
async def handle_task(message: str) -> str:
    response = await client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": message}],
    )
    return response.content[0].text
LangGraph — Wrapping as an A2A Agent:
from a2a.types import AgentSkill
from langgraph.prebuilt import create_react_agent

skill = AgentSkill(
    id="graph-workflow",
    name="Graph Workflow",
    description="Executes multi-step analysis workflows using LangGraph state machines.",
    tags=["workflow", "stateful", "multi-step"],
)

# Build the LangGraph agent; expose via A2AStarletteApplication (see streaming-idioms.mdx
# for the TaskUpdater + astream integration pattern)
graph = create_react_agent("anthropic:claude-sonnet-4-6", tools=[...])

JSON-RPC Methods

The A2A protocol exposes these JSON-RPC methods on your agent’s root endpoint (POST /):
MethodUse CaseResponse
message/sendFire-and-forget, await a single complete responseJSON-RPC response with Task
message/streamReal-time SSE stream of status and artifact eventsSSE event stream
tasks/getPoll for current task stateTask object
tasks/cancelCancel an in-progress taskAcknowledgment
tasks/resubscribeReconnect to a dropped SSE streamSSE event stream from current state
Most CRAFT agents use message/stream exclusively — it is the preferred method for all production interactions because it delivers progressive status updates to the user.

Message Structure

Every request to a CRAFT agent is a Message containing one or more Parts:
{
  "jsonrpc": "2.0",
  "method": "message/stream",
  "params": {
    "message": {
      "role": "user",
      "message_id": "<uuid>",
      "context_id": "<session-id>",
      "parts": [
        { "kind": "text", "text": "Show me Q4 revenue by region" },
        {
          "kind": "data",
          "data": {
            "type": "datasource",
            "resource_uri": "data:acme-corp:ml-project:analytics-db",
            "datasource_type": "database",
            "datasource_name": "Analytics Database",
            "selected_schemas": [
              { "schema_name": "public", "schema_fqn": "analytics-db.analytics_db.public" }
            ]
          }
        }
      ]
    },
    "contextId": "<session-id>"
  },
  "id": "req-1"
}

Part Types

Part Typekind valueUse Case
TextPart"text"Natural language input or agent response
DataPart"data"Structured JSON — datasource context, artifact references, selection context
FilePart"file"Binary content referenced by URI (asset://artifacts/chart.png)
The context_id groups messages into a conversation session. CRAFT agents use this to retrieve conversation history from the task store and maintain coherent multi-turn dialogue.

Task Lifecycle

Every message/send or message/stream call creates or resumes a Task. Tasks follow a strict state machine:
submitted ──► working ──► completed
                      ──► failed
             ──► input-required
             ──► canceled
             ──► rejected
Terminal states (completed, failed, canceled, rejected) are final — a task in a terminal state cannot be restarted. To continue a conversation, the client sends a new message with the same context_id.

SSE Streaming — Event Sequence

When a client calls message/stream, the server responds with Content-Type: text/event-stream and pushes events as the agent works. Each data: line is a complete JSON-RPC 2.0 response object.

Event Types

Result TypeWhen Used
TaskFirst event — the created task (state = submitted)
TaskStatusUpdateEventLifecycle state changes and intermediate messages
TaskArtifactUpdateEventCompleted artifacts (results, charts, files)

Protocol Rules

  1. The first event MUST be a Task or a Message
  2. Intermediate events are TaskStatusUpdateEvent (state=working) and TaskArtifactUpdateEvent
  3. The final event MUST be TaskStatusUpdateEvent with final: true and a terminal state
  4. The SSE connection closes after the final event

Wire Example — Text2SQL Stream

The following is a real-world event sequence from the CRAFT text2sql agent:
data: {"kind":"status-update","task_id":"t1","final":false,
       "status":{"state":"working","message":{"role":"agent",
       "parts":[{"kind":"text","text":"Analyzing database schema"}]}}}

data: {"kind":"status-update","task_id":"t1","final":false,
       "status":{"state":"working","message":{"role":"agent",
       "parts":[{"kind":"text","text":"Running query"}]}}}

data: {"kind":"artifact-update","task_id":"t1",
       "artifact":{"artifact_id":"abc","name":"query_summary",
       "parts":[{"kind":"text","text":"Top 10 customers by revenue"}]}}

data: {"kind":"artifact-update","task_id":"t1","last_chunk":true,
       "artifact":{"artifact_id":"def","name":"query_results",
       "parts":[{"kind":"data","data":{"type":"artifact",
       "uri":"data:acme:proj:results-parquet",
       "resource_type":"parquet",
       "metadata":{"row_count":10,"columns":["customer_name","total_revenue"]}}}]}}

data: {"kind":"status-update","task_id":"t1","final":true,
       "status":{"state":"completed"}}

Chunked Artifact Streaming

Large artifacts can be delivered in chunks using the append and lastChunk flags:
{"artifactUpdate": {"artifact": {"artifactId": "a1", "parts": [...chunk1...], "append": false, "lastChunk": false}}}
{"artifactUpdate": {"artifact": {"artifactId": "a1", "parts": [...chunk2...], "append": true,  "lastChunk": false}}}
{"artifactUpdate": {"artifact": {"artifactId": "a1", "parts": [...chunk3...], "append": true,  "lastChunk": true}}}

Agent-to-Agent Communication Flow

The following sequence diagram shows how an orchestrator delegates a task to a sub-agent using the A2A protocol.

Authentication

Agent Cards declare supported authentication schemes in securitySchemes. CRAFT agents use JWT bearer tokens — the orchestrator injects them when calling sub-agents.
{
  "securitySchemes": {
    "bearer": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" }
  },
  "security": [{ "bearer": [] }]
}
Agents validate the token, extract the user_id and org_id, and use them to scope all database queries and audit logs. A small UserContextBuilder that reads the Authorization header and exposes a typed context object to your dependencies is the canonical pattern for Pydantic AI + a2a server integrations.

Reconnection

If an SSE connection drops mid-stream, the client can reconnect using tasks/resubscribe:
{
  "jsonrpc": "2.0",
  "method": "tasks/resubscribe",
  "params": { "taskId": "task-123" }
}
The server resumes the event stream from the task’s current state. Your agent implementation does not need to handle this explicitly — A2AStarletteApplication and DefaultRequestHandler manage reconnection automatically.

Next Steps

Your First Agent

Build your first agent using Google ADK, Pydantic AI, or another supported framework.

Multi-Agent Patterns

Orchestration, delegation, and fan-out across multiple A2A agents.