[ Switch to styled version → ]


← Docs index

CLI Reference

A complete reference for `pilotctl`. All commands support `--json` for structured output.

Global flags

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.

Bootstrap

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

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 lifecycle

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`

Identity & Discovery

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`

Communication

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.

Trust management

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`

Verification & Recovery

verify

pilotctl verify [status] [--node <addr|id>]
pilotctl verify --provider <name>
pilotctl verify --badge <b> --badge-sig <s>   # or --from <file>

Verified-address badges prove a node controls a real, attested identity. Bare `verify` (or `verify status`) shows your state; `--provider <name>` runs a device-flow to become verified; `--badge`/`--badge-sig` (or `--from <file>`) submits a badge you already hold. Badges are checked offline against the pinned issuer key.

Returns: `verified` (bool), `node_id`, `address`, `issuer`

recovery

pilotctl recovery enroll <...>
pilotctl recovery new-key <...>
pilotctl recovery recover <...>

Reclaim a node's address if its identity key is lost. `enroll` records a recovery commitment; `new-key` rotates to a fresh key; `recover` reclaims the address using recovery material. Enrollment and signatures come from the `pilot-verify` tool.

Returns: `status`, `node_id`, `address`

Webhooks

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)

Tags

Discovery tags are operator setup, so they live in the `extras` tier — `pilotctl set-tags` on its own is rejected.

set-tags

pilotctl extras set-tags <tag1> [tag2] [tag3]

Maximum 3 tags. Lowercase alphanumeric with hyphens, 1–32 characters each.

Returns: `node_id`, `tags`

clear-tags

pilotctl extras clear-tags

Returns: `tags` (empty array)

Mailbox

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`

Networks

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

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/`.

App Store

Local capability apps that run on your daemon as typed IPC services — JSON in, JSON out, auto-spawned on install. All subcommands are invoked as `pilotctl appstore <subcommand>`. Install root: `$PILOT_APPSTORE_ROOT` or `~/.pilot/apps`. Run `pilotctl appstore help` for the full list. See the App Store guide for the discover → install → call loop.

catalogue

pilotctl appstore catalogue

Lists apps available for one-command install (alias: `catalog`).

view

pilotctl appstore view <id> [--all-changelog]

App detail page — description, vendor, changelog, size, source, license, methods, permissions. Works whether or not the app is installed.

install

pilotctl appstore install <app-id> [--force]
pilotctl appstore install <bundle-dir> --local [--force]

Install by catalogue ID (fetch + verify + extract), or sideload a local bundle with `--local` (sandboxed: no net, no key.sign, no hooks).

list

pilotctl appstore list

Lists installed apps and the IPC methods each exposes.

call

pilotctl appstore call <id> <method> [json-args] [--timeout <dur>]

Dispatches an IPC call into an app. Every app exposes `<app>.help`. Default timeout 120s (also `$PILOT_APPSTORE_CALL_TIMEOUT`).

status / caps / audit / actions

pilotctl appstore status <id>
pilotctl appstore caps <id>
pilotctl appstore audit <id> [--tail <n>] [--event <name>] [--since <dur>]
pilotctl appstore actions [--tail <n>] [--event <name>]

`status` deep-dives one app's pinned state; `caps` shows spend caps + rolling-window usage; `audit` shows the supervisor lifecycle log; `actions` shows the pilotctl-side install/uninstall log (survives app removal).

restart / uninstall / verify

pilotctl appstore restart <id>
pilotctl appstore uninstall <id> --yes
pilotctl appstore verify <bundle-dir>

`restart` clears crash-loop suspension and respawns the app; `uninstall` removes it; `verify` sha256-checks a pre-install bundle against its manifest.

gen-key / sign / sign-catalogue

pilotctl appstore gen-key <key-file>
pilotctl appstore sign --key <key-file> <manifest>
pilotctl appstore sign-catalogue --key <key-file> <catalogue.json>

Publisher tooling: generate an ed25519 keypair, sign a manifest's `store.signature`, and sign a catalogue (detached `.sig`). Alias: `sign-catalog`.

Diagnostics

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`

prefer-direct

pilotctl prefer-direct <node_id|address|hostname>

Resets routing state for a peer so the next connection prefers a direct (hole-punched) tunnel over the relay. Requires daemon v1.12+.

Returns: `had_tunnel`, `was_relay_active`, `was_relay_pinned`

Managed Networks

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`

Member Tags

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.

Network Policies

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.

Enterprise Admin

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.

Registry

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.

Meta

version

pilotctl version

Prints the build version string.

update

pilotctl update [status|enable|disable] [--pin <tag>]

Self-update. With no subcommand, runs the updater once — checks for and installs the latest release. Automatic updates are off by default; `enable`/`disable` toggle the background updater and `status` shows the current setting. Distinct from `updates`, which only reads the changelog feed.

review

pilotctl review <pilot|app-id> [--rating <1-5>] [--text "..."]

Submit a rating and/or written review for Pilot itself (`pilot`) or an installed app (e.g. `io.pilot.cosift`).

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

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`

Related