Flow

Built-in Services

Three services run automatically when the daemon starts - no extra binaries needed.

Choosing the right service

Each built-in service handles a different communication pattern. Pick the one that matches your need:

NeedServicePort
Liveness check / latency measurementEcho7
Send a message to someone's inbox or transfer a fileData Exchange1001
Real-time event streaming with topic filteringEvent Stream1002

For interactive request-response (send a message, get a reply), use connect or send on port 1000 (stdio) instead - those are stream connections, not a built-in service.

Echo (port 7)

The echo service reflects back any data sent to it. Used for liveness probes, latency measurement, and throughput benchmarks.

# Ping (uses echo port internally)
pilotctl ping other-agent

# Throughput benchmark (sends data through echo)
pilotctl bench other-agent 10   # 10 MB

The echo service is zero-config - it accepts connections and echoes data back. No application logic.

Data Exchange (port 1001)

A typed frame protocol that handles structured data transfer. Messages arrive in the recipient's ~/.pilot/inbox/, files in ~/.pilot/received/. Both persist until the recipient reads or clears them - delivery survives disconnections.

Frame types

TypeIDDescription
Text1Plain text messages
Binary2Raw binary data
JSON3Structured JSON payloads
File4File transfer with metadata (filename embedded in payload)

Wire format

Each frame is: [4-byte type][4-byte length][payload]. For file frames, the payload contains an additional header: [2-byte name length][name bytes][file data]. Maximum payload size is 16 MB.

Messages

pilotctl send-message other-agent --data "task complete"
pilotctl send-message other-agent --data '{"result":42}' --type json

Files

pilotctl send-file other-agent ./report.pdf

Inspecting the mailbox

pilotctl inbox       # List messages
pilotctl received    # List files

See Messaging for full details on message types, inbox format, and file transfer.

Event Stream (port 1002)

A pub/sub broker with topic filtering and wildcards. Each daemon runs its own independent broker - there is no central message server. Subscribers connect to the publisher's daemon, and the broker distributes events to all active subscribers on that node.

# Subscribe to status events
pilotctl subscribe other-agent status --count 5

# Publish a status event
pilotctl publish other-agent status --data "processing complete"

Delivery is at-most-once - events go only to currently connected subscribers. No persistence, no replay. See the Pub/Sub page for architecture details, delivery guarantees, topic conventions, and wildcard syntax.

Custom services

The four services above are just the built-in ones. You can listen on any port using the Go or Python SDK to build custom services. The daemon routes incoming connections to your handler based on the destination port number.

# Example: listen on port 3000 using the Go SDK
listener := daemon.Listen(3000)
conn, _ := listener.Accept()

See the Go SDK and Python SDK for details on building custom services.

Disabling services

Each built-in service can be disabled when running the standalone daemon binary:

daemon --no-echo          # Disable echo (port 7)
daemon --no-dataexchange   # Disable data exchange (port 1001)
daemon --no-eventstream    # Disable event stream (port 1002)

These flags are available on the standalone daemon binary (see Daemon flags). They are not available via pilotctl daemon start.

Disabling a service means the daemon will not accept connections on that port. Other nodes trying to connect to a disabled service will get a connection error.