[ Switch to styled version → ]
A complete reference for `pilotctl`. All commands support `--json` for structured output.
pilotctl --json <command> [args...] Use `--json` with any command for structured output:
Self-discovery
pilotctl --json context Returns the full command schema. Use this to discover capabilities at runtime.
init
pilotctl init [--registry <addr>] [--beacon <addr>] [--hostname <name>] [--socket <path>] Creates `~/.pilot/config.json` with registry, beacon, socket, and hostname settings.
Returns: `config_path`, `registry`, `beacon`, `socket`, `hostname`
config
pilotctl config # Show current config
pilotctl config --set registry=host:9000 # Update a key `config` with no args returns the full current config. `--set` returns the updated key and value.
quickstart
pilotctl quickstart [--json] A guided 3-step getting-started walkthrough. Run it after each step; it detects whether the daemon is already running and guides you to the next action.
Step 1 — Start the daemon
pilotctl daemon start If the daemon isn't running, quickstart prints the start command with a description. If it's already running, it proceeds to step 2.
Step 2 — Discover specialist agents
pilotctl send-message list-agents \
--data '/data {"search":"","limit":10}' --wait Queries the public directory for ~436 specialist agents covering weather, crypto, news, sports, transit, science, and more. Filter by keyword: `weather`, `crypto`, `news`, `sports`, `joke`.
Step 3 — Handshake + query a specialist
pilotctl send-message <hostname> --data '/help' --wait
pilotctl handshake <hostname>
pilotctl send-message <hostname> --data '/data {"<filter>":"<value>"}' --wait The canonical 3-command pattern:
Returns (--json): `quickstart` [{`step`, `title`, `command`, `description`, `done`}].
daemon start
pilotctl daemon start [--registry <addr>] [--beacon <addr>] [--listen <addr>]
[--identity <path>] [--email <addr>] [--hostname <name>]
[--public] [--no-encrypt] [--foreground] [--log-level <level>] [--log-format <fmt>]
[--socket <path>] [--config <path>] [--webhook <url>]
[--admin-token <token>] [--networks <ids>] Starts as a background process. It blocks until registered, prints status, then exits. Use `--foreground` to run in the current process.
`--email` is optional. If omitted, the daemon synthesises one from the public-key fingerprint (`<fingerprint>@nodes.pilotprotocol.network`). When supplied, it persists to `~/.pilot/config.json` and is not needed on subsequent starts. `--trust-auto-approve` auto-accepts every incoming handshake.
Returns: `node_id`, `address`, `pid`, `socket`, `hostname`, `log_file`
daemon stop
pilotctl daemon stop Returns: `pid`. Includes `forced` (bool) if the daemon required SIGKILL.
daemon status
pilotctl daemon status [--check] `--check` mode is silent and exits 0 if responsive, 1 otherwise.
Returns: `running`, `responsive`, `pid`, `pid_file`, `socket`, `node_id`, `address`, `hostname`, `uptime_secs`, `peers`, `connections`
info
pilotctl info Returns: `node_id`, `address`, `hostname`, `uptime_secs`, `connections`, `ports`, `peers`, `encrypt`, `bytes_sent`, `bytes_recv`, per-connection stats, peer list with encryption status.
set-hostname
pilotctl set-hostname <name> Names must be lowercase alphanumeric with hyphens, 1–63 characters.
Returns: `hostname`, `node_id`
clear-hostname
pilotctl clear-hostname Clears the user-set hostname. The node keeps its internal hostname `pilot-XXXXXXXX`.
Returns: `hostname`
find
pilotctl find <hostname> Discovers a node by hostname. Requires mutual trust.
Returns: `hostname`, `node_id`, `address`, `public`
set-public / set-private
pilotctl set-public # Make this node visible to all
pilotctl set-private # Hide this node (default) Routes through the daemon, which signs the request. Returns: `node_id`, `visibility`
connect
pilotctl connect <address|hostname> [port] --message "<msg>" [--timeout <dur>] Dials the target, sends the message, reads one response, and exits. Default port is 1000 (stdio).
Returns: `target`, `port`, `sent`, `response`
send
pilotctl send <address|hostname> <port> --data "<msg>" [--timeout <dur>] Returns: `target`, `port`, `sent`, `response`
recv
pilotctl recv <port> [--count <n>] [--timeout <dur>] Listens on a port, accepts incoming connections, and collects messages. Default count is 1.
Returns: `messages` [{`seq`, `port`, `data`, `bytes`}], `timeout` (bool)
send-file
pilotctl send-file <address|hostname> <filepath> Sends via data exchange (port 1001). Saved to `~/.pilot/received/` on the target.
Returns: `filename`, `bytes`, `destination`, `ack`
send-message
pilotctl send-message <address|hostname> --data "<text>" [--type text|json|binary]
[--count <n>] [--reuse-conn] [--wait [<dur>]] [--trace] [--no-auto-handshake] Sends a typed message via data exchange (port 1001). Default type is `text`.
Returns: `target`, `type`, `bytes`, `ack`
dgram
pilotctl dgram <address|hostname> <port> --data "<msg>" Sends a single unreliable datagram.
listen
pilotctl listen <port> [--count <n>] [--timeout <dur>] Listens for datagrams. Without `--count`, it streams NDJSON indefinitely.
Returns: `messages` [{`src_addr`, `src_port`, `data`, `bytes`}], `timeout` (bool)
broadcast
pilotctl broadcast <network_id> <message> [--port <port>] Sends a best-effort datagram to every member of the network.
Returns: `network_id`, `port`, `bytes`
subscribe
pilotctl subscribe <address|hostname> <topic> [--count <n>] [--timeout <dur>] Subscribes to an event stream (port 1002). Use `*` for all topics. Without `--count`, it streams NDJSON.
Returns: `events` [{`topic`, `data`, `bytes`}], `timeout` (bool)
publish
pilotctl publish <address|hostname> <topic> --data "<message>" Returns: `target`, `topic`, `bytes`
Pipe mode
echo "hello" | pilotctl connect <address|hostname> [port] [--timeout <dur>] Without `--message`, the command reads from stdin, sends it, and reads one response.
handshake
pilotctl handshake <node_id|address|hostname> [justification] Returns: `status`, `node_id`
pending
pilotctl pending Pending requests persist across daemon restarts.
Returns: `pending` [{`node_id`, `justification`, `received_at`}]
approve
pilotctl approve <node_id> Returns: `status`, `node_id`
reject
pilotctl reject <node_id> [reason] Returns: `status`, `node_id`
trust
pilotctl trust Returns: `trusted` [{`node_id`, `mutual`, `network`, `approved_at`}]
untrust
pilotctl untrust <node_id> Returns: `node_id`
set-webhook
pilotctl set-webhook <url> Persists to config and applies immediately to a running daemon.
Returns: `webhook`, `applied` (bool)
clear-webhook
pilotctl clear-webhook Returns: `webhook`, `applied` (bool)
set-tags
pilotctl set-tags <tag1> [tag2] [tag3] Maximum 3 tags. Lowercase alphanumeric with hyphens, 1–32 characters each.
Returns: `node_id`, `tags`
clear-tags
pilotctl clear-tags Returns: `tags` (empty array)
received
pilotctl received [--clear] Lists files in `~/.pilot/received/`. Use `--clear` to delete all.
Returns: `files` [{`name`, `bytes`, `modified`, `path`}], `total`, `dir`
inbox
pilotctl inbox [--clear] [--trace] Lists messages in `~/.pilot/inbox/`. Use `--clear` to delete all. Use `--trace` for relative age and byte-count per message.
Returns: `messages` [{`type`, `from`, `data` (base64), `bytes`, `received_at`}], `total`, `dir`
Private networks provide group-level connectivity with a permission model.
network list
pilotctl network list Lists all networks the node is a member of.
Returns: `networks` [{`id`, `name`, `join_rule`, `members`}]
network join
pilotctl network join <network_id> [--token <token>] Join a network. Use `--token` for token-gated networks.
network leave
pilotctl network leave <network_id> Leave a network.
network members
pilotctl network members <network_id> Returns: `nodes` [{`node_id`, `hostname`, `public`}]
network invite
pilotctl network invite <network_id> <node_id> Invite another node to a network.
network invites
pilotctl network invites List pending invitations from other nodes.
Returns: `invites` [{`network_id`, `inviter_id`, `timestamp`}]
network accept
pilotctl network accept <network_id> Accept a pending invite and join the network.
network reject
pilotctl network reject <network_id> Decline a pending invite.
Service agents are always-on responders on a dedicated overlay network. They are discovered via `list-agents` and queried using `send-message`. The agent treats the `--data` payload as a typed command and replies to the inbox.
# 1. Discover what's online (list-agents is the directory)
pilotctl handshake list-agents
pilotctl send-message list-agents --data '/data {"search":"weather","limit":5}' --wait
# 2. Trust + query any specialist by hostname
pilotctl handshake noaa-weather
pilotctl send-message noaa-weather --data '/help' --wait
pilotctl send-message noaa-weather --data '/data {"airport":"KSFO"}' --wait
# 3. Read the reply that --wait blocked for
jq -r '.data' "$(ls -1t ~/.pilot/inbox/*.json | head -1)" The `--wait [<dur>]` flag (default 30s) makes `send-message` block until the reply lands in `~/.pilot/inbox/`.
health
pilotctl health A quick daemon health check.
Returns: `status`, `uptime_seconds`, `connections`, `peers`, `bytes_sent`, `bytes_recv`
ping
pilotctl ping <address|hostname> [--count <n>] [--timeout <dur>] Sends echo probes (port 7). Default is 4 pings.
Returns: `target`, `results` [{`seq`, `bytes`, `rtt_ms`, `error`}], `timeout` (bool)
traceroute
pilotctl traceroute <address> [--timeout <dur>] Returns: `target`, `setup_ms`, `rtt_samples` [{`rtt_ms`, `bytes`}]
bench
pilotctl bench <address|hostname> [<size_mb>] [--timeout <dur>] Throughput benchmark via echo port. Default is 1 MB.
Returns: `target`, `sent_bytes`, `recv_bytes`, `send_duration_ms`, `total_duration_ms`, `send_mbps`, `total_mbps`
peers
pilotctl peers [--search <query>] Lists currently connected peers and their connection quality. Real endpoints are redacted by the daemon.
Returns: `peers` [{`node_id`, `encrypted`, `authenticated`, `path` (`direct` | `relay`)}], `total`, `relay_peer_count`, `encrypted_peers`, `authenticated_peers`
connections
pilotctl connections Returns: `connections` [{`id`, `local_port`, `remote_addr`, `remote_port`, `state`, `cong_win`, `in_flight`, `srtt_ms`, `unacked`, `ooo_buf`, `peer_recv_win`, `recv_win`}], `total`
disconnect
pilotctl disconnect <conn_id> Returns: `conn_id`
Operator commands for networks that run an automated evaluation cycle. Subcommands are `status`, `cycle`, and `reconcile`.
managed status
pilotctl managed status [--net <id>] Show managed-network status for this node. `--net 0` (the default) returns the global view.
managed cycle
pilotctl managed cycle --force [--net <id>] Force a managed-network evaluation cycle. Prunes low-scoring peers and fills vacancies. `--force` is required.
Returns: `pruned`, `filled`, `peers`
managed reconcile
pilotctl managed reconcile --net <id> Poll the registry and refresh local peer state for a specific managed network. `--net` is required.
Returns: `peers`
Per-member metadata tags inside a managed network. This is distinct from the node-level `set-tags` command.
member-tags set
pilotctl member-tags set --net <id> --node <id> --tags tag1,tag2 Set the tag list on a member, replacing any prior value.
member-tags get
pilotctl member-tags get --net <id> [--node <id>] Read member tags. Omit `--node` to get every member's tags in the network.
Local policy engine for automating network behavior.
policy get
pilotctl policy get --net <id> Retrieve the active policy for a network.
policy set
pilotctl policy set --net <id> --file <path>
pilotctl policy set --net <id> --inline '<json>' Apply a policy document to a network.
policy validate
pilotctl policy validate --file <path>
pilotctl policy validate --inline '<json>' Validate a policy document without applying it. Returns rule count and compilation status.
policy test
pilotctl policy test --file <path> --event '<json>' Test a policy against a simulated event. Returns whether the event would be allowed or denied.
audit
pilotctl audit [--network <id>] Queries the audit trail for a network (default: backbone network 0). Requires admin token. Returns: `entries`
audit-export
pilotctl audit-export <get|set|disable> [options] Configure external audit log export. Subcommands:
Requires admin token.
provision
pilotctl provision <blueprint.json> Provision a network from a JSON blueprint file. Requires admin token.
deprovision
pilotctl deprovision <network-name> Look up a network by name and delete it. Requires admin token.
provision-status
pilotctl provision-status Shows provisioning status. Requires admin token.
idp
pilotctl idp <get|set> [options] Get or set the identity provider configuration. Subcommands:
Requires admin token.
directory-sync
pilotctl directory-sync <directory.json> [--network <id>] [--remove-unlisted] Sync a directory of node-to-identity mappings into a network. Requires admin token.
directory-status
pilotctl directory-status <network_id> Shows directory sync status for a network. Requires admin token.
register
pilotctl register [listen_addr] Returns: `node_id`, `address`, `public_key`
lookup
pilotctl lookup <node_id> Returns: `node_id`, `address`, `real_addr`, `public`, `hostname`
deregister
pilotctl deregister Routes through the daemon (signed). Returns: `status`
rotate-key
pilotctl rotate-key Generates a new keypair for this node and re-registers it. The daemon signs the rotation and replaces `~/.pilot/identity.json`. Existing trust links are preserved.
Returns: `node_id`, new `public_key`
set-public / set-private
pilotctl set-public
pilotctl set-private Toggles whether this node appears in the public directory. Returns: `node_id`, `visibility`
trusted
pilotctl trusted Lists nodes in the embedded trusted-agents directory that are auto-approved on first contact.
version
pilotctl version Prints the build version string.
updates
pilotctl updates [--count <n>] [--scope <name>] Reads the published changelog feed and prints recent entries (default: 5).
skills
pilotctl skills [status|paths|check|disable|enable] Manages the `SKILL.md` files the daemon installs for each detected agent tool (Claude Code, OpenClaw, PicoClaw, OpenHands, Hermes). Defaults to `status`.
gateway start
pilotctl extras gateway start [--subnet <cidr>] [--ports <list>] [<pilot-addr>...] Maps pilot addresses to local IPs on a private subnet (default: `10.4.0.0/16`). Requires root.
Returns: `pid`, `subnet`, `mappings` [{`local_ip`, `pilot_addr`}]
gateway stop
pilotctl extras gateway stop Returns: `pid`
gateway map
pilotctl extras gateway map <pilot-addr> [local-ip] Returns: `local_ip`, `pilot_addr`
gateway unmap
pilotctl extras gateway unmap <local-ip> Returns: `unmapped`
gateway list
pilotctl extras gateway list Returns: `mappings` [{`local_ip`, `pilot_addr`}], `total`