DEV Community

Philip Stayetski
Philip Stayetski

Posted on • Originally published at pilotprotocol.network

A2A Agent Cards Over Pilot Tunnels

Google's Agent-to-Agent (A2A) protocol standardizes what agents say to each other — Agent Cards, task lifecycle, JSON-RPC 2.0. But it assumes HTTP transport: public URLs, a /.well-known/agent.json endpoint, TLS certs. That's a fine assumption for a cloud service. It's a bad one for an agent behind NAT, running in a container, or living on someone's laptop — which describes most real agent deployments.

A2A defines the language of agent collaboration. It doesn't define how two agents that can't both hold a public IP actually reach each other. That's a networking problem, and Pilot Protocol is a networking layer: permanent virtual addresses, encrypted UDP tunnels, NAT traversal, and a trust model. A2A defines the language; Pilot provides the phone system. You need both to have a conversation.

Where the two layers meet

Concern A2A Pilot
Capability advertisement Agent Cards (JSON) Registry (capability flags + metadata)
Task lifecycle send/get/cancel task (JSON-RPC) Messaging ports (send/recv)
Wire format JSON-RPC 2.0 Binary header + payload
Transport HTTP/HTTPS UDP overlay
Discovery Well-known URL or directory Registry resolve + trust handshake
Security TLS + auth headers X25519 + AES-GCM, encrypted by default
NAT traversal Not addressed STUN, hole-punching, relay fallback
Trust model OAuth / API keys Private-by-default, trust-gated resolve

A2A tells you the shape of the conversation. Pilot tells you how the bytes actually get from one agent to the other when neither one has a stable public address.

The Agent Card's weak point

A standard minimal A2A Agent Card looks like this:

{
  "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",
    "tags": ["research", "nlp", "summarization"]
  }],
  "defaultInputModes": ["text/plain"],
  "defaultOutputModes": ["text/plain", "text/markdown"]
}
Enter fullscreen mode Exit fullscreen mode

The url field is where the assumption bites: it has to be a publicly reachable HTTPS endpoint. Every agent that isn't running behind a reverse proxy with a domain name and a cert either can't be reached, or has to be stood up with infrastructure that has nothing to do with what the agent actually does.

Swap that url for a Pilot virtual address — a permanent identifier like 1:0000.0042.00A1 — and the agent is reachable over Pilot's encrypted overlay instead. No public IP, no DNS record, no certificate to renew.

Serving Agent Cards over a Pilot tunnel (Go)

Using github.com/pilot-protocol/pilotprotocol/pkg/driver:

drv, err := driver.Connect("/tmp/pilot.sock")
info, _ := drv.Info()
pilotAddr := info.Address // e.g., "1:0000.0042.00A1"

card := AgentCard{
    URL: fmt.Sprintf("pilot://%s:80", pilotAddr),
    // ... other fields
}

http.HandleFunc("/.well-known/agent.json", func(w http.ResponseWriter, r *http.Request) {
    json.NewEncoder(w).Encode(card)
})

http.HandleFunc("/a2a", func(w http.ResponseWriter, r *http.Request) {
    // handles JSON-RPC methods: "tasks/send", "tasks/get"
})

drv.ListenAndServeHTTP(80, http.DefaultServeMux)
Enter fullscreen mode Exit fullscreen mode

The card fetch, the task submission, and the result delivery all travel over Pilot's encrypted UDP tunnel. Key exchange (X25519) and encryption (AES-GCM) are negotiated automatically when the tunnel is established — the application code above never touches TLS.

Trust-gated cards instead of public ones

Standard A2A treats the Agent Card as public: anyone with the URL can fetch it. Pilot's trust model changes that by default, in three layers:

  1. Address resolution is trust-gated — an untrusted peer can't resolve the agent's address, so it can't even confirm the agent exists.
  2. Connection requires mutual trust — an explicit handshake (mutual approve) has to complete before a tunnel opens.
  3. The card itself is served only over an already-trusted connection — its contents are revealed post-authentication, not before.

That gives you a privacy gradient A2A alone doesn't offer:

  • Public agents — serve the card to anyone who resolves the address.
  • Private agents — require a trust handshake before the card is even visible.
  • Semi-private agents — a redacted card (name/description only) for untrusted peers, the full card (skills, examples) for trusted ones.

A medical-research agent, a financial-analysis agent, or anything sitting on proprietary data can be fully A2A-compliant while staying invisible to everyone it hasn't explicitly trusted.

A2A over the internet vs. A2A over Pilot

Dimension A2A over the internet A2A over Pilot
Reachability Requires a public IP or reverse proxy Works behind any NAT
Encryption TLS certs — issuance and renewal Automatic X25519 + AES-GCM, no certs to manage
Discovery DNS + well-known URL Registry resolve, no DNS involved
Privacy Card visible to anyone with the URL Visible only to peers you've explicitly trusted
Identity A domain name you purchase and maintain A permanent virtual address, assigned once

None of this replaces A2A — the protocol still defines what a task request looks like, how capabilities are described, how results come back. What changes is everything underneath: no public endpoint to expose, no cert lifecycle to manage, and a trust boundary that exists by default instead of being bolted on with API keys.

Try it

curl -fsSL https://pilotprotocol.network/install.sh | sh
Enter fullscreen mode Exit fullscreen mode

Full walkthrough, the driver API, and the registry docs: pilotprotocol.network/docs. Source is open, AGPL-3.0: github.com/pilot-protocol.

Top comments (0)