[ Switch to styled version → ]


← Docs index

CLI Reference

A complete reference for the `pilotctl` command-line interface. Nearly all commands support the `--json` flag for structured output (documented exceptions: `quickstart` always prints its text banner; `gateway start` has no JSON output).

Global flags

pilotctl --json <command> [args...]

Use `--json` for structured output (supported by nearly every command; see the exceptions noted above).

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]

Prints a static 3-step getting-started banner — 1 DISCOVER, 2 TRUST, 3 TALK — with first-time daemon setup mentioned only in a footer. It does not detect daemon state.

The banner shows three steps:

The banner's footer covers first-time setup only: if the daemon isn't running yet, start it with `pilotctl daemon start`.

`--json` is accepted but `quickstart` always prints the text banner and emits no structured output.

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. 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. When supplied, it persists to `~/.pilot/account.json`. `--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: silent, 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 are validated by the registry (lowercase alphanumeric plus hyphens).

Returns: `hostname`, `node_id`

clear-hostname

pilotctl clear-hostname

Clears the user-set hostname. The node then has no hostname and is reachable by address only until a new one is set.

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. 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: 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: 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: `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>]

Fans a best-effort datagram out to every member of the network. `--port` defaults to 1000. Requires an admin token.

Returns: `network_id`, `port`, `bytes`

subscribe

pilotctl subscribe <address|hostname> <topic> [--count <n>] [--timeout <dur>]

Subscribes to 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`, `connect` 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 an attested identity. `verify` or `verify status` shows current state. `--provider <name>` runs a device-flow to become verified. `--badge` or `--from <file>` submits an existing badge. Badges are checked offline against the pinned issuer key.

Returns: `node_id`, `address`, `verified` (bool), `status`, `provider`, `verified_at`

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. Enrollment and signatures come from the `pilot-verify` tool.

sign-request / verify-request

pilotctl sign-request --audience <a> (--body-file <f> | --body-hash <64hex> | --body '<string>')
pilotctl verify-request --envelope '<canonical>' --signature '<b64>' [--standing] [--max-skew <secs>]

Sign an arbitrary request payload with the node's identity, or verify an envelope from a peer.

`sign-request` returns: `envelope`, `signature`, `address`. `verify-request` returns the verifier reply and exits non-zero on an invalid signature.

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 in the `extras` tier.

set-tags

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

Maximum 3 tags. Each tag is validated by the registry.

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] [--full] [--latest] [--limit <n>] [--since <dur>] [--from <peer>] [--before <dur>] [read <id>]

Lists messages in `~/.pilot/inbox/`. Use `--clear` to delete all. `--from <peer>` filters to a single sender. `--before <dur>` scopes a `--clear` to messages older than the duration.

Returns: `messages` [{`id`, `from`, `type`, `bytes`, `received_at`, `preview`}], `total`, `shown`, `dir`. The full plain-text payload (`data`) replaces `preview` when `full` or `latest` flags are passed.

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.

network create / delete / rename

pilotctl network create --name <name> [--join-rule open|token|invite] [--token <t>] [--enterprise]
pilotctl network delete <network_id>
pilotctl network rename <network_id> <new_name>

Create, delete, or rename a network. The `--enterprise` flag enables enterprise controls at creation time.

network promote / demote / kick / role

pilotctl network promote <network_id> <node_id>
pilotctl network demote <network_id> <node_id>
pilotctl network kick <network_id> <node_id>
pilotctl network role <network_id> <node_id>

Membership administration: promote a member to admin, demote an admin, remove a member, or inspect a member's role. These commands authenticate with the registry admin token.

network policy

pilotctl network policy <network_id> [--max-members <n>] [--description <text>] [--allowed-ports <list>]

Get the network policy, or set it with the key flags.

Service Agents

Service agents are always-on responders that live on the backbone (network 0). They are discovered via `list-agents`, then communicated with using `send-message`. The agent treats the `--data` payload as a typed command.

# 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` flag makes `send-message` block until the reply lands in `~/.pilot/inbox/`.

App Store

The app store installs local capability apps that run on the daemon as typed IPC services. All subcommands are invoked as `pilotctl appstore <subcommand>`. The install root is `$PILOT_APPSTORE_ROOT` or `~/.pilot/apps`. Run `pilotctl appstore help` for the complete subcommand list.

catalogue

pilotctl appstore catalogue

Lists apps available for install. Alias: `catalog`.

view

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

Shows app details, including description, vendor, changelog, size, source URL, license, methods, and permissions.

install

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

Install by catalogue ID, or sideload a local bundle with `--local`. The daemon auto-spawns the app on install. The command prints usage examples after installation.

outdated / upgrade

pilotctl appstore outdated
pilotctl appstore upgrade <id>
pilotctl appstore upgrade --all

`outdated` lists installed apps with a newer catalogue version. `upgrade` re-runs the verified install for one app or all apps.

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 and prints the JSON result on stdout. Every app exposes `<app>.help`. Default timeout is 120s. After each call, a next-steps block prints to stderr. This can be disabled with `PILOT_NEXT_STEPS=off`.

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` shows an app's state. `caps` shows manifest spend caps and usage. `audit` shows the supervisor lifecycle log. `actions` shows the install/uninstall log.

restart / uninstall / verify

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

`restart` 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 a keypair, sign a manifest, and sign a catalogue. Alias: `sign-catalog`.

Diagnostics

health

pilotctl health

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: 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: 1 MB.

Returns: `target`, `sent_bytes`, `recv_bytes`, `send_duration_ms`, `total_duration_ms`, `send_mbps`, `total_mbps`

peers

pilotctl peers [--search <query>] [--all] [--limit <n>]

Lists currently connected peers and their connection quality. The client strips real endpoints before printing. `--limit <n>` caps the number of rows (default 20). `--all` lists every peer.

Returns: `peers` [{`node_id`, `encrypted`, `authenticated`, `relay` (bool)}], `total`, `encrypted` (count)

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

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. 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. Replaces any prior value.

member-tags get

pilotctl member-tags get --net <id> [--node <id>]

Read member tags. Omit `--node` to dump 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. Use `--remove-unlisted` to disable nodes not in the file. 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`, `hostname`, `public`, `networks`, `last_seen_unix`, `type`, `version` (real endpoints are redacted client-side).

deregister

pilotctl deregister

Routes through 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`. The old private key is destroyed.

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 list

Lists nodes in the embedded trusted-agents directory that are auto-approved on first contact. Different from `pilotctl trust`, which shows live trust state.

Meta

version

pilotctl version

Prints the build version string.

update

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

Self-update. With no subcommand, it runs the updater once. Automatic updates are off by default. `enable`/`disable` toggle the background updater and `status` shows the current setting.

review

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

Submit a rating and/or written review for Pilot itself or for an installed app.

updates

pilotctl updates [--count <n>] [--scope <name>]

Reads the published changelog feed and prints recent entries (default: 10). `--scope` filters by tag.

skills

pilotctl skills [status|paths|check|set-mode|disable|enable]

Manages the `SKILL.md` files the daemon installs for each detected agent tool (Claude Code, OpenClaw, PicoClaw, OpenHands, Hermes, Goose, OpenCode). Without a subcommand, 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.

`gateway start` execs the `pilot-gateway` binary; it prints logs and returns no JSON envelope.

gateway stop

pilotctl extras gateway stop

Not supported from pilotctl. Stop `pilot-gateway` directly.

gateway map

pilotctl extras gateway map <pilot-addr> [local-ip]

Execs `pilot-gateway map`; the mapping is logged by the gateway process, not returned as JSON by pilotctl.

gateway unmap

pilotctl extras gateway unmap <local-ip>

Not supported from pilotctl. Unmapping is owned by the `pilot-gateway` process.

gateway list

pilotctl extras gateway list

Returns an empty mapping list with a note. Live mappings are held inside the `pilot-gateway` process.

Related