You have two agents. One produces live data — a price ticker, a sensor reading, a stream of inference output — and the other needs to consume it as it happens. The obvious move is a TCP stream, and for a lot of cases that's fine. But for unidirectional feeds, TCP drags in machinery you never use: backpressure you have to handle, head-of-line blocking you have to explain, connection state you have to babysit. Streaming live data from one agent to another over UDP is often the simpler fit — if you deal with the three things raw UDP leaves on the table.
This post is a tutorial for that pattern: one agent pushes live data, another consumes it, over a lightweight transport instead of a TCP-based stream. I'll cover when the trade-off makes sense, what you lose by going bare UDP, and a concrete setup where the transport is already handled for you.
Why stream live data from one agent to another over UDP
UDP is a datagram protocol. No connection, no ordering guarantee, no retransmission — you hand a packet to the socket and it goes. That sounds like a bug list, but for live feeds it's exactly the semantics you want:
- Price tickers. A stale tick is worse than a missed tick. If the network drops one update, the next one supersedes it anyway. Retransmitting the old price after the new one arrived is actively harmful.
- Sensor readings. A temperature sample from ten seconds ago is not interesting. Consumers want the latest reading, not a guaranteed delivery of every reading.
- Inference output. Streaming tokens from a model — if one chunk is lost, the stream keeps going; you don't want the pipeline to stall waiting for a retransmit.
All three share a shape: the latest value matters more than every value. That is the signature of a unidirectional feed, and it's where TCP's guarantees stop being guarantees and start being overhead.
When a unidirectional feed beats a TCP stream
TCP gives you two things: ordering and retransmission. For a one-way data feed, both can work against you.
Ordering means head-of-line blocking: one dropped segment stalls every segment behind it, even the ones that arrived fine. Retransmission means a consumer can receive a stale datagram after a fresher one — which, for a ticker, is worse than silence.
The fix isn't "use TCP anyway." It's to notice that you don't need transport-level ordering at all. Put a sequence number in each datagram, and let the consumer decide what to do with gaps — skip them, log them, or request a snapshot. That's the classic pattern, and it keeps the transport dumb and fast.
What raw UDP doesn't give you is anything else. And that's the catch.
The three problems raw UDP leaves you with
If you stream over plain UDP sockets, you're on the hook for everything around the datagram:
- Addressing. The producer needs a reachable address for the consumer. The moment either agent is behind NAT, moves across clouds, or restarts with a new IP, your feed breaks. You end up building a rendezvous system — which is a whole project.
- Encryption. Datagrams are plaintext on the wire. For market data or anything proprietary, that's a non-starter. You'd be hand-rolling a key exchange and per-packet authenticated encryption.
- NAT traversal. Consumer behind a home router, producer in a VPC — no socket you open will connect without hole punching or a relay. Doing this reliably is days of work, and it's the same work for every feed you build.
These three problems are the reason most people give up and go back to TCP-based streaming with a broker in the middle. But there's a middle path: keep the unidirectional, latest-value-wins design, and let an overlay network carry the datagrams.
Streaming between agents with encrypted UDP tunnels
Pilot Protocol is an open-source overlay network for AI agents (Go, no external dependencies, AGPL-3.0). The relevant part here is the transport: agents talk over encrypted UDP tunnels — X25519 key exchange with AES-256-GCM for tunnel traffic — and the network handles NAT traversal for you (STUN discovery, hole punching, and a relay fallback when a direct path isn't possible). Every agent gets a permanent virtual address that survives restarts and IP changes.
That removes all three problems at once. Your producer and consumer each run a daemon, trust each other with a one-time handshake, and then stream to each other by name — no IPs, no port forwarding, no TLS certs, no VPN.
For unidirectional feeds specifically, the daemon runs an event stream broker that fits the pattern exactly: the producer publishes events to a topic, the broker fans them out to subscribers. One-way by construction — the publisher never tracks who's listening.
# on the consumer agent: collect the next 5 events, give up after 60s
pilotctl subscribe market-agent ticks --count 5 --timeout 60s
# on the producer agent: push an event to that topic
pilotctl publish market-agent ticks --data '{"sensor":"rack-3","temp":61}'
The subscription streams as NDJSON — one JSON object per line — or you can drop --count and stream indefinitely. Wildcards work too: pilotctl subscribe market-agent "*" --count 10 subscribes to every topic on that agent.
Notice what you didn't write: no socket setup, no connection lifecycle, no retry loop for NAT timeouts, no encryption code. The transport is UDP under the hood, but the plumbing is the daemon's job.
Design notes for fire-and-forget feeds
Whatever transport you end up on, a unidirectional feed earns its keep with a few conventions:
- Sequence numbers. Stamp every datagram so the consumer can detect gaps. With a feed, gaps are information — a gap pattern can mean the producer is overloaded or the path is lossy.
- Timestamps and staleness. Include a timestamp and let the consumer drop anything older than its tolerance. A ticker consumer that applies a 30-second-old price has a bug, not a feature.
- Snapshots over retries. When a consumer detects it's too far behind, don't replay the stream — send the current state and resume. Latest-value-wins means a snapshot is the only retransmission that matters.
- Small payloads. UDP datagrams are happiest small. If your events are big, that's a sign the consumer wants a document, not a feed.
The same rules apply whether you're writing a raw socket loop or publishing to a broker — the design survives the transport.
Getting the feed running
For the overlay approach, install the daemon on both agents, register, and handshake once:
curl -fsSL https://pilotprotocol.network/install.sh | sh
Then it's the two commands above: pilotctl publish on the producer, pilotctl subscribe on the consumer. The full protocol details — transport, encryption, trust model, and the pub/sub semantics — are in the Pilot Protocol docs.
For a one-way live feed, the question isn't "TCP or UDP?" so much as "who maintains the connection?" If you're willing to own sockets, NAT, and encryption, raw UDP with sequence numbers is a fine, minimal design. If you'd rather ship the feed and not the plumbing, an overlay with encrypted UDP tunnels gets you the same unidirectional pattern without the operational tax — and your tickers, sensors, and inference streams just flow.
Top comments (0)