Flow

Configuration

Config files, environment variables, directory structure, and daemon flags.

Config file

Configuration is stored in ~/.pilot/config.json:

{
  "registry": "34.71.57.205:9000",
  "beacon": "34.71.57.205:9001",
  "hostname": "my-agent",
  "email": "user@example.com",
  "socket": "/tmp/pilot.sock",
  "webhook": "http://localhost:8080/events"
}

CLI flags override environment variables, which override config file values. The config file is created by pilotctl init and can be updated with pilotctl config --set.

Config commands

Initialize

pilotctl init --hostname my-agent

Creates ~/.pilot/config.json with the specified settings.

View config

pilotctl config

Set a value

pilotctl config --set registry=host:9000
pilotctl config --set hostname=new-name

Environment variables

VariableDefaultDescription
PILOT_SOCKET/tmp/pilot.sockPath to the daemon IPC socket
PILOT_REGISTRY34.71.57.205:9000Registry server address
PILOT_BEACON34.71.57.205:9001Beacon server address (used for STUN, NAT punch, and relay)
PILOT_DAEMON_BIN(auto-discovered)Override path to the pilot-daemon binary (otherwise pilotctl looks next to itself, then in $PATH)
PILOT_GATEWAY_BIN(auto-discovered)Override path to the pilot-gateway binary
PILOT_HOSTNAME(none)Hostname to set during install. If unset, the node is assigned an internal hostname of the form pilot-XXXXXXXX (8 hex chars = first 4 bytes of SHA-256(public_key))
PILOT_ADMIN_TOKEN(none)Admin token for enterprise operations
PILOT_HOME~/.pilotDirectory where pilot stores identity, config, and received files
PILOT_EMAIL(none)Email address used for first-time daemon registration (same as --email flag)
PILOT_RC(none)Path to a shell RC snippet sourced by the daemon on startup

Directory structure

~/.pilot/
  bin/                # Installed binaries (pilot-daemon, pilotctl, pilot-gateway, pilot-updater)
  bin/.pilot-version  # Current version (used by auto-updater)
  config.json         # Configuration file
  identity.json       # Ed25519 keypair (persistent identity)
  trust.json          # Trust state (trusted peers, pending requests)
  setups/             # Setup manifests (role identity files)
  received/           # Files received via data exchange
  inbox/              # Messages received via data exchange
  pilot.pid           # Daemon PID file
  pilot.log           # Daemon log file
  updater.log         # Auto-updater log file

Daemon flags

These flags forward from pilotctl daemon start to the underlying pilot-daemon binary.

FlagDescription
--registry <addr>Registry server address
--beacon <addr>Beacon server address (STUN)
--listen <addr>Local UDP listen address (default: :0)
--endpoint <addr>Fixed public endpoint for cloud VMs (skips STUN)
--identity <path>Path to identity key file
--email <addr>Email address for account identification and key recovery
--hostname <name>Register with this hostname
--publicStart as a public node
--no-encryptDisable tunnel encryption
--foregroundRun in the current process (don't fork)
--trust-auto-approveAuto-approve every incoming trust handshake
--log-level <level>Log level: debug, info, warn, error
--log-format <fmt>Log format: text or json
--socket <path>IPC socket path (default /tmp/pilot.sock)
--config <path>Config file path
--webhook <url>Webhook URL for event notifications
--admin-token <token>Admin token for network create/admin operations
--networks <ids>Comma-separated network IDs to auto-join on startup
--wait <dur>How long to wait for the daemon to become ready (default 15s)

pilot-daemon-only tuning flags

The following flags accept tuning values but are only consumed when you invoke the pilot-daemon binary directly (for systemd unit files, container entrypoints, embedded driver harnesses, etc.). They are not forwarded by pilotctl daemon start; the daemon uses the defaults below.

FlagDefaultDescription
-keepalive <dur>30sKeepalive probe interval
-idle-timeout <dur>120sIdle connection timeout
-syn-rate-limit <n>100Max SYN packets per second
-max-conns-per-port <n>1024Max connections per port
-max-conns-total <n>4096Max total connections
-time-wait <dur>10sTIME_WAIT duration
-registry-tlsfalseEnable TLS for registry connection
-registry-fingerprint <hex>(none)SHA-256 fingerprint of registry TLS cert
-no-echofalseDisable the built-in echo service (port 7)
-no-dataexchangefalseDisable the built-in data exchange (port 1001)
-dataexchange-b64falseInclude a lossless data_b64 field alongside data in inbox messages — opt in when payloads are binary (e.g. zlib-compressed envelopes)
-no-eventstreamfalseDisable the built-in event stream (port 1002)
-relay-onlyfalseHide real_addr from peers; reach only via beacon-relay
-transport <mode>udpTunnel transport: udp (default — binds a UDP socket, today's behavior) or compat (opt-in — tunnels Pilot packets over WSS to the beacon for daemons in UDP-blocked environments such as Docker on Render/Railway/Vercel/Lambda). See Running pilot behind a firewall.
-compat-beacon <url>wss://beacon.pilotprotocol.network/v1/compatWSS endpoint used when -transport=compat
-tls-trust <mode>systemCompat-mode TLS trust store: system (default — OS trust store; matches the public beacon's Let's Encrypt cert) or pinned (Pilot CA root embedded in the daemon binary; rejects any cert not signed by it). Default will flip back to pinned in a future release once the production Pilot CA root ships embedded in client binaries. End-to-end Ed25519 protects payload identity in both modes.
-fake-listen-addr <addr>(none)Advertise this listen_addr to the registry instead of the real one

Logging

The daemon uses structured logging via Go's slog package. Logs are written to ~/.pilot/pilot.log.

# Debug logging
pilotctl daemon start --log-level debug

# JSON log format (for log aggregation)
pilotctl daemon start --log-format json

# View logs
tail -f ~/.pilot/pilot.log

Log levels: debug, info (default), warn, error

Setup manifests

When a setup skill configures this agent for a specific role, it writes a setup manifest to ~/.pilot/setups/<slug>.json. This file persists the role configuration so the agent knows its identity, which skills to use and how, which peers exist, and what data flows to expect.

{
  "setup": "fleet-health-monitor",
  "setup_name": "Fleet Health Monitor",
  "role": "web-monitor",
  "role_name": "Web Server Monitor",
  "hostname": "acme-web-monitor",
  "description": "Watches nginx/app health, CPU, memory, response times.",
  "skills": {
    "pilot-health": "Check nginx, app endpoints, SSL certs.",
    "pilot-alert": "Publish alerts to acme-alert-hub on health-alert.",
    "pilot-metrics": "Collect CPU, memory, disk, response time."
  },
  "peers": [
    {
      "role": "alert-hub",
      "hostname": "acme-alert-hub",
      "description": "Central alert aggregator"
    }
  ],
  "data_flows": [
    {
      "direction": "send",
      "peer": "acme-alert-hub",
      "port": 1002,
      "topic": "health-alert",
      "description": "Health check failures"
    }
  ],
  "handshakes_needed": ["acme-alert-hub"]
}

Manifest fields

FieldTypeDescription
setupstringSetup slug (matches the filename)
setup_namestringHuman-readable setup name
rolestringThis agent's role ID within the setup
role_namestringHuman-readable role name
hostnamestringThis agent's hostname
descriptionstringWhat this agent does in context
skillsmapSkill name → contextual description of what it does in this role
peersarrayAll peer agents in the setup (even indirect ones)
data_flowsarrayDirectional data flows (send/receive) with port and topic
handshakes_neededarrayHostnames of peers that need direct trust (handshakes)

The manifest is a convention - the AI agent writes it during setup and reads it when it needs to act. No daemon or CLI changes are required.