| Internet-Draft | Pilot Protocol | March 2026 |
| Teodor | Expires 15 September 2026 | [Page] |
This document specifies Pilot Protocol, an overlay network that provides autonomous AI agents with virtual addresses, port-based service multiplexing, reliable and unreliable transport, NAT traversal, encrypted tunnels, and a bilateral trust model. Pilot Protocol operates as a network and transport layer beneath application-layer agent protocols such as A2A and MCP. It encapsulates virtual packets in UDP datagrams for transit over the existing Internet. The protocol gives agents first-class network citizenship --- stable identities, reachable addresses, and standard transport primitives --- independent of their underlying network infrastructure.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 15 September 2026.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document.¶
AI agents are autonomous software entities that reason, plan, and execute tasks. As agents become more prevalent, they need to communicate with each other across heterogeneous network environments: cloud, edge, behind NAT, and across organizational boundaries. Current agent protocols (MCP, A2A) operate at the application layer over HTTP, assuming agents have stable, reachable endpoints. This assumption fails for a large class of deployments.¶
Pilot Protocol is an overlay network stack that gives agents network-layer primitives: virtual addresses, ports, reliable streams, unreliable datagrams, NAT traversal, encrypted tunnels, name resolution, and a bilateral trust model. It is positioned as the network/transport layer beneath application-layer agent protocols --- analogous to how TCP/IP sits beneath HTTP.¶
The protocol is designed around five principles:¶
Agents are first-class network citizens. Every agent gets a unique virtual address, can bind ports, listen for connections, and be reached by any authorized peer.¶
The network boundary is the trust boundary. Network membership serves as the primary access control mechanism. Joining a network requires meeting its rules.¶
Transport agnosticism. The protocol provides reliable streams (TCP-equivalent) and unreliable datagrams (UDP-equivalent). Anything that runs on TCP/IP can run on the overlay.¶
Minimize the protocol, maximize the surface. The protocol defines addressing, packets, and transport. Application-level message formats are layers built on top.¶
Practical over pure. The protocol uses a centralized registry for address assignment and a centralized beacon for NAT traversal. Full decentralization is a future goal, not a prerequisite.¶
Pilot Protocol operates at the network and transport layers of the overlay stack. It is complementary to, not competitive with, application-layer agent protocols:¶
A2A defines what agents say to each other. Pilot defines how they reach each other.¶
MCP defines agent-to-tool interfaces. Pilot provides the transport substrate.¶
QUIC [RFC9000] is a potential underlay transport. Pilot could run over QUIC instead of raw UDP.¶
LISP [RFC9300] provides conceptual precedent for identity/locator separation.¶
VXLAN [RFC7348] and GENEVE [RFC8926] are overlay encapsulation precedents at the data link layer. Pilot operates at the network layer.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
An autonomous software entity capable of reasoning, planning, and executing tasks without continuous human supervision.¶
The local Pilot Protocol process that implements the virtual network stack. It maintains a UDP tunnel, handles routing, session management, and encryption. Analogous to a virtual NIC.¶
An SDK or library that agents import to communicate with the local daemon over IPC. Provides the application-facing API (listen, dial, read, write, close).¶
A centralized service that assigns virtual addresses, maintains the address-to-locator mapping table, manages network membership, and stores public keys.¶
A service that provides NAT traversal coordination: endpoint discovery (STUN-like), hole-punch coordination, and relay fallback.¶
A 48-bit overlay address assigned to an agent, independent of its underlying IP address.¶
A bilateral trust relationship between two agents, established through explicit mutual consent.¶
Pilot Protocol is a five-layer overlay stack:¶
| Layer | Function |
|---|---|
| Application | HTTP, RPC, custom protocols (above Pilot) |
| Session | Reliable streams, unreliable datagrams |
| Network | Virtual addresses, ports, routing |
| Tunnel | NAT traversal, UDP encapsulation, encryption |
| Physical | Real Internet (IP/TCP/UDP) |
The overlay handles addressing, routing, and session management. The underlying Internet handles physical delivery.¶
Assigns virtual addresses, maintains address table, manages networks and trust pairs, relays handshake requests for private nodes. Runs on TCP. The only globally reachable component.¶
Provides STUN-like endpoint discovery, hole-punch coordination, and relay fallback for symmetric NAT. Runs on UDP.¶
Core protocol implementation running on each participating machine. Maintains a single UDP socket, multiplexes all virtual connections, handles tunnel encryption, and exposes a local IPC socket for drivers.¶
Client SDK that agents import. Connects to the local daemon via Unix domain socket. Implements standard network interfaces (listeners, connections).¶
DNS equivalent for the overlay. Runs as a service on virtual port 53, resolving human-readable names to virtual addresses.¶
Bridge between the overlay and standard IP. Maps virtual addresses to local IPs, allowing unmodified TCP programs to reach agents.¶
Addresses are 48 bits, split into two fields:¶
0 1 2 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Network ID (16 bits) | Node ID (32 bits) ~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ~ Node ID (continued) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+¶
Identifies the network or topic. Network 0 is the global backbone; all nodes are members by default. Networks 1-65534 are created for specific purposes. Network 65535 is reserved.¶
Identifies the individual agent within a network. Supports over 4 billion nodes per network.¶
Addresses are written as N:XXXX.YYYY.ZZZZ where:¶
N is the network ID in decimal¶
XXXX.YYYY.ZZZZ is the node ID as three groups of 4 hexadecimal digits¶
Examples:¶
A socket address appends a port: 1:00A3.F291.0004:1000¶
| Address | Meaning |
|---|---|
0:0000.0000.0000
|
Unspecified / wildcard |
0:0000.0000.0001
|
Registry |
0:0000.0000.0002
|
Beacon |
0:0000.0000.0003
|
Nameserver |
X:FFFF.FFFF.FFFF
|
Broadcast on network X |
Virtual ports are 16-bit unsigned integers (0-65535):¶
| Range | Purpose |
|---|---|
| 0-1023 | Reserved / well-known |
| 1024-49151 | Registered services |
| 49152-65535 | Ephemeral / dynamic |
| Port | Service | Description |
|---|---|---|
| 0 | Ping | Liveness checks |
| 1 | Control | Daemon-to-daemon control |
| 7 | Echo | Echo service (testing) |
| 53 | Name resolution | Nameserver queries |
| 80 | Agent HTTP | Web endpoints |
| 443 | Secure channel | X25519 + AES-256-GCM |
| 444 | Trust handshake | Peer trust negotiation |
| 1000 | Standard I/O | Text stream between agents |
| 1001 | Data exchange | Typed frames (text, binary, JSON, file) |
| 1002 | Event stream | Pub/sub with topic filtering |
| 1003 | Task submission | Task lifecycle and reputation scoring |
The fixed packet header is 34 bytes:¶
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Ver | Flags | Protocol | Payload Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Network ID | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Source Node ID | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination Network ID | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Destination Node ID | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgment Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Window (segments) | Checksum (hi) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum (lo) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
All multi-byte fields are in network byte order (big-endian).¶
| Field | Offset | Size | Description |
|---|---|---|---|
| Version | 0 | 4 bits | Protocol version. Current: 1 |
| Flags | 0 | 4 bits | SYN (0x1), ACK (0x2), FIN (0x4), RST (0x8) |
| Protocol | 1 | 1 byte | Transport type (see Section 6.3) |
| Payload Length | 2 | 2 bytes | Payload length in bytes (max 65535) |
| Source Network | 4 | 2 bytes | Source network ID |
| Source Node | 6 | 4 bytes | Source node ID |
| Dest Network | 10 | 2 bytes | Destination network ID |
| Dest Node | 12 | 4 bytes | Destination node ID |
| Source Port | 16 | 2 bytes | Source port |
| Dest Port | 18 | 2 bytes | Destination port |
| Sequence Number | 20 | 4 bytes | Byte offset of this segment |
| Ack Number | 24 | 4 bytes | Next expected byte from peer |
| Window | 28 | 2 bytes | Advertised receive window in segments |
| Checksum | 30 | 4 bytes | CRC32 over header + payload |
| Value | Name | Description |
|---|---|---|
| 0x01 | Stream | Reliable, ordered delivery (TCP-like) |
| 0x02 | Datagram | Unreliable, unordered (UDP-like) |
| 0x03 | Control | Internal control messages |
| Bit | Name | Description |
|---|---|---|
| 0 | SYN | Synchronize --- initiate connection |
| 1 | ACK | Acknowledge --- confirm receipt |
| 2 | FIN | Finish --- close connection |
| 3 | RST | Reset --- abort connection |
The checksum is computed as follows:¶
Set the 4-byte checksum field to zero.¶
Compute CRC32 (IEEE polynomial) over the entire header (34 bytes with zeroed checksum field) concatenated with the payload bytes.¶
Write the resulting 32-bit value into the checksum field in big-endian byte order.¶
Receivers MUST verify the checksum and discard packets with incorrect values.¶
Note: CRC32 detects accidental corruption but does not provide cryptographic integrity. Tamper resistance is provided by tunnel-layer encryption (Section 7.2).¶
Virtual packets are encapsulated in UDP datagrams for transit over the real Internet. Four frame types are defined, distinguished by a 4-byte magic value.¶
+------+------+------+------+---...---+---...---+
| 0x50 | 0x49 | 0x4C | 0x54 | Header | Payload |
+------+------+------+------+---...---+---...---+
P I L T 34 bytes variable
¶
The magic bytes 0x50494C54 ("PILT") indicate an unencrypted Pilot Protocol frame. The header and payload follow immediately.¶
+------+------+------+------+----------+----------+---...---+
| 0x50 | 0x49 | 0x4C | 0x53 | SenderID | Nonce |Ciphertext
+------+------+------+------+----------+----------+---...---+
P I L S 4 bytes 12 bytes variable
¶
The magic bytes 0x50494C53 ("PILS") indicate an encrypted frame.¶
4-byte Node ID of the sending daemon, in big-endian. Used by the receiver to look up the shared AES-256-GCM key for this peer.¶
12-byte GCM nonce. See Section 11 for construction.¶
The Pilot Protocol header and payload, encrypted with AES-256-GCM [RFC5116]. The ciphertext includes a 16-byte authentication tag appended by GCM.¶
The encryption key is derived from an X25519 [RFC7748] ECDH exchange between the two daemons (see Section 7.3).¶
+------+------+------+------+----------+---...---+
| 0x50 | 0x49 | 0x4C | 0x4B | SenderID | X25519 |
+------+------+------+------+----------+---...---+
P I L K 4 bytes 32 bytes
¶
Anonymous key exchange. The sender transmits its ephemeral X25519 public key (32 bytes, per [RFC7748]). Both sides compute the ECDH shared secret and derive an AES-256-GCM key.¶
PILK provides confidentiality but not authentication. An active attacker can perform a man-in-the-middle attack by substituting their own public key. See Section 7.4 for the authenticated variant.¶
+------+------+------+------+----------+---------+---------+---------+
| 0x50 | 0x49 | 0x4C | 0x41 | SenderID | X25519 | Ed25519 | Sig |
+------+------+------+------+----------+---------+---------+---------+
P I L A 4 bytes 32 bytes 32 bytes 64 bytes
¶
Authenticated key exchange. In addition to the X25519 public key, the sender includes its Ed25519 public key (32 bytes, per [RFC8032]) and a 64-byte Ed25519 signature.¶
The signature covers the concatenation of:¶
The ASCII string "auth" (4 bytes)¶
The sender's Node ID (4 bytes, big-endian)¶
The X25519 public key (32 bytes)¶
The receiver verifies the signature using the sender's Ed25519 public key, which it obtains from the registry and cross-checks against the claimed Node ID. This binds the ephemeral X25519 key to the sender's persistent identity, preventing man-in-the-middle attacks.¶
Daemons with persistent Ed25519 identities SHOULD use PILA. Daemons without persistent identities fall back to PILK.¶
Dial()
CLOSED -----------> SYN_SENT
^ |
| SYN-ACK recv
| |
| v
| ESTABLISHED <--- Listen() + SYN recv
| |
| Close()
| |
| v
| FIN_WAIT
| |
| ACK recv
| |
| v
| TIME_WAIT
| |
| 10s timeout
| |
+--------------------+
Connection establishment uses a three-way handshake:¶
Initiator Responder
| |
|-------- SYN seq=X ------------->|
| |
|<--- SYN+ACK seq=Y ack=X+1 -----|
| |
|-------- ACK ack=Y+1 ----------->|
| |
| ESTABLISHED | ESTABLISHED
¶
The initiator selects an initial sequence number X. The responder selects its own initial sequence number Y and acknowledges X+1. The initiator confirms by acknowledging Y+1.¶
Both sides include their advertised receive window in the Window field of the SYN and SYN-ACK packets.¶
Closer Remote
| |
|-------- FIN seq=N ------------->|
| |
|<------- ACK ack=N+1 -----------|
| |
| TIME_WAIT (10s) | CLOSED
| |
| CLOSED |
¶
The closer sends FIN, waits for ACK, and enters TIME_WAIT for 10 seconds. The 10-second TIME_WAIT is shorter than TCP's typical 2*MSL because overlay RTTs are bounded by the underlay network.¶
Sequence numbers are 32-bit unsigned integers with wrapping comparison per [RFC1982]:¶
seqAfter(a, b) = int32(a - b) > 0¶
This correctly handles wraparound at 2^32.¶
The Stream protocol (0x01) provides reliable, ordered byte stream delivery using a sliding window mechanism.¶
RTO is computed per [RFC6298]:¶
SRTT (Smoothed RTT): updated with alpha = 1/8¶
RTTVAR (RTT Variance): updated with beta = 1/4¶
RTO = SRTT + max(G, 4 * RTTVAR)¶
G (clock granularity floor) = 10 ms¶
RTO is clamped to the range 200 ms to 10 s¶
SYN packets are retransmitted with exponential backoff: 1s, 2s, 4s, 8s, up to 5 retries. Data segments allow up to 8 retransmission attempts before the connection is closed.¶
Segments received out of order are buffered and delivered to the application in sequence order when gaps are filled.¶
When the receiver has out-of-order segments, it encodes SACK blocks in the ACK payload. Each SACK block is a pair of 32-bit sequence numbers representing a contiguous range of received bytes beyond the cumulative ACK point. Up to 4 SACK blocks are encoded per ACK.¶
The sender uses SACK information to retransmit only the missing segments, skipping segments the peer has already received.¶
The protocol implements TCP-style congestion control:¶
The congestion window (cwnd) starts at 10 segments (40 KB) per [RFC6928] and grows by one segment for each ACK received, until cwnd reaches the slow-start threshold (ssthresh).¶
After cwnd reaches ssthresh, growth switches to additive-increase: cwnd grows by approximately one segment per round-trip time (Appropriate Byte Counting per [RFC3465]).¶
After 3 duplicate pure ACKs (data packets with piggybacked ACKs are excluded per [RFC5681] Section 3.2), the sender retransmits the missing segment without waiting for RTO.¶
On loss detection (fast retransmit or RTO), ssthresh is set to max(cwnd/2, 2 segments). On RTO, cwnd is additionally reset to 1 segment (Tahoe behavior).¶
The maximum congestion window is 1 MB. The maximum segment size (MSS) is 4096 bytes.¶
Each ACK carries the receiver's advertised window --- the number of free segments in its receive buffer. The sender's effective window is:¶
effective_window = min(cwnd, peer_advertised_window)¶
This prevents a fast sender from overwhelming a slow receiver.¶
When the receiver advertises a zero window, the sender enters persist mode and sends 1-byte probe segments at exponentially increasing intervals until the receiver opens its window.¶
Small writes are buffered when unacknowledged data is in flight and flushed when:¶
The buffer reaches MSS (4096 bytes), or¶
All previous data is acknowledged, or¶
A 40 ms timeout expires.¶
This reduces packet overhead for applications performing many small writes. The algorithm can be disabled per-connection with a NoDelay option, analogous to TCP_NODELAY.¶
Large writes are automatically segmented into MSS-sized chunks (4096 bytes) by the daemon. Applications can write arbitrarily large buffers without manual chunking.¶
Instead of sending an ACK for every received segment, the daemon batches up to 2 segments or 40 ms (whichever comes first). When out-of-order data is present, ACKs are sent immediately with SACK blocks to trigger fast retransmit. When data is sent on a connection, the pending delayed ACK is cancelled because the outgoing data packet piggybacks the latest cumulative ACK and receive window.¶
Keepalive probes (empty ACKs) are sent every 30 seconds to idle connections. Connections idle for 120 seconds are automatically closed. These timers are appropriate for the overlay's use case (agent communication), where stale connections should be reclaimed promptly.¶
On startup, the daemon sends a UDP probe to the beacon. The beacon observes the daemon's public IP address and port (as mapped by NAT) and reports it back. This follows the mechanism described in [RFC8489] (Session Traversal Utilities for NAT).¶
The discovered public endpoint is registered with the registry as the daemon's locator.¶
For daemons with known public endpoints (e.g., cloud VMs), the
-endpoint host:port flag skips STUN and registers the specified
endpoint directly.¶
When daemon A wants to reach daemon B and both are behind NAT:¶
Daemon A sends a punch request to the beacon, specifying B's Node ID.¶
The beacon looks up B's registered endpoint and sends a punch command to both A and B, instructing each to send a UDP packet to the other's observed endpoint.¶
Both daemons send UDP packets to each other simultaneously, punching holes in their respective NATs.¶
Subsequent packets flow directly between A and B.¶
This works for Full Cone, Restricted Cone, and Port-Restricted Cone NAT types.¶
When hole punching fails (typically Symmetric NAT, where the mapped port changes per destination), the beacon provides transparent relay:¶
+----------+ +----------+ +----------+ | Daemon A | ------> | Beacon | ------> | Daemon B | +----------+ relay +----------+ relay +----------+¶
The relay frame format:¶
+------+----------+----------+---...---+ | 0x05 | SenderID | DestID | Payload | +------+----------+----------+---...---+ 1 byte 4 bytes 4 bytes variable¶
The beacon unwraps the relay header and forwards the payload to the destination daemon. Relay is transparent to the session layer --- the virtual packet inside the relay frame is identical to a directly-delivered packet.¶
When dialing a remote daemon, the connection strategy is:¶
Attempt 3 direct UDP sends to the peer's registered endpoint.¶
If all 3 fail, switch to relay mode through the beacon.¶
Attempt 3 relay sends.¶
If all relay attempts fail, return an error to the application.¶
The switch from direct to relay is automatic and transparent to the application layer.¶
Each node receives an Ed25519 [RFC8032] keypair from the registry upon registration. The private key serves as the node's identity credential. The registry holds all public keys and can verify signatures.¶
Identities may be persisted to disk so that a node retains its keypair and virtual address across restarts. On restart with a persisted identity, the daemon re-registers with the stored public key and the registry restores the node's address and memberships.¶
Tunnel encryption is enabled by default. On startup, each daemon generates an ephemeral X25519 [RFC7748] keypair. When two daemons first communicate, they exchange public keys via PILK (Section 7.3) or PILA (Section 7.4) frames, compute an ECDH shared secret, and establish an AES-256-GCM [RFC5116] cipher.¶
All subsequent packets between the pair are encrypted (PILS frames), regardless of virtual port. The encryption is at the tunnel layer --- it protects all overlay traffic between two daemons, including connection handshakes.¶
Tunnel encryption is backward-compatible: if a peer does not respond to key exchange, communication falls back to plaintext (PILT frames).¶
When a daemon has a persisted Ed25519 identity, the key exchange is upgraded from PILK to PILA (see Section 7.4). The Ed25519 signature binds the ephemeral X25519 key to the node's persistent identity, preventing man-in-the-middle attacks.¶
Implementations SHOULD use PILA when an Ed25519 identity is available.¶
Virtual port 443 provides end-to-end encryption between two agents, on top of any tunnel-layer encryption. The agents perform an X25519 ECDH handshake to derive a shared secret, then use AES-256-GCM for all subsequent data.¶
Each encrypted frame:¶
[4-byte length][12-byte nonce][ciphertext + 16-byte GCM tag]¶
This provides defense in depth: even if the tunnel encryption is compromised (e.g., by a compromised intermediate daemon in a future multi-hop topology), port 443 data remains protected.¶
Port 444 implements a bilateral trust negotiation protocol. Two agents exchange trust requests with justification strings and must both approve before a trust relationship is established.¶
Three auto-approval paths exist:¶
Mutual handshake: If both agents independently request trust with each other, the relationship is auto-approved.¶
Network trust: If both agents share a non-backbone network, the relationship is auto-approved (network membership serves as a trust signal).¶
Manual approval: If neither condition is met, the request is queued for the receiving agent's operator to approve or reject.¶
Trust pairs are recorded in the registry and persist across restarts. Trust is revocable: revoking trust immediately prevents further communication.¶
Agents are private by default:¶
A node's physical IP:port is never disclosed in registry responses unless the node has explicitly opted into public visibility.¶
Resolving a private node's endpoint requires one of: (a) the node is public, (b) a mutual trust pair exists, or (c) both nodes share a non-backbone network.¶
Listing nodes on the backbone (network 0) is rejected by the registry. Non-backbone networks allow listing since membership is the trust boundary.¶
The registry enforces per-connection sliding window rate limits using a token-bucket algorithm with per-source tracking. Clients that exceed the limit receive throttle responses.¶
Daemons implement SYN rate limiting to mitigate connection flood attacks.¶
The daemon's Unix domain socket is created with mode 0600, restricting access to the socket owner. This prevents unprivileged processes on the same machine from issuing commands to the daemon.¶
AES-256-GCM nonces are 96 bits (12 bytes), constructed as:¶
+---...---+---...---+ | Prefix | Counter | +---...---+---...---+ 4 bytes 8 bytes¶
4 bytes generated from a cryptographically secure random source when the tunnel session is established. Unique per session with overwhelming probability.¶
8-byte unsigned integer, starting at 0, incremented by 1 for each packet encrypted. The counter MUST NOT be reset within a session.¶
A new tunnel session is established when two daemons perform an X25519 key exchange (PILK or PILA). Each session produces:¶
Since each session uses a different key, nonces from different sessions cannot collide (different keys are independent encryption contexts).¶
The 8-byte counter supports 2^64 encryptions per session. Implementations MUST re-key (initiate a new key exchange) before the counter reaches 2^64 - 1. In practice, at 1 million packets per second, counter exhaustion would take over 584,000 years.¶
Secure connections on port 443 use a separate nonce scheme: a monotonically increasing 8-byte counter zero-padded to 12 bytes. Each connection has an independent counter and key derived from its own X25519 handshake.¶
The 4-bit Version field in the packet header identifies the protocol version. The current version is 1. Version 0 is reserved and MUST NOT be used.¶
The initiator includes its protocol version in the SYN packet. The responder checks the version:¶
If supported: echoes the same version in SYN-ACK. Both sides use this version for the connection's lifetime.¶
If unsupported: sends RST. No version downgrade negotiation occurs.¶
For non-SYN packets, if the Version field does not match the connection's established version, the packet is silently discarded. Implementations SHOULD log such events at debug level.¶
Future protocol versions MAY extend the header format. Implementations MUST NOT assume a fixed header size based solely on the Version field --- they SHOULD use the version to determine the expected header layout.¶
The total per-packet overhead for encrypted tunnel frames is:¶
| Component | Size |
|---|---|
| PILS magic | 4 bytes |
| Sender Node ID | 4 bytes |
| GCM nonce | 12 bytes |
| Pilot header | 34 bytes |
| GCM authentication tag | 16 bytes |
| Total | 70 bytes |
For plaintext frames (PILT), overhead is 38 bytes (4-byte magic + 34-byte header).¶
With a typical 1500-byte Ethernet MTU, 20-byte IP header, and 8-byte UDP header:¶
The default MSS of 4096 bytes exceeds single-packet capacity on standard Ethernet paths. Full-MSS segments will be fragmented into 3 IP fragments. This is acceptable on most networks but may fail on paths that block IP fragmentation.¶
Recommendations:¶
For Internet-facing deployments where IP fragmentation may be blocked, an MSS of 1400 bytes avoids fragmentation on virtually all paths.¶
For datacenter or local deployments (jumbo frames), the default 4096 MSS is appropriate.¶
Implementations SHOULD provide a configurable MSS option.¶
Implementations SHOULD NOT set the Don't Fragment (DF) bit on UDP datagrams, allowing IP-layer fragmentation as a fallback.¶
The echo service reflects any data received back to the sender. It is used for liveness testing (ping) and throughput benchmarking.¶
A typed frame protocol for structured data. Each frame carries a 4-byte type tag and a 4-byte length prefix:¶
| Type | Value | Description |
|---|---|---|
| Text | 0x01 | UTF-8 text |
| Binary | 0x02 | Raw bytes |
| JSON | 0x03 | JSON document |
| File | 0x04 | File with name metadata |
A publish/subscribe broker. Agents subscribe to named topics and receive
events published by any peer. Wildcard subscriptions (*) match all
topics. The wire protocol uses newline-delimited text commands:¶
A task lifecycle protocol. Agents submit tasks with descriptions, workers accept or decline, execute, and return results. A reputation score (polo score) adjusts based on execution efficiency.¶
The daemon and driver communicate over a Unix domain socket using length-prefixed messages:¶
[4-byte big-endian length][message bytes]¶
Maximum message size: 1,048,576 bytes (1 MB).¶
| Cmd | Name | Direction | Description |
|---|---|---|---|
| 0x01 | Bind | Driver -> Daemon | Bind a virtual port |
| 0x02 | BindOK | Daemon -> Driver | Confirm port binding |
| 0x03 | Dial | Driver -> Daemon | Connect to remote agent |
| 0x04 | DialOK | Daemon -> Driver | Connection established |
| 0x05 | Accept | Daemon -> Driver | Incoming connection |
| 0x06 | Send | Driver -> Daemon | Send data on connection |
| 0x07 | Recv | Daemon -> Driver | Receive data |
| 0x08 | Close | Driver -> Daemon | Close connection |
| 0x09 | CloseOK | Daemon -> Driver | Connection closed |
| 0x0A | Error | Daemon -> Driver | Error response |
| 0x0B | SendTo | Driver -> Daemon | Send datagram |
| 0x0C | RecvFrom | Daemon -> Driver | Receive datagram |
| 0x0D | Info | Driver -> Daemon | Query daemon status |
| 0x0E | InfoOK | Daemon -> Driver | Status response (JSON) |
| 0x0F | Handshake | Driver -> Daemon | Trust handshake command |
| 0x10 | HandshakeOK | Daemon -> Driver | Handshake result (JSON) |
The packet checksum uses CRC32 (IEEE polynomial), which detects accidental corruption but provides no cryptographic integrity. An attacker who can modify packets in transit can recompute a valid CRC32. Integrity against active attackers is provided by tunnel-layer AES-256-GCM encryption, which MUST be used for all Internet-facing deployments.¶
The PILK key exchange frame provides no identity binding. An active man-in-the-middle attacker can substitute their own X25519 public key, establishing separate encrypted sessions with each peer. The PILA authenticated key exchange (Section 7.4) prevents this by binding the ephemeral key to an Ed25519 identity. Implementations SHOULD use PILA whenever an Ed25519 identity is available.¶
The registry is a centralized trusted third party. Compromise of the registry could allow:¶
Address hijacking (reassigning a node's virtual address)¶
Locator spoofing (returning incorrect IP:port for a node)¶
Public key substitution (enabling identity impersonation)¶
Metadata harvesting (enumerating registered nodes)¶
Mitigations include TLS transport for registry connections, admin token authentication for write operations, and hot-standby replication for availability. Future work should explore distributed registry designs with consensus-based replication.¶
AES-256-GCM security depends critically on nonce uniqueness under the same key. The nonce construction (Section 11) guarantees uniqueness through a random prefix (unique per session) and a monotonic counter (never reset within a session). Since each key exchange produces a new key, nonces from different sessions are in independent cryptographic contexts.¶
Implementations MUST NOT reuse nonces. Implementations MUST NOT reset the counter within a session. Implementations MUST re-key before counter exhaustion.¶
Even with tunnel encryption (PILS), the sender's Node ID is transmitted in cleartext (it is needed for the receiver to look up the decryption key). This allows a passive observer to determine which daemons are communicating, though the content and virtual addressing within the encrypted payload remain confidential.¶
Pilot Protocol implements congestion control at the overlay layer, while the underlay UDP-over-IP path may also be subject to network-level congestion signals (ICMP source quench, ECN). The overlay congestion control operates independently, which may lead to suboptimal behavior on heavily congested paths. This is a known issue shared with all overlay transport protocols.¶
Tunnel-layer AES-256-GCM provides implicit replay protection: GCM authentication will fail for replayed packets if the receiver tracks seen nonces. However, the current specification does not mandate a replay window. Implementations SHOULD track recently seen nonces and discard duplicates.¶
The Unix domain socket IPC between daemon and driver is a trust boundary. The daemon trusts that any process connecting to the socket is authorized (enforced by filesystem permissions, mode 0600). If an attacker gains access to the socket, they can impersonate the local agent. Deployments SHOULD ensure the daemon runs under a dedicated user account.¶
This document requests the creation of a "Pilot Protocol Tunnel Magic Values" registry with the following initial entries:¶
| Magic | Hex | Description |
|---|---|---|
| PILT | 0x50494C54 | Plaintext frame |
| PILS | 0x50494C53 | Encrypted frame |
| PILK | 0x50494C4B | Key exchange frame |
| PILA | 0x50494C41 | Authenticated key exchange frame |
This document requests the creation of a "Pilot Protocol Type Values" registry with the following initial entries:¶
| Value | Name | Description |
|---|---|---|
| 0x01 | Stream | Reliable, ordered delivery |
| 0x02 | Datagram | Unreliable, unordered delivery |
| 0x03 | Control | Internal control messages |
This document requests the creation of a "Pilot Protocol Well-Known Ports" registry with the following initial entries:¶
| Port | Service | Description |
|---|---|---|
| 0 | Ping | Liveness checks |
| 1 | Control | Daemon-to-daemon control |
| 7 | Echo | Echo service |
| 53 | Name Resolution | Nameserver |
| 80 | Agent HTTP | Web endpoints |
| 443 | Secure | End-to-end encrypted channel |
| 444 | Trust | Trust handshake protocol |
| 1000 | StdIO | Text stream |
| 1001 | DataExchange | Typed frame protocol |
| 1002 | EventStream | Pub/sub broker |
| 1003 | TaskSubmit | Task lifecycle |
Per [RFC7942], this section documents the known implementations of Pilot Protocol at the time of writing.¶
Vulture Labs¶
Complete implementation of Pilot Protocol including daemon, driver SDK, registry, beacon, nameserver, gateway, and CLI (pilotctl). Implemented in Go with zero external dependencies.¶
Production-ready for experimental deployments.¶
All features specified in this document are implemented, including tunnel encryption (PILK/PILA/PILS), SACK, congestion control, flow control, Nagle's algorithm, automatic segmentation, NAT traversal (STUN, hole-punch, relay), trust handshake protocol, privacy model, and all built-in services.¶
226+ tests (202 PASS, 24 SKIP). Integration tests validated across 5 GCP regions (US Central, US East, Europe West, US West, Asia East) with both public-IP and NAT-only topologies.¶
Proprietary.¶
calin@vulturelabs.com¶
Vulture Labs¶
Python client SDK using ctypes FFI to the Go shared library. Published
on PyPI as pilotprotocol.¶
Beta.¶
Driver operations (dial, listen, accept, send, receive, close), datagram support, info queries.¶
Proprietary.¶
calin@vulturelabs.com¶
The author thanks the participants of the IETF AI protocols discussions for their contributions to the understanding of the agent communication landscape.¶
A SYN packet from 0:0000.0000.0001 port 49152 to 0:0000.0000.0002
port 1000, with no payload:¶
Byte 0: 0x11 (version=1, flags=SYN) Byte 1: 0x01 (protocol=Stream) Byte 2-3: 0x0000 (payload length=0) Byte 4-5: 0x0000 (src network=0) Byte 6-9: 0x00000001 (src node=1) Byte 10-11: 0x0000 (dst network=0) Byte 12-15: 0x00000002 (dst node=2) Byte 16-17: 0xC000 (src port=49152) Byte 18-19: 0x03E8 (dst port=1000) Byte 20-23: 0x00000000 (seq=0) Byte 24-27: 0x00000000 (ack=0) Byte 28-29: 0x0200 (window=512 segments) Byte 30-33: [CRC32] (computed over header)¶
Total: 34 bytes.¶
An ACK data packet with 5-byte payload "hello":¶
Byte 0: 0x12 (version=1, flags=ACK)
Byte 1: 0x01 (protocol=Stream)
Byte 2-3: 0x0005 (payload length=5)
...
Byte 28-29: 0x01F6 (window=502 segments)
Byte 30-33: [CRC32] (computed over header + payload)
Byte 34-38: 0x68656C6C6F ("hello")
¶
Total: 39 bytes.¶
A PILS frame carrying an encrypted Pilot packet:¶
Byte 0-3: 0x50494C53 (magic="PILS") Byte 4-7: 0x00000001 (sender node ID=1) Byte 8-19: [12-byte nonce] Byte 20+: [ciphertext + 16-byte GCM tag]¶