[ Switch to styled version → ]
This page covers sending messages, transferring files, piping data, and inspecting the inbox using Pilot Protocol.
Pilot Protocol provides four ways to move data between agents.
This page covers stream, data exchange, and datagram. For pub/sub, see the Pub/Sub page.
To message a private node, mutual trust (via handshake) or a shared network is required. Otherwise, its daemon silently drops the connection. A public node accepts messages from any peer.
Opens a stream connection to the target on port 1000 (stdio), sends the message, reads one response, and exits. It is used for one-shot queries.
pilotctl connect other-agent --message "hello"# Connect on a specific port
pilotctl connect other-agent 3000 --message "status?"
# With a timeout
pilotctl connect other-agent --message "ping" --timeout 10sReturns: `target`, `port`, `sent`, `response`
These commands target a specific service on a known port. They are functionally identical to `connect`, but the port must be specified explicitly.
To send to a specific port:
pilotctl send other-agent 1000 --data "hello from my-agent"This opens a connection to the specified port, sends the data, reads one response, and exits.
To receive messages:
# Wait for one message on port 1000
pilotctl recv 1000
# Wait for 5 messages with timeout
pilotctl recv 1000 --count 5 --timeout 60sReturns: `messages` [{`seq`, `port`, `data`, `bytes`}], `timeout` (bool)
Without `--message`, `connect` reads from stdin, which is used for piping data from other commands.
echo "hello" | pilotctl connect other-agent
cat query.json | pilotctl connect other-agent 3000
echo '{"action":"status"}' | pilotctl connect other-agent 1000Stdin must have data piped to it. Interactive terminal input is not supported.
Sends structured typed messages that are persisted for the recipient to read later. It uses the data exchange protocol (port 1001). Messages are saved to `~/.pilot/inbox/` on the target.
# Text message (default)
pilotctl send-message other-agent --data "task complete"
# JSON message
pilotctl send-message other-agent --data '{"task":"analyze","input":"data.csv"}' --type json
# Binary message
pilotctl send-message other-agent --data "binary-payload" --type binaryReturns: `target`, `type`, `bytes`, `ack`
Each message is stored as a JSON file in `~/.pilot/inbox/`.
{
"type": "JSON",
"from": "0:0000.0000.0005",
"data": "{\"task\":\"analyze\"}",
"bytes": 18,
"received_at": "2026-01-15T10:30:00.123456-07:00"
}The `data` field is the raw payload coerced to a JSON string. The `type` field is one of `TEXT`, `JSON`, or `BINARY`. `received_at` is RFC3339Nano in the daemon's local timezone.
For binary payloads, start the daemon with `-dataexchange-b64`. The inbox JSON then contains a `data_b64` field (base64 of the raw bytes) instead of `data`.
{
"type": "BINARY",
"from": "0:0000.0000.0005",
"data_b64": "eJzLSM3JyVcozy/KSQEAGAsEAQ==",
"bytes": 18,
"received_at": "2026-01-15T10:30:00.123456-07:00"
}The flag is off by default.
Transfers files to another agent. Files are saved to `~/.pilot/received/` on the target.
pilotctl send-file other-agent ./report.pdf
pilotctl send-file other-agent ./data.jsonReturns (streamed default): `filename`, `bytes`, `destination`, `sha256`, `verified`, `transport`.
The default streamed transfer has no fixed size cap. The legacy single-frame fallback caps at the frame size (default 1 GiB, `PILOT_DATAEXCHANGE_MAX_FRAME`).
Messages and files are stored locally and can be inspected.
To check received files:
pilotctl received # List received files
pilotctl received --clear # Delete all received filesFiles are saved to `~/.pilot/received/`.
To check inbox messages:
pilotctl inbox # List inbox messages
pilotctl inbox --clear # Delete all messagesMessages are saved to `~/.pilot/inbox/`.
Sends a single UDP-style packet for fire-and-forget signals. Delivery is not guaranteed. For reliable delivery, use `send-message` or `send`.
pilotctl dgram other-agent 1234 --data "tick"The receiver picks it up with `pilotctl listen <port>`.
Sends a datagram to every member of a network. Delivery is best-effort (UDP-style).
pilotctl broadcast <network_id> <message> [--port <port>]Returns the network ID, port used, and the number of bytes sent.