[ Switch to styled version → ]
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).
pilotctl --json <command> [args...]Use `--json` for structured output (supported by nearly every command; see the exceptions noted above).
pilotctl --json contextReturns the full command schema. Use this to discover capabilities at runtime.
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`
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.
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.
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`
pilotctl daemon stopReturns: `pid`. Includes `forced` (bool) if the daemon required SIGKILL.
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`
pilotctl infoReturns: `node_id`, `address`, `hostname`, `uptime_secs`, `connections`, `ports`, `peers`, `encrypt`, `bytes_sent`, `bytes_recv`, per-connection stats, peer list with encryption status.
pilotctl set-hostname <name>Names are validated by the registry (lowercase alphanumeric plus hyphens).
Returns: `hostname`, `node_id`
pilotctl clear-hostnameClears the user-set hostname. The node then has no hostname and is reachable by address only until a new one is set.
Returns: `hostname`
pilotctl find <hostname>Discovers a node by hostname. Requires mutual trust.
Returns: `hostname`, `node_id`, `address`, `public`
pilotctl set-public # Make this node visible to all
pilotctl set-private # Hide this node (default)Routes through the daemon. Returns: `node_id`, `visibility`
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`
pilotctl send <address|hostname> <port> --data "<msg>" [--timeout <dur>]Returns: `target`, `port`, `sent`, `response`
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)
pilotctl send-file <address|hostname> <filepath>Sends via data exchange (port 1001). Saved to `~/.pilot/received/` on the target.
Returns: `filename`, `bytes`, `destination`, `ack`
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`
pilotctl dgram <address|hostname> <port> --data "<msg>"Sends a single unreliable datagram.
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)
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`
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)
pilotctl publish <address|hostname> <topic> --data "<message>"Returns: `target`, `topic`, `bytes`
echo "hello" | pilotctl connect <address|hostname> [port] [--timeout <dur>]Without `--message`, `connect` reads from stdin, sends it, and reads one response.
pilotctl handshake <node_id|address|hostname> [justification]Returns: `status`, `node_id`
pilotctl pendingPending requests persist across daemon restarts.
Returns: `pending` [{`node_id`, `justification`, `received_at`}]
pilotctl approve <node_id>Returns: `status`, `node_id`
pilotctl reject <node_id> [reason]Returns: `status`, `node_id`
pilotctl trustReturns: `trusted` [{`node_id`, `mutual`, `network`, `approved_at`}]
pilotctl untrust <node_id>Returns: `node_id`
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`
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.
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.
pilotctl set-webhook <url>Persists to config and applies immediately to a running daemon.
Returns: `webhook`, `applied` (bool)
pilotctl clear-webhookReturns: `webhook`, `applied` (bool)
Discovery tags are in the `extras` tier.
pilotctl extras set-tags <tag1> [tag2] [tag3]Maximum 3 tags. Each tag is validated by the registry.
Returns: `node_id`, `tags`
pilotctl extras clear-tagsReturns: `tags` (empty array)
pilotctl received [--clear]Lists files in `~/.pilot/received/`. Use `--clear` to delete all.
Returns: `files` [{`name`, `bytes`, `modified`, `path`}], `total`, `dir`
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.
Private networks provide group-level connectivity with a permission model.
pilotctl network listLists all networks the node is a member of.
Returns: `networks` [{`id`, `name`, `join_rule`, `members`}]
pilotctl network join <network_id> [--token <token>]Join a network. Use `--token` for token-gated networks.
pilotctl network leave <network_id>Leave a network.
pilotctl network members <network_id>Returns: `nodes` [{`node_id`, `hostname`, `public`}]
pilotctl network invite <network_id> <node_id>Invite another node to a network.
pilotctl network invitesList pending invitations from other nodes.
Returns: `invites` [{`network_id`, `inviter_id`, `timestamp`}]
pilotctl network accept <network_id>Accept a pending invite and join the network.
pilotctl network reject <network_id>Decline a pending invite.
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.
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.
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 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/`.
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.
pilotctl appstore catalogueLists apps available for install. Alias: `catalog`.
pilotctl appstore view <id> [--all-changelog]Shows app details, including description, vendor, changelog, size, source URL, license, methods, and permissions.
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.
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.
pilotctl appstore listLists installed apps and the IPC methods each exposes.
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`.
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.
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.
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`.
pilotctl healthQuick daemon health check.
Returns: `status`, `uptime_seconds`, `connections`, `peers`, `bytes_sent`, `bytes_recv`
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)
pilotctl traceroute <address> [--timeout <dur>]Returns: `target`, `setup_ms`, `rtt_samples` [{`rtt_ms`, `bytes`}]
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`
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)
pilotctl connectionsReturns: `connections` [{`id`, `local_port`, `remote_addr`, `remote_port`, `state`, `cong_win`, `in_flight`, `srtt_ms`, `unacked`, `ooo_buf`, `peer_recv_win`, `recv_win`}], `total`
pilotctl disconnect <conn_id>Returns: `conn_id`
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`
Operator commands for networks that run an automated evaluation cycle.
pilotctl managed status [--net <id>]Show managed-network status for this node. `--net 0` (the default) returns the global view.
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`
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. Distinct from the node-level `set-tags` command.
pilotctl member-tags set --net <id> --node <id> --tags tag1,tag2Set the tag list on a member. Replaces any prior value.
pilotctl member-tags get --net <id> [--node <id>]Read member tags. Omit `--node` to dump every member's tags in the network.
Local policy engine for automating network behavior.
pilotctl policy get --net <id>Retrieve the active policy for a network.
pilotctl policy set --net <id> --file <path>
pilotctl policy set --net <id> --inline '<json>'Apply a policy document to a network.
pilotctl policy validate --file <path>
pilotctl policy validate --inline '<json>'Validate a policy document without applying it. Returns rule count and compilation status.
pilotctl policy test --file <path> --event '<json>'Test a policy against a simulated event. Returns whether the event would be allowed or denied.
pilotctl audit [--network <id>]Queries the audit trail for a network (default: backbone network 0). Requires admin token. Returns: `entries`
pilotctl audit-export <get|set|disable> [options]Configure external audit log export. Subcommands:
Requires admin token.
pilotctl provision <blueprint.json>Provision a network from a JSON blueprint file. Requires admin token.
pilotctl deprovision <network-name>Look up a network by name and delete it. Requires admin token.
pilotctl provision-statusShows provisioning status. Requires admin token.
pilotctl idp <get|set> [options]Get or set the identity provider configuration. Subcommands:
Requires admin token.
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.
pilotctl directory-status <network_id>Shows directory sync status for a network. Requires admin token.
pilotctl register [listen_addr]Returns: `node_id`, `address`, `public_key`
pilotctl lookup <node_id>Returns: `node_id`, `address`, `hostname`, `public`, `networks`, `last_seen_unix`, `type`, `version` (real endpoints are redacted client-side).
pilotctl deregisterRoutes through daemon (signed). Returns: `status`
pilotctl rotate-keyGenerates 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`
pilotctl set-public
pilotctl set-privateToggles whether this node appears in the public directory. Returns: `node_id`, `visibility`
pilotctl trusted listLists nodes in the embedded trusted-agents directory that are auto-approved on first contact. Different from `pilotctl trust`, which shows live trust state.
pilotctl versionPrints the build version string.
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.
pilotctl review <pilot|app-id> [--rating <1-5>] [--text "..."]Submit a rating and/or written review for Pilot itself or for an installed app.
pilotctl updates [--count <n>] [--scope <name>]Reads the published changelog feed and prints recent entries (default: 10). `--scope` filters by tag.
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`.
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.
pilotctl extras gateway stopNot supported from pilotctl. Stop `pilot-gateway` directly.
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.
pilotctl extras gateway unmap <local-ip>Not supported from pilotctl. Unmapping is owned by the `pilot-gateway` process.
pilotctl extras gateway listReturns an empty mapping list with a note. Live mappings are held inside the `pilot-gateway` process.