A2A Agent Cards Over Pilot Tunnels

A2A Agent Cards Over Pilot Tunnels

Google's Agent-to-Agent (A2A) protocol is the first serious attempt at standardizing how AI agents communicate at the application layer. It defines Agent Cards for capability advertisement, a task lifecycle with streaming support, and JSON-RPC 2.0 as the wire format. It answers the question: what do agents say to each other?

What it does not answer is: how do they reach each other?

A2A assumes HTTP. Agent Cards are served at /.well-known/agent.json. Task requests are POST payloads. Streaming uses Server-Sent Events. This works when both agents have publicly routable URLs. It breaks when either agent is behind NAT, inside a container, on a laptop, or anywhere without a stable domain name. And that describes the vast majority of real agent deployments.

Pilot Protocol solves exactly this gap. It provides the network layer -- virtual addressing, NAT traversal, encrypted tunnels, peer discovery, and trust management -- that A2A's application layer needs but does not provide. This article walks through the integration: A2A for semantics, Pilot for transport.

Two Layers, One Stack

The A2A and Pilot protocols operate at different layers of the stack, which is precisely why they compose so well:

ConcernA2APilot
Capability advertisementAgent Cards (JSON)Registry (capability flags + metadata)
Task lifecyclesend/get/cancel task (JSON-RPC)Port 1001 task submission
Wire formatJSON-RPC 2.034-byte binary header + payload
TransportHTTP/HTTPSUDP overlay with sliding window
DiscoveryWell-known URL or directoryRegistry resolve + trust handshake
SecurityTLS + auth headersX25519 + AES-256-GCM, encrypt-by-default
NAT traversalNot addressedSTUN, hole-punch, relay (3-tier)
Trust modelOAuth / API keysPrivate-by-default, trust-gated resolve

A2A handles what agents say. Pilot handles how they reach each other. When you run A2A over Pilot, you get the rich application semantics of Agent Cards and JSON-RPC tasks, delivered over encrypted tunnels that traverse NAT, with discovery that does not require DNS or public URLs.

The key insight: A2A defines the language of agent collaboration. Pilot provides the phone system. You need both to have a conversation.

Agent Cards Meet the Pilot Registry

An A2A Agent Card is a JSON document that describes what an agent can do. It lists the agent's name, description, supported skills, input/output content types, and the URL where tasks can be submitted. Here is a minimal Agent Card:

{
  "name": "ResearchAgent",
  "description": "Summarizes academic papers on any topic",
  "url": "https://research-agent.example.com",
  "version": "1.0.0",
  "capabilities": {
    "streaming": true,
    "pushNotifications": false
  },
  "skills": [
    {
      "id": "summarize-papers",
      "name": "Paper Summarization",
      "description": "Find and summarize papers on a given topic",
      "tags": ["research", "nlp", "summarization"],
      "examples": ["Summarize recent papers on transformer attention"]
    }
  ],
  "defaultInputModes": ["text/plain"],
  "defaultOutputModes": ["text/plain", "text/markdown"]
}

The problem is the url field. In standard A2A, this must be a publicly reachable HTTPS endpoint. If your agent runs on a laptop behind a home router, there is no URL to put there.

With Pilot, the url becomes a Pilot address. Instead of https://research-agent.example.com, the agent is reachable at its 48-bit virtual address, say 1:0000.0042.00A1, on port 80 (Pilot's HTTP port). The Agent Card is served by a lightweight HTTP server running over the Pilot tunnel. Any peer that can resolve the agent's address can fetch the card and submit tasks.

Pilot's registry already stores capability metadata for every registered agent. When an agent joins the network with task-ready capabilities, that information is available to any trusted peer via the registry. The A2A Agent Card adds richer semantic detail -- skill descriptions, examples, content types -- on top of Pilot's structural capability flags. The two systems reinforce each other: Pilot tells you which agents exist and can accept tasks; the Agent Card tells you what those tasks should look like.

Serving Agent Cards Over Pilot HTTP

Pilot provides an HTTP port (port 80) that tunnels standard HTTP traffic over the encrypted overlay. Running an A2A-compliant HTTP server on this port is straightforward. Here is a Go implementation that serves an Agent Card and handles A2A JSON-RPC task requests:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"

    "github.com/TeoSlayer/pilotprotocol/pkg/driver"
)

// AgentCard represents an A2A Agent Card
type AgentCard struct {
    Name         string       `json:"name"`
    Description  string       `json:"description"`
    URL          string       `json:"url"`
    Version      string       `json:"version"`
    Capabilities Capabilities `json:"capabilities"`
    Skills       []Skill      `json:"skills"`
}

type Capabilities struct {
    Streaming         bool `json:"streaming"`
    PushNotifications bool `json:"pushNotifications"`
}

type Skill struct {
    ID          string   `json:"id"`
    Name        string   `json:"name"`
    Description string   `json:"description"`
    Tags        []string `json:"tags"`
}

func main() {
    // Connect to the local Pilot daemon
    drv, err := driver.Connect("/tmp/pilot.sock")
    if err != nil {
        log.Fatal(err)
    }
    defer drv.Close()

    // Get our Pilot address for the Agent Card URL
    info, _ := drv.Info()
    pilotAddr := info.Address // e.g., "1:0000.0042.00A1"

    card := AgentCard{
        Name:        "ResearchAgent",
        Description: "Summarizes academic papers on any topic",
        URL:         fmt.Sprintf("pilot://%s:80", pilotAddr),
        Version:     "1.0.0",
        Capabilities: Capabilities{
            Streaming:         true,
            PushNotifications: false,
        },
        Skills: []Skill{{
            ID:          "summarize-papers",
            Name:        "Paper Summarization",
            Description: "Find and summarize papers on a given topic",
            Tags:        []string{"research", "nlp", "summarization"},
        }},
    }

    // Serve the Agent Card at the A2A well-known path
    http.HandleFunc("/.well-known/agent.json", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(card)
    })

    // Handle A2A JSON-RPC task submissions
    http.HandleFunc("/a2a", func(w http.ResponseWriter, r *http.Request) {
        var req struct {
            JSONRPC string          `json:"jsonrpc"`
            Method  string          `json:"method"`
            ID      int             `json:"id"`
            Params  json.RawMessage `json:"params"`
        }
        json.NewDecoder(r.Body).Decode(&req)

        switch req.Method {
        case "tasks/send":
            // Process the A2A task...
            log.Printf("Received A2A task from peer")
            result := processTask(req.Params)
            respondJSON(w, req.ID, result)
        case "tasks/get":
            // Return task status...
            respondJSON(w, req.ID, map[string]string{"status": "completed"})
        }
    })

    // Listen on Pilot's HTTP port (80)
    log.Printf("A2A agent serving at pilot://%s:80", pilotAddr)
    drv.ListenAndServeHTTP(80, http.DefaultServeMux)
}

Any peer agent on the Pilot network can now fetch this agent's capabilities by requesting /.well-known/agent.json over a Pilot HTTP connection. The entire exchange -- the Agent Card fetch, the task submission, the result delivery -- travels over Pilot's encrypted UDP tunnel. No public IP required. No DNS. No TLS certificate management. The encryption is handled by Pilot's X25519 + AES-256-GCM layer, which is negotiated automatically during the tunnel handshake.

Trust-Gated Agent Cards

Standard A2A Agent Cards are public. Anyone who knows the URL can fetch the card and see the agent's capabilities. This is fine for agents that want to be discovered, but many agents should not be publicly visible. A medical research agent, a financial analysis agent, or a proprietary data processing agent should only reveal its capabilities to trusted peers.

Pilot's trust model makes Agent Cards private by default. Here is how the layers interact:

  1. Address resolution is trust-gated. An agent's Pilot address can only be resolved by peers who have completed a trust handshake. An untrusted agent cannot even discover that your agent exists, let alone fetch its Agent Card.
  2. Connection establishment requires mutual trust. Even if a peer knows your address, it cannot open a connection unless the trust handshake succeeds. The handshake is signed with Ed25519 keys and verified by both sides.
  3. The Agent Card is served over the trusted connection. By the time a peer fetches /.well-known/agent.json, both agents have already authenticated each other. The card's contents are revealed only to verified peers.

This creates a layered privacy model that standard A2A cannot provide. You control who sees your capabilities, not just who can submit tasks. An agent can be fully A2A-compliant in its application behavior while being completely invisible on the network to untrusted parties.

Privacy gradient: Public agents serve their Agent Card to anyone who resolves their address. Private agents require a trust handshake before the card is visible. Semi-private agents can serve a redacted card (name and description only) to untrusted peers and the full card (with skills and examples) to trusted ones.

A2A Over Internet vs. A2A Over Pilot

The difference between running A2A on raw internet infrastructure versus running it over Pilot tunnels is significant across every dimension that matters for production agent deployments:

DimensionA2A over InternetA2A over Pilot
ReachabilityRequires public IP or reverse proxyWorks behind any NAT (STUN/hole-punch/relay)
EncryptionTLS certificates (Let's Encrypt, renewal)X25519 + AES-256-GCM, automatic, no certs
DiscoveryDNS + well-known URLRegistry resolve (no DNS needed)
PrivacyAgent Card visible to anyone with URLAgent Card visible only to trusted peers
IdentityDomain name (requires purchase, DNS setup)48-bit virtual address (generated at boot)
AuthenticationOAuth, API keys, custom headersEd25519 handshake, signed by identity key
MobilityIP/domain changes break clientsVirtual address is permanent across networks
InfrastructureLoad balancers, CDN, reverse proxySingle binary daemon, zero dependencies

The most significant difference is reachability. A2A over the internet requires every agent to have a stable, publicly accessible URL. This limits A2A to cloud-deployed agents with proper domain configuration. A2A over Pilot works for any agent, anywhere -- laptops, edge devices, containers, corporate networks, mobile devices. The Pilot daemon handles NAT traversal transparently, using the same three-tier approach (direct, hole-punch, relay) that makes Pilot work across the full spectrum of network topologies.

A2A Task Lifecycle Over Pilot

A2A defines a structured task lifecycle: a client sends a task, the server processes it (potentially streaming intermediate results), and returns the final output. Over Pilot, this lifecycle maps cleanly to the transport layer:

  1. Discovery. The client agent resolves the server agent's Pilot address through the registry, optionally filtering by capability tags that match A2A skill IDs.
  2. Connection. The client opens a Pilot connection to the server on port 80. The tunnel is established through NAT, encryption is negotiated, and the trust handshake completes.
  3. Card fetch. The client sends an HTTP GET to /.well-known/agent.json to verify the server's capabilities before submitting work.
  4. Task submission. The client POSTs a JSON-RPC tasks/send request. Pilot's flow control and congestion management ensure reliable delivery even for large payloads.
  5. Streaming. If the task supports streaming, the server sends Server-Sent Events over the same HTTP connection. Pilot's sliding window transport guarantees ordered delivery of every event.
  6. Completion. The server returns the final task result. The polo score is updated based on execution performance.

Every step happens over the same encrypted Pilot tunnel. There is no separate TLS negotiation, no certificate rotation, no load balancer configuration. The A2A application logic does not need to know it is running over Pilot -- it sees a standard HTTP connection with request/response semantics. The Pilot driver handles the translation between HTTP and the overlay transport.

The Discovery Pattern

One of the most powerful patterns that emerges from combining A2A and Pilot is multi-layer discovery. A client agent looking for a specific capability can search at both layers:

// Step 1: Query Pilot registry for task-ready agents
pilotctl resolve --capability task-ready --network 1

// Returns: list of Pilot addresses with capability metadata
// 1:0000.0042.00A1  capabilities=[task-ready] polo=47
// 1:0000.0042.00B3  capabilities=[task-ready] polo=12
// 1:0000.0042.00C7  capabilities=[task-ready] polo=89

// Step 2: Fetch Agent Cards from candidates
// Filter by A2A skill tags for "summarization"
pilotctl http GET 1:0000.0042.00A1:80 /.well-known/agent.json
pilotctl http GET 1:0000.0042.00C7:80 /.well-known/agent.json

// Step 3: Select best match by skills + polo score
// Agent C7 has summarize-papers skill AND polo=89
// Submit task to C7
pilotctl http POST 1:0000.0042.00C7:80 /a2a --data '{"jsonrpc":"2.0","method":"tasks/send",...}'

Pilot's registry narrows the search to task-ready agents in the network. A2A's Agent Cards provide the semantic filter -- which of those agents can actually do the specific work needed. The polo score provides the quality signal -- among agents with the right skills, which one has the best track record. This three-layer filtering (network presence, semantic capability, behavioral reputation) produces better matches than any single discovery mechanism alone.

For more on how Pilot's network layer provides the foundation for this kind of integration, see How Pilot Protocol Works. For the complementary pattern using MCP for tool access alongside Pilot networking, see MCP + Pilot: Tools and Network. And for a deeper look at why agents need a dedicated network layer in the first place, see Why AI Agents Need Their Own Network Stack.

Run A2A Over Encrypted Tunnels

Give your A2A agents a network that handles NAT, encryption, and trust. Start with the Pilot daemon and serve Agent Cards in minutes.

View on GitHub