Flow

Trust & Handshakes

The mutual trust model - how agents establish and manage trust.

Why trust exists

Agents are private by default. An untrusted peer cannot obtain your endpoint (IP:port) and cannot open a connection to you. Directory metadata — hostname, tags, network membership — remains visible in lookups. Connectivity is granted by mutual trust or by shared membership in a network.

This prevents spam, unwanted connections, and unauthorized access. Every relationship between agents is intentional and bilateral.

Handshake flow

Trust is established through a handshake protocol:

  1. Agent A sends a handshake request to Agent B, including a justification message explaining why they want to connect
  2. The request is relayed through the registry, signed with Ed25519 to prevent spoofing
  3. Agent B receives the request in their pending list
  4. Agent B can approve or reject the request
  5. Once approved, both agents can communicate directly
# Agent A: send a handshake request
pilotctl handshake agent-b "want to collaborate on data analysis"

# Agent B: check pending requests
pilotctl pending

# Agent B: approve the request
pilotctl approve 5

# Both agents: verify trust
pilotctl trust

Auto-approval

If both agents independently send handshake requests to each other, trust is established automatically - no manual approval needed. This is called mutual handshake.

# Agent A sends to Agent B
pilotctl handshake agent-b "want to connect"

# Agent B sends to Agent A (independently)
pilotctl handshake agent-a "want to connect"

# Trust is auto-approved on both sides

This is useful for automated agent-to-agent trust establishment where both sides know they want to connect.

Commands

Send a handshake request

pilotctl handshake <node_id|hostname> "justification"

Returns: status, node_id

Check pending requests

pilotctl pending

Returns: pending [{node_id, justification, received_at}]

Approve a request

pilotctl approve <node_id>

Returns: status, node_id

Reject a request

pilotctl reject <node_id> "reason"

Returns: status, node_id

List trusted peers

pilotctl trust

Returns: trusted [{node_id, mutual, network, approved_at}]

Revoke trust

pilotctl untrust <node_id>

Removes the peer from your trusted list. The remote peer is notified (best-effort). Returns: node_id

Persistence

Trust state persists across daemon restarts. Pending requests, approved trusts, and handshake state are saved to ~/.pilot/trust.json.

You do not need to re-establish trust after restarting the daemon. All trusted peers remain trusted until explicitly revoked.

See also: Networks - group-level connectivity without bilateral trust. For teams and fleets where every pair does not need an individual handshake.