From cd9946ecb62e030fa5ecfbb395f0cfd32df8a4c9 Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Fri, 17 Jul 2026 13:52:41 +0300 Subject: [PATCH 01/10] docs(mcp-setup): update for the shipped pilotprotocol-mcp package The MCP Setup page described an unpublished, git-clone-only build under the old TeoSlayer org. pilotprotocol-mcp@0.1.0 is now on npm, so update to match: - install is one command: `npx -y pilotprotocol-mcp setup` - links point at github.com/pilot-protocol/pilot-mcp (the package repo) - 400+ -> 435 specialists (the count the package advertises) - add "What you get": the 10 MCP tools, 6 resources, 5 prompts - replace the vague modes list with the real Local (v0.1, now) / Hosted SSH (v0.2) / Hosted HTTP (v0.3) table - lead with the package framing: "MCP gave your agent tools. Pilot gives your agent peers." - add per-harness manual config (Claude Code, Cursor/Cline, OpenHands) Build green (344 pages). Co-Authored-By: Claude Opus 4.8 --- src/pages/docs/mcp-setup.astro | 73 ++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/src/pages/docs/mcp-setup.astro b/src/pages/docs/mcp-setup.astro index e7b3cfbb..906067e3 100644 --- a/src/pages/docs/mcp-setup.astro +++ b/src/pages/docs/mcp-setup.astro @@ -3,45 +3,92 @@ import DocLayout from "../../layouts/DocLayout.astro"; ---

MCP Setup

-

Expose the whole overlay — 400+ specialists plus agent-to-agent messaging — to any MCP client as a single server.

+

Expose the whole overlay — 435 specialist agents plus agent-to-agent messaging — to any MCP client as a single server. One command configures every harness on your machine.

-

What pilot-mcp is

+

What pilotprotocol-mcp is

-

pilot-mcp is an MCP server that fronts the Pilot overlay. Your MCP client (Claude Code, Cursor, Cline, OpenClaw, Hermes, OpenHands, Continue.dev, Codex CLI, and others) gets the specialist directory, typed queries, and A2A messaging as MCP tools — without learning pilotctl.

+

pilotprotocol-mcp is an MCP server that fronts the Pilot overlay. Your MCP client — Claude Code, Cursor, Cline, OpenClaw, Hermes, OpenHands, Continue.dev, Codex CLI, Junie, GitHub Copilot, PicoClaw — gets the specialist directory, typed queries, and A2A messaging as MCP tools, without learning pilotctl.

+ +

MCP gave your agent tools. Pilot gives your agent peers — a directory of 435 specialists you can query without an API key, plus a direct message path to other operators' agents over an encrypted P2P network.

Setup

-
# Build/run from source (not yet published to npm):
-git clone https://github.com/TeoSlayer/pilot-mcp && cd pilot-mcp && npm install && npm run setup
+

One command detects every MCP-capable harness on your machine, writes the server entry into each one's config, pulls the Go daemon, and starts it. Total time is about a minute.

+ +
npx -y pilotprotocol-mcp setup
+ +

Your node keeps its own Ed25519 identity, and traffic is peer-to-peer on the direct path (payloads stay end-to-end encrypted; when a direct path isn't possible, an encrypted relay carries the bytes).

+ +

Per-harness (manual)

+ +

If you'd rather wire one harness by hand instead of running setup:

+ +
# Claude Code
+claude mcp add --transport stdio pilot -- npx -y pilotprotocol-mcp
 
-  

The setup command pulls the Go daemon if needed, starts it, detects installed MCP-capable harnesses, and writes the server entry into each one's config. Total time is about a minute; your node keeps its own Ed25519 identity, and traffic is peer-to-peer on the direct path (payloads stay end-to-end encrypted; when a direct path isn't possible, an encrypted relay carries the bytes).

+# Cursor — ~/.cursor/mcp.json (Cline uses the same JSON) +{"mcpServers":{"pilot":{"command":"npx","args":["-y","pilotprotocol-mcp"]}}} + +# OpenHands — ~/.openhands/config.toml +[mcp.stdio_servers.pilot] +command = "npx" +args = ["-y", "pilotprotocol-mcp"]
+ +

What you get

+ +

The server exposes 10 tools shaped around the 3-command pattern (/help, /data, /summary) that pilotctl enforces — the tool surface prevents the bare-message mistake that would otherwise no-op.

+ + + + + + + + + + + + + + + +
ToolWhat it does
pilot_search(keyword, limit?)Find specialists by keyword (literal token match — use short generic words: bitcoin, weather, nba).
pilot_help(agent)Learn a specialist's /data filter schema.
pilot_query(agent, filters?)Fetch structured data; detects ~8 KB truncation and surfaces a hint.
pilot_summary(agent, question?)LLM-synthesized digest when /data would exceed truncation.
pilot_send(peer, message)Send plain text to a human-operated peer.
pilot_inbox(limit?)Read received messages.
pilot_handshake(target, reason?)Establish bilateral trust (warns about ~60s registry propagation).
pilot_find(hostname)DNS-like lookup of a hostname to a Pilot address.
pilot_peers()List connected peers and path (direct vs relay).
pilot_approve(target)Accept a pending handshake.
+ +

Plus 6 resourcespilot://catalog (live directory snapshot), pilot://inbox, pilot://trust, pilot://peers, pilot://identity, pilot://daemon-health — and 5 prompts: the 3-command pattern, A2A messaging, handshake-first-contact, troubleshooting, and a readiness check.

Modes

-
    -
  • Local (run from the pilot-mcp repo) — full P2P with your own identity. Not yet published to npm.
  • -
  • Hosted (SSH / HTTP) — planned; no local daemon, at the cost of a hosted party seeing metadata. Not yet available.
  • -
+ + + + + + + +
ModeFirst callPrivacyStatus
Localnpx -y pilotprotocol-mcp~1 min: pulls the Go daemon, starts it, wires the harnessFull P2P; no third party sees metadatav0.1 — shipping now
Hosted SSHssh://…~10 sec: paste one line; your SSH key is the identityHosted party sees metadata (specialist payloads stay E2E)v0.2 — planned
Hosted HTTPhttps://… --token~30 sec: sign up, save a bearer tokenSame as SSHv0.3 — conditional on demand
+ +

There is deliberately no ephemeral anonymous HTTP mode: a 30-second identity can't propagate trust through the registry, so it can't do the agent-to-agent messaging that is Pilot's reason to exist.

Why not just another MCP server?

-

A typical MCP server wraps one API and brings one more credential. pilot-mcp brings a network: one identity, no API keys, live data from specialists built for agent traffic (no rate-limit dance, no captchas), and a direct message path to other operators' agents. Pilot and MCP compose — Pilot is the transport and directory underneath; MCP is how your harness reaches it. See vs MCP / A2A / ACP for the full comparison.

+

A typical MCP server wraps one API and brings one more credential. pilotprotocol-mcp brings a network: one identity, no API keys, live data from specialists built for agent traffic (no rate-limit dance, no captchas), and a direct message path to other operators' agents. Pilot and MCP compose — Pilot is the transport and directory underneath; MCP is how your harness reaches it. See vs MCP / A2A / ACP for the full comparison.

From 7cebd77ccf0b5823ee1225ab1e2cba1422f04a6a Mon Sep 17 00:00:00 2001 From: pilot-plain-bot <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 10:53:47 +0000 Subject: [PATCH 02/10] chore(plain): auto-regenerate stale machine-UI twins --- src/pages/plain/docs/mcp-setup.astro | 84 +++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 13 deletions(-) diff --git a/src/pages/plain/docs/mcp-setup.astro b/src/pages/plain/docs/mcp-setup.astro index 71c3db59..c4d102f9 100644 --- a/src/pages/plain/docs/mcp-setup.astro +++ b/src/pages/plain/docs/mcp-setup.astro @@ -1,39 +1,97 @@ --- // Auto-generated by scripts/regen-plain.mjs. Edit the marketing source and re-run. // plain-source: src/pages/docs/mcp-setup.astro -// plain-source-sha256: 2c2d425c2359ae02ef4259cf143112354125fef9d1333ec0f27743df958dfc0c +// plain-source-sha256: 84c1f16bbf4ff0f01e292f5e4f9f266b5da3cd477d5ae3a9aa218ad74ba2a148 import PlainLayout from '../../../layouts/PlainLayout.astro'; --- - +

← Docs index

MCP Setup

-

pilot-mcp is an MCP server that exposes the Pilot overlay to MCP clients. This provides access to over 400 specialists and agent-to-agent messaging as a single server.

+

pilotprotocol-mcp is an MCP server that exposes the Pilot overlay to MCP clients. It provides access to 435 specialist agents and agent-to-agent messaging as a single server.

-

What pilot-mcp is

-

pilot-mcp is an MCP server that fronts the Pilot overlay. MCP clients such as Claude Code, Cursor, Cline, OpenClaw, Hermes, OpenHands, Continue.dev, and Codex CLI can access the specialist directory, typed queries, and A2A messaging as MCP tools without using pilotctl.

+

What pilotprotocol-mcp is

+

pilotprotocol-mcp is an MCP server that fronts the Pilot overlay. It allows MCP clients to access the specialist directory, typed queries, and agent-to-agent messaging as MCP tools without using pilotctl.

+
    +
  • Claude Code
  • +
  • Cursor
  • +
  • Cline
  • +
  • OpenClaw
  • +
  • Hermes
  • +
  • OpenHands
  • +
  • Continue.dev
  • +
  • Codex CLI
  • +
  • Junie
  • +
  • GitHub Copilot
  • +
  • PicoClaw
  • +
+

The service provides a directory of 435 specialists and a direct message path to other operators' agents over an encrypted P2P network.

Setup

-
# Build/run from source (not yet published to npm):
-git clone https://github.com/TeoSlayer/pilot-mcp && cd pilot-mcp && npm install && npm run setup
-

The setup command downloads and starts the Go daemon, detects installed MCP-capable harnesses, and adds the server entry to their configuration files. The process takes about one minute. The node maintains its own Ed25519 identity. Traffic is peer-to-peer and end-to-end encrypted. An encrypted relay is used if a direct path is not available.

+

A single command detects MCP-capable harnesses, writes the server entry into each configuration file, pulls the Go daemon, and starts it.

+
npx -y pilotprotocol-mcp setup
+

Each node maintains its own Ed25519 identity. Traffic is peer-to-peer when a direct path is available, with payloads end-to-end encrypted. An encrypted relay is used when a direct path is not possible.

+

For manual configuration of a single harness:

+
# Claude Code
+claude mcp add --transport stdio pilot -- npx -y pilotprotocol-mcp
+
+# Cursor — ~/.cursor/mcp.json (Cline uses the same JSON)
+{"mcpServers":{"pilot":{"command":"npx","args":["-y","pilotprotocol-mcp"]}}}
+
+# OpenHands — ~/.openhands/config.toml
+[mcp.stdio_servers.pilot]
+command = "npx"
+args = ["-y", "pilotprotocol-mcp"]
+ +

What you get

+

The server exposes 10 tools.

+
    +
  • pilot_search(keyword, limit?): Find specialists by keyword.
  • +
  • pilot_help(agent): Learn a specialist's /data filter schema.
  • +
  • pilot_query(agent, filters?): Fetch structured data.
  • +
  • pilot_summary(agent, question?): Get an LLM-synthesized digest for large data.
  • +
  • pilot_send(peer, message): Send plain text to a human-operated peer.
  • +
  • pilot_inbox(limit?): Read received messages.
  • +
  • pilot_handshake(target, reason?): Establish bilateral trust.
  • +
  • pilot_find(hostname): Look up a hostname to a Pilot address.
  • +
  • pilot_peers(): List connected peers and their path.
  • +
  • pilot_approve(target): Accept a pending handshake.
  • +
+

The server also exposes 6 resources and 5 prompts.

+
    +
  • pilot://catalog
  • +
  • pilot://inbox
  • +
  • pilot://trust
  • +
  • pilot://peers
  • +
  • pilot://identity
  • +
  • pilot://daemon-health
  • +
+
    +
  • The 3-command pattern (/help, /data, /summary)
  • +
  • A2A messaging
  • +
  • Handshake-first-contact
  • +
  • Troubleshooting
  • +
  • Readiness check
  • +

Modes

    -
  • Local: Run from the pilot-mcp repository. Provides full P2P with a local identity. Not yet published to npm.
  • -
  • Hosted (SSH / HTTP): Planned. Does not require a local daemon. A hosted party can see metadata. Not yet available.
  • +
  • Local: Uses `npx -y pilotprotocol-mcp`. First call takes about 1 minute. It is fully P2P with no third-party metadata visibility. Status is v0.1, shipping now.
  • +
  • Hosted SSH: Uses `ssh://…`. First call takes about 10 seconds. The hosted party sees metadata, but specialist payloads remain E2E encrypted. Status is v0.2, planned.
  • +
  • Hosted HTTP: Uses `https://… --token`. First call takes about 30 seconds. Privacy is the same as SSH. Status is v0.3, conditional on demand.
+

There is no ephemeral anonymous HTTP mode because a short-lived identity cannot propagate trust through the registry, which is required for agent-to-agent messaging.

-

Why not just another MCP server?

-

A standard MCP server wraps a single API. pilot-mcp provides access to a network with a single identity and no API keys. It offers live data from specialists designed for agent traffic and a direct message path to other agents. Pilot serves as the transport and directory, while MCP is the access protocol for the harness.

+

Function

+

pilotprotocol-mcp provides a network rather than a wrapper for a single API. It uses one identity and no API keys. It provides live data from specialists built for agent traffic and a direct message path to other operators' agents. Pilot is the transport and directory layer, and MCP is the protocol for the harness to access it.

Related

From 866f6b48937312c52dfb20cc694b22132fa68bbe Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Fri, 17 Jul 2026 13:54:43 +0300 Subject: [PATCH 03/10] ci: re-trigger after plain-twin regen (mcp-setup) Co-Authored-By: Claude Opus 4.8 From a15bc0d15c87ab5860928b0956ad55f8d9f4cee8 Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Fri, 17 Jul 2026 15:41:34 +0300 Subject: [PATCH 04/10] docs: bump 400+ -> 435+ specialists to match the pilotprotocol-mcp package count Co-Authored-By: Claude Opus 4.8 --- src/pages/docs/cli-reference.astro | 2 +- src/pages/docs/getting-started.astro | 2 +- src/pages/docs/index.astro | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/docs/cli-reference.astro b/src/pages/docs/cli-reference.astro index 52244f42..dd707f0d 100644 --- a/src/pages/docs/cli-reference.astro +++ b/src/pages/docs/cli-reference.astro @@ -71,7 +71,7 @@ const bodyContent = `

CLI Reference

Step 2 — Discover specialist agents

pilotctl send-message list-agents \
     --data '/data {"search":"","limit":10}' --wait
-

Queries the public directory for 400+ specialist agents covering weather, crypto, news, sports, transit, science, and more. Filter by keyword: weather, crypto, news, sports, joke.

+

Queries the public directory for 435+ 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
diff --git a/src/pages/docs/getting-started.astro b/src/pages/docs/getting-started.astro
index 3d668a23..1f18686c 100644
--- a/src/pages/docs/getting-started.astro
+++ b/src/pages/docs/getting-started.astro
@@ -136,7 +136,7 @@ Daemon running (pid 12345)
   

Sends echo probes through the overlay and reports round-trip times.

4. Ask your first specialist

-

This is the payoff. The overlay runs a directory of 400+ specialist service agents — live weather, crypto, transit, papers, sports — that answer structured queries with no API keys. Specialists live on the backbone; you handshake one and ask:

+

This is the payoff. The overlay runs a directory of 435+ specialist service agents — live weather, crypto, transit, papers, sports — that answer structured queries with no API keys. Specialists live on the backbone; you handshake one and ask:

# Find a specialist in the directory
 pilotctl handshake list-agents
 pilotctl send-message list-agents --data '/data {"search":"weather","limit":5}' --wait
diff --git a/src/pages/docs/index.astro b/src/pages/docs/index.astro
index f04c7aa5..165caa3a 100644
--- a/src/pages/docs/index.astro
+++ b/src/pages/docs/index.astro
@@ -6,7 +6,7 @@ const cards: { slug: string; href: string; label: string; desc: string; icon?: s
   { slug: 'getting-started', href: 'getting-started', label: 'Getting Started', desc: 'Install, start the daemon, and connect to your first peer.' },
   { slug: 'concepts', href: 'concepts', label: 'Core Concepts', desc: 'Addressing, transport, encryption, NAT traversal, and the trust model.' },
   { slug: 'pilot-director', href: 'pilot-director', label: 'pilot-director', desc: 'Hand it a plain-English task, get a validated plan across the network\'s specialists.' },
-  { slug: 'service-agents', href: 'service-agents', label: 'Service Agents', desc: '400+ live specialists — discover, handshake, and query structured data with no API keys.' },
+  { slug: 'service-agents', href: 'service-agents', label: 'Service Agents', desc: '435+ live specialists — discover, handshake, and query structured data with no API keys.' },
   { slug: 'app-store', href: 'app-store', label: 'App Store', desc: 'Installable local capability apps — discover, install, and call typed IPC methods.' },
   { slug: 'consent', href: 'consent', label: 'Consent & Privacy', desc: 'Every default-on feature — telemetry, broadcasts, reviews, skill injection — and how to turn each off.' },
   { slug: 'cli-reference', href: 'cli-reference', label: 'CLI Reference', desc: 'Complete reference for all pilotctl commands, flags, and return values.' },

From 34c5eddaa9073aa470751da3b01cd73eb3786965 Mon Sep 17 00:00:00 2001
From: pilot-plain-bot <41898282+github-actions[bot]@users.noreply.github.com>
Date: Fri, 17 Jul 2026 12:45:26 +0000
Subject: [PATCH 05/10] chore(plain): auto-regenerate stale machine-UI twins

---
 src/pages/plain/docs/cli-reference.astro   | 359 ++++++++++++++-------
 src/pages/plain/docs/getting-started.astro |  90 +++---
 src/pages/plain/docs/index.astro           |  50 ++-
 3 files changed, 318 insertions(+), 181 deletions(-)

diff --git a/src/pages/plain/docs/cli-reference.astro b/src/pages/plain/docs/cli-reference.astro
index b42921f7..79b6f81d 100644
--- a/src/pages/plain/docs/cli-reference.astro
+++ b/src/pages/plain/docs/cli-reference.astro
@@ -1,7 +1,7 @@
 ---
 // Auto-generated by scripts/regen-plain.mjs. Edit the marketing source and re-run.
 // plain-source: src/pages/docs/cli-reference.astro
-// plain-source-sha256: e2cdec80884a84c4f360e02bb10e303e5f885a98181f478bb47b77124dee970e
+// plain-source-sha256: a583dcb5e4091dde938f5d990d5063113398fdd549ac9aa14db16be59cc83f6c
 import PlainLayout from '../../../layouts/PlainLayout.astro';
 ---
 
@@ -19,32 +19,41 @@ import PlainLayout from '../../../layouts/PlainLayout.astro';
   
  • Success: {"status":"ok","data":{...}}
  • Error: {"status":"error","code":"...","message":"...","hint":"..."}
  • -

    Self-discovery

    + +

    Self-discovery

    pilotctl --json context

    Returns the full command schema - use this to discover capabilities at runtime.

    Bootstrap

    -

    init

    + + +

    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

    + +

    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

    + + +

    quickstart

    pilotctl quickstart [--json]
    -

    Prints a static 3-step getting-started banner (start the daemon, discover agents, handshake + query). It does not detect daemon state; it is a fixed cheat-sheet you can print any time.

    -

    Step 1 — Start the daemon

    +

    Prints a static 3-step getting-started banner (start the daemon, discover agents, handshake + query). It does not detect daemon state; it is a fixed cheat-sheet.

    + +

    Step 1 — Start the daemon

    pilotctl daemon start
    -

    The banner shows the `pilotctl daemon start` command in its first-time-setup footer. (The steps below expand each line of the banner.)

    -

    Step 2 — Discover specialist agents

    +

    The banner shows the `pilotctl daemon start` command in its first-time-setup footer.

    + +

    Step 2 — Discover specialist agents

    pilotctl send-message list-agents \
         --data '/data {"search":"","limit":10}' --wait
    -

    Queries the public directory for 400+ 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

    +

    Queries the public directory for 435+ 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
    @@ -57,61 +66,77 @@ pilotctl send-message <hostname> --data '/data {"<filter>":"<

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

    Daemon lifecycle

    -

    daemon start

    + + +

    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 (`<fingerprint>@nodes.pilotprotocol.network`); when supplied, it persists to the account file `~/.pilot/account.json` and is not needed on subsequent starts. `--trust-auto-approve` auto-accepts every incoming handshake (useful for service-agent nodes).

    +

    `--email` is optional. If omitted, the daemon synthesises one from the public-key fingerprint (`<fingerprint>@nodes.pilotprotocol.network`); when supplied, it persists to the account file `~/.pilot/account.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

    + +

    daemon stop

    pilotctl daemon stop

    Returns: `pid`. Includes `forced` (bool) if the daemon required SIGKILL.

    -

    daemon status

    + +

    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

    + + +

    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

    + +

    set-hostname

    pilotctl set-hostname <name>

    Names are validated by the registry (lowercase alphanumeric plus hyphens); it rejects names that do not conform.

    Returns: `hostname`, `node_id`

    -

    clear-hostname

    + +

    clear-hostname

    pilotctl clear-hostname
    -

    Clears the user-set hostname. The node keeps a registry-assigned internal hostname (of the form `pilot-XXXXXXXX`) until you set a new one.

    +

    Clears the user-set hostname. The node keeps a registry-assigned internal hostname (of the form `pilot-XXXXXXXX`) until a new one is set.

    Returns: `hostname`

    -

    find

    + +

    find

    pilotctl find <hostname>

    Discovers a node by hostname. Requires mutual trust.

    Returns: `hostname`, `node_id`, `address`, `public`

    -

    set-public / set-private

    + +

    set-public / set-private

    pilotctl set-public      # Make this node visible to all
     pilotctl set-private     # Hide this node (default)

    Routes through the daemon (signs the request). Returns: `node_id`, `visibility`

    Communication

    -

    connect

    + + +

    connect

    pilotctl connect <address|hostname> [port] --message "<msg>" [--timeout <dur>]

    Dials the target, sends the message, reads one response, exits. Default port: 1000 (stdio).

    Returns: `target`, `port`, `sent`, `response`

    -

    send

    + +

    send

    pilotctl send <address|hostname> <port> --data "<msg>" [--timeout <dur>]

    Returns: `target`, `port`, `sent`, `response`

    -

    recv

    + +

    recv

    pilotctl recv <port> [--count <n>] [--timeout <dur>]

    Listens on a port, accepts incoming connections, collects messages. Default count: 1.

    Returns: `messages` [{`seq`, `port`, `data`, `bytes`}], `timeout` (bool)

    -

    send-file

    + +

    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

    + +

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

    @@ -123,141 +148,177 @@ pilotctl set-private # Hide this node (default)
  • `--trace` — print per-step timing on stderr.
  • Returns: `target`, `type`, `bytes`, `ack`

    -

    dgram

    + +

    dgram

    pilotctl dgram <address|hostname> <port> --data "<msg>"

    Sends a single unreliable datagram (UDP-style — no ACK, no retry, no ordering). Use for telemetry, heartbeats, or anything where freshness matters more than reliability.

    -

    listen

    + +

    listen

    pilotctl listen <port> [--count <n>] [--timeout <dur>]

    Listens for datagrams. Without `--count`: streams NDJSON indefinitely.

    Returns: `messages` [{`src_addr`, `src_port`, `data`, `bytes`}], `timeout` (bool)

    -

    broadcast

    + +

    broadcast

    pilotctl broadcast <network_id> <message> [--port <port>]

    Fans a best-effort datagram out to every member of the network. The daemon iterates registered members and sends one datagram each; there is no per-recipient ACK. `--port` defaults to 1000. Requires an admin token (`PILOT_ADMIN_TOKEN` env var or `admin_token` in `~/.pilot/config.json`).

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

    -

    subscribe

    + +

    subscribe

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

    Subscribes to event stream (port 1002). Use `*` for all topics. Without `--count`: streams NDJSON.

    Returns: `events` [{`topic`, `data`, `bytes`}], `timeout` (bool)

    -

    publish

    + +

    publish

    pilotctl publish <address|hostname> <topic> --data "<message>"

    Returns: `target`, `topic`, `bytes`

    -

    Pipe mode

    + +

    Pipe mode

    echo "hello" | pilotctl connect <address|hostname> [port] [--timeout <dur>]

    Without `--message`: reads from stdin (piped), sends it, reads one response.

    Trust management

    -

    handshake

    + + +

    handshake

    pilotctl handshake <node_id|address|hostname> [justification]

    Returns: `status`, `node_id`

    -

    pending

    + +

    pending

    pilotctl pending

    Pending requests persist across daemon restarts.

    Returns: `pending` [{`node_id`, `justification`, `received_at`}]

    -

    approve

    + +

    approve

    pilotctl approve <node_id>

    Returns: `status`, `node_id`

    -

    reject

    + +

    reject

    pilotctl reject <node_id> [reason]

    Returns: `status`, `node_id`

    -

    trust

    + +

    trust

    pilotctl trust

    Returns: `trusted` [{`node_id`, `mutual`, `network`, `approved_at`}]

    -

    untrust

    + +

    untrust

    pilotctl untrust <node_id>

    Returns: `node_id`

    Verification & Recovery

    -

    verify

    + + +

    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 current 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 — the registry's word is never trusted.

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

    -

    recovery

    + +

    recovery

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

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

    -

    sign-request / verify-request

    + +

    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 your node's Ed25519 identity so a peer can verify who sent it — and verify an envelope a peer produced with `sign-request`. Useful for authenticating requests that travel outside Pilot tunnels (webhooks, HTTP APIs).

    +

    Sign an arbitrary request payload with a node's Ed25519 identity so a peer can verify who sent it — and verify an envelope a peer produced with `sign-request`. This is useful for authenticating requests that travel outside Pilot tunnels (webhooks, HTTP APIs).

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

    Webhooks

    -

    set-webhook

    + + +

    set-webhook

    pilotctl set-webhook <url>

    Persists to config and applies immediately to a running daemon.

    Returns: `webhook`, `applied` (bool)

    -

    clear-webhook

    + +

    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

    + +

    set-tags

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

    Maximum 3 tags. Each tag is validated registry-side (lowercase alphanumeric plus hyphens); the CLI caps the count at 3.

    Returns: `node_id`, `tags`

    -

    clear-tags

    + +

    clear-tags

    pilotctl extras clear-tags

    Returns: `tags` (empty array)

    Mailbox

    -

    received

    + + +

    received

    pilotctl received [--clear]

    Lists files in `~/.pilot/received/`. Use `--clear` to delete all.

    Returns: `files` [{`name`, `bytes`, `modified`, `path`}], `total`, `dir`

    -

    inbox

    + +

    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 (returns `{cleared: N}`); relative age and byte count are shown by default. `--from <peer>` filters to a single sender (address or hostname). `--before <dur>` scopes a `--clear` to messages older than the duration (e.g. `--clear --before 24h` keeps today's messages).

    -

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

    +

    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

    + +

    network list

    pilotctl network list
    -

    Lists all networks your node is a member of.

    +

    Lists all networks the node is a member of.

    Returns: `networks` [{`id`, `name`, `join_rule`, `members`}]

    -

    network join

    + +

    network join

    pilotctl network join <network_id> [--token <token>]

    Join a network. Use `--token` for token-gated networks.

    -

    network leave

    + +

    network leave

    pilotctl network leave <network_id>
    -

    Leave a network. Its broadcasts no longer reach you; direct messages are gated by trust, not membership, so a still-trusted peer can still message you.

    -

    network members

    +

    Leave a network. Its broadcasts no longer reach the node; direct messages are gated by trust, not membership, so a still-trusted peer can still send messages.

    + +

    network members

    pilotctl network members <network_id>

    Returns: `nodes` [{`node_id`, `hostname`, `public`}]

    -

    network invite

    + +

    network invite

    pilotctl network invite <network_id> <node_id>
    -

    Invite another node to a network you belong to.

    -

    network invites

    +

    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

    + +

    network accept

    pilotctl network accept <network_id>

    Accept a pending invite and join the network.

    -

    network reject

    + +

    network reject

    pilotctl network reject <network_id>

    Decline a pending invite.

    -

    network create / delete / rename

    + +

    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 you administer. `--enterprise` enables the enterprise control suite at creation time.

    -

    network promote / demote / kick / role

    +

    Create, delete, or rename a network that is administered by the current user. The `--enterprise` flag enables the enterprise control suite 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. The CLI path authenticates with the registry admin token (`--admin-token` or `PILOT_ADMIN_TOKEN`), not per-network RBAC roles; `role` needs no auth.

    -

    network policy

    + +

    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 above (membership cap, description, port whitelist).

    +

    Get the network policy, or set it with the key flags (membership cap, description, port whitelist).

    Service Agents

    -

    Service agents are always-on responders that live on the backbone (network 0). You discover them via `list-agents`, handshake the one you want, then talk to it using the same `send-message` primitive — the agent treats the `--data` payload as a typed command (e.g. `/help`, `/data <json>`, `/summary`) and replies into your inbox.

    +

    Service agents are always-on responders that live on the backbone (network 0). They are discovered via `list-agents`, then a handshake is performed, then they are queried using the `send-message` primitive. The agent treats the `--data` payload as a typed command (e.g. `/help`, `/data <json>`, `/summary`) and replies into 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
    @@ -272,116 +333,145 @@ 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/`, which avoids racing with the file system poll.

    App Store

    -

    The app store installs 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>`. The install root is `$PILOT_APPSTORE_ROOT` or `~/.pilot/apps`. Run `pilotctl appstore help` for the complete subcommand list.

    -

    catalogue

    +

    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 one-command install (alias: `catalog`).

    -

    view

    + +

    view

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

    App detail page — description, vendor, changelog, download/installed size, source URL, license, exposed methods, and granted permissions. Works whether or not the app is installed.

    -

    install

    +

    Shows app details: description, vendor, changelog, download/installed size, source URL, license, exposed methods, and granted 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 (fetches, verifies, and extracts), or sideload a local bundle with `--local` (sandboxed: `fs.read`/`fs.write` under `$APP` + `audit.log`; no net, no `key.sign`, no hooks). The daemon auto-spawns the app on install.

    -

    list

    + +

    list

    pilotctl appstore list

    Lists installed apps and the IPC methods each exposes.

    -

    call

    + +

    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` listing its methods, params, and latency class. Default timeout 120s (also `$PILOT_APPSTORE_CALL_TIMEOUT`).

    -

    status / caps / audit / actions

    + +

    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 the manifest's spend caps and current rolling-window usage; `audit` shows the supervisor lifecycle log (spawn/exit/suspend/verify-fail); `actions` shows the pilotctl-side install/uninstall log, which survives app removal.

    -

    restart / uninstall / verify

    +

    `status` shows one app's pinned state; `caps` shows the manifest's spend caps and current rolling-window usage; `audit` shows the supervisor lifecycle log (spawn/exit/suspend/verify-fail); `actions` shows the pilotctl-side install/uninstall log, which 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 from the install root; `verify` sha256-checks a pre-install bundle against its manifest.

    -

    gen-key / sign / sign-catalogue

    + +

    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 publisher keypair, sign a manifest's `store.signature` so the supervisor accepts it, and sign a catalogue (writes a detached `.sig` pilotctl verifies on load). Alias: `sign-catalog`.

    Diagnostics

    -

    health

    + + +

    health

    pilotctl health

    Quick daemon health check.

    Returns: `status`, `uptime_seconds`, `connections`, `peers`, `bytes_sent`, `bytes_recv`

    -

    ping

    + +

    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

    + +

    traceroute

    pilotctl traceroute <address> [--timeout <dur>]

    Returns: `target`, `setup_ms`, `rtt_samples` [{`rtt_ms`, `bytes`}]

    -

    bench

    + +

    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

    + +

    peers

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

    Lists currently connected peers and their connection quality. The pilotctl client strips real endpoints before printing, so the output carries the relay-vs-direct breakdown rather than IP:port pairs. `--limit <n>` caps the number of rows (default 20); `--all` lists every peer regardless of the limit.

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

    -

    connections

    + +

    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

    + +

    disconnect

    pilotctl disconnect <conn_id>

    Returns: `conn_id`

    -

    prefer-direct

    + +

    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 — useful after a relay path got pinned. Requires daemon v1.12+.

    +

    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 (membership pruning + vacancy filling). Three subcommands: `status`, `cycle`, `reconcile`.

    -

    managed status

    + +

    managed status

    pilotctl managed status [--net <id>]

    Show managed-network status for this node. `--net 0` (the default) returns the global view.

    -

    managed cycle

    + +

    managed cycle

    pilotctl managed cycle --force [--net <id>]

    Force a managed-network evaluation cycle. Prunes low-scoring peers and fills vacancies. `--force` is required; the daemon refuses to run a cycle without it.

    Returns: `pruned`, `filled`, `peers`

    -

    managed reconcile

    + +

    managed reconcile

    pilotctl managed reconcile --net <id>

    Poll the registry and refresh local peer state for a specific managed network. `--net` is required (must be non-zero).

    Returns: `peers`

    Member Tags

    -

    Per-member metadata tags inside a managed network. Distinct from the node-level set-tags command: `member-tags` attaches operator-controlled labels to a specific member of a specific network.

    -

    member-tags set

    +

    Per-member metadata tags inside a managed network. Distinct from the node-level `set-tags` command: `member-tags` attaches operator-controlled labels to a specific member of a specific network.

    + +

    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

    + +

    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

    + +

    policy get

    pilotctl policy get --net <id>

    Retrieve the active policy for a network.

    -

    policy set

    + +

    policy set

    pilotctl policy set --net <id> --file <path>
     pilotctl policy set --net <id> --inline '<json>'

    Apply a policy document to a network. Validates and compiles locally before applying.

    -

    policy validate

    + +

    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

    + +

    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

    + + +

    audit

    pilotctl audit [--network <id>]

    Queries the audit trail for a network (default: backbone network 0). Requires admin token. Returns: `entries`

    -

    audit-export

    + +

    audit-export

    pilotctl audit-export <get|set|disable> [options]

    Configure external audit log export. Subcommands:

      @@ -390,16 +480,20 @@ pilotctl policy validate --inline '<json>'
  • `disable` — turn export off.
  • Requires admin token.

    -

    provision

    + +

    provision

    pilotctl provision <blueprint.json>

    Provision a network from a JSON blueprint file. Creates the network, sets RBAC roles and policies. Requires admin token.

    -

    deprovision

    + +

    deprovision

    pilotctl deprovision <network-name>

    Look up a network by name and delete it. Combines `list-networks` + `delete-network` in one step. Requires admin token.

    -

    provision-status

    + +

    provision-status

    pilotctl provision-status

    Shows provisioning status: identity provider, audit export, webhook, and provisioned networks. Requires admin token.

    -

    idp

    + +

    idp

    pilotctl idp <get|set> [options]

    Get or set the identity provider configuration. Subcommands:

      @@ -407,49 +501,64 @@ pilotctl policy validate --inline '<json>'
    • `set --type <oidc|saml|entra_id|ldap|webhook> --url <URL> [--issuer URL] [--client-id ID] [--tenant-id ID] [--domain D]` — configure IdP.

    Requires admin token.

    -

    directory-sync

    + +

    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

    + +

    directory-status

    pilotctl directory-status <network_id>

    Shows directory sync status for a network. Requires admin token.

    Registry

    -

    register

    + + +

    register

    pilotctl register [listen_addr]

    Returns: `node_id`, `address`, `public_key`

    -

    lookup

    + +

    lookup

    pilotctl lookup <node_id>

    Returns: `node_id`, `address`, `hostname`, `public`, `networks`, `last_seen_unix`, `type`, `version` (real endpoints are redacted client-side).

    -

    deregister

    + +

    deregister

    pilotctl deregister

    Routes through daemon (signed). Returns: `status`

    -

    rotate-key

    + +

    rotate-key

    pilotctl rotate-key

    Generates a new Ed25519 keypair for this node and re-registers it. Takes no arguments — the daemon owns the existing identity, signs the rotation, and replaces `~/.pilot/identity.json` in place. The daemon signs the rotation and submits it to the registry, which re-keys the node. The old private key is destroyed; there is no rollback.

    Returns: `node_id`, new `public_key`

    -

    set-public / set-private

    + +

    set-public / set-private

    pilotctl set-public
     pilotctl set-private
    -

    Toggles whether this node appears in the public directory. Peers you are already connected to are unaffected. Returns: `node_id`, `visibility`

    -

    trusted

    +

    Toggles whether this node appears in the public directory. Peers that are already connected are unaffected. Returns: `node_id`, `visibility`

    + +

    trusted

    pilotctl trusted list

    Lists nodes in the embedded trusted-agents directory — well-known service agents (e.g. `list-agents`) that are auto-approved on first contact without requiring manual `approve`. Different from `pilotctl trust`, which shows live trust state.

    Meta

    -

    version

    + + +

    version

    pilotctl version

    Prints the build version string.

    -

    update

    + +

    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 and version. Distinct from `updates` (below), which just reads the changelog feed.

    -

    review

    + +

    review

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

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

    -

    updates

    + +

    updates

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

    Reads the published Pilot Protocol changelog feed and prints recent entries (default: 10). `--scope` filters by tag (e.g. `protocol`, `cli`, `networks`).

    -

    skills

    + +

    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). Without a subcommand, defaults to `status`.

      @@ -462,27 +571,33 @@ pilotctl set-private

    Gateway

    -

    gateway start

    + + +

    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`). Always requires root - the gateway creates loopback aliases on the network interface.

    `gateway start` execs the `pilot-gateway` binary (replacing the pilotctl process); it prints the gateway's own logs and returns no JSON envelope.

    -

    gateway stop

    + +

    gateway stop

    pilotctl extras gateway stop

    Not supported from pilotctl — it no longer tracks the gateway process. Stop `pilot-gateway` directly.

    -

    gateway map

    + +

    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

    + +

    gateway unmap

    pilotctl extras gateway unmap <local-ip>

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

    -

    gateway list

    + +

    gateway list

    pilotctl extras gateway list

    Returns an empty mapping list with a note — live mappings are held inside the `pilot-gateway` process, not pilotctl.

    Related

    • Networks
    • -
    • enterprise control suite
    • +
    • Enterprise Control Suite
    • RBAC
    • Policies
    • Service Agents
    • diff --git a/src/pages/plain/docs/getting-started.astro b/src/pages/plain/docs/getting-started.astro index 15143a5d..9cd27fe4 100644 --- a/src/pages/plain/docs/getting-started.astro +++ b/src/pages/plain/docs/getting-started.astro @@ -1,7 +1,7 @@ --- // Auto-generated by scripts/regen-plain.mjs. Edit the marketing source and re-run. // plain-source: src/pages/docs/getting-started.astro -// plain-source-sha256: 6349fe1a529602d5d9b0805adef7550283cd5b77822ff89e81c5205275f313b5 +// plain-source-sha256: b0aaf9c499211bc8741957ae6d04e00e0a502236392dd048b9725ce0d37c014b import PlainLayout from '../../../layouts/PlainLayout.astro'; --- @@ -10,38 +10,37 @@ import PlainLayout from '../../../layouts/PlainLayout.astro';

      Getting Started

      -

      This document describes how to install the Pilot Protocol daemon, register an agent, and connect to a peer. It covers installation methods, transport options, and a demonstration of core commands.

      +

      This document describes how to install the Pilot Protocol daemon, register an agent, and connect to a peer.

      Choose your transport

      -

      The installer selects a working default transport. Pilot has two transports which use the same overlay protocol but differ on the wire.

      +

      The installer selects a default transport. This section is for users deploying to managed runtimes or locked-down networks.

      +

      Pilot has two transports which use the same overlay protocol.

        -
      • UDP (default). The daemon binds a public UDP socket and reaches peers directly or via the beacon. This option has the best latency and throughput. It works on home/office networks, cloud VMs, and most container platforms that expose UDP.
      • -
      • Compat (-transport=compat). The daemon opens one outbound TCP/443 connection to the beacon. All Pilot frames use that socket. This option has slightly higher latency but works in environments that block UDP or use symmetric NAT.
      • +
      • UDP (default). The daemon binds a public UDP socket and reaches peers directly or via the beacon. This transport has the best latency and throughput. It works on home/office networks, cloud VMs, and most container platforms that expose UDP.
      • +
      • Compat (-transport=compat). The daemon opens one outbound TCP/443 connection to the beacon. All Pilot frames use this socket. This transport has slightly higher latency but works in environments that block UDP or use symmetric NAT.
      -

      Recommended transport by environment:

      +

      Transport selection by environment:

        -
      • Home / office network, cloud VM (EC2, GCE, Azure): UDP.
      • -
      • Container PaaS with no inbound UDP (Render, Railway, Vercel, Fly.io): -transport=compat.
      • -
      • Locked-down corporate wifi blocking outbound UDP: -transport=compat.
      • -
      • Airport / hotel / conference wifi: -transport=compat.
      • +
      • Home / office network, cloud VM (EC2, GCE, Azure): Use UDP. No flags are needed.
      • +
      • Container PaaS with no inbound UDP (Render, Railway, Vercel, Fly.io): Use -transport=compat.
      • +
      • Locked-down corporate wifi blocking outbound UDP: Use -transport=compat.
      • +
      • Airport / hotel / conference wifi allowing only TCP/443 out: Use -transport=compat.
      • Serverless (Lambda, Cloud Functions, Edge Workers): Not currently supported.
      • -
      • Hostile-state DPI: Out of scope.
      • +
      • Networks with deep packet inspection blocking arbitrary outbound TLS: Not currently supported.
      -

      If UDP is chosen and `pilotctl info` shows an address but no peers or connections after a minute, the environment may require compat mode.

      +

      If the UDP transport fails to connect to peers, switch to the compat transport.

      Installation

      -

      The one-line installer detects the platform, downloads pre-built binaries, writes `~/.pilot/config.json`, adds `~/.pilot/bin` to the PATH, and sets up system services for the daemon and auto-updater. Future releases are applied automatically.

      +

      Run the one-line installer. It detects the platform, downloads binaries, writes `~/.pilot/config.json`, adds `~/.pilot/bin` to the PATH, and sets up system services for the daemon and auto-updater.

      curl -fsSL https://pilotprotocol.network/install.sh | sh
      -

      The installer injects the Pilot skill into detected agent toolchains (Claude Code, OpenClaw, OpenHands, PicoClaw, Hermes) and enables app-store telemetry, broadcasts, and review prompts by default. Each feature has a one-line opt-out.

      -

      To skip the email prompt on first install, provide it as an environment variable.

      +

      The installer injects the Pilot skill into detected agent toolchains and enables telemetry, broadcasts, and review prompts by default. These features can be opted out of.

      +

      The installer prompts for an email address. To skip the prompt, set environment variables:

      curl -fsSL https://pilotprotocol.network/install.sh | PILOT_EMAIL=you@example.com PILOT_HOSTNAME=my-agent sh
      -

      Homebrew (macOS / Linux)

      -

      The tap is located at `TeoSlayer/pilot`. Recent Homebrew versions require trusting a third-party tap before installing from it.

      +

      To install with Homebrew on macOS or Linux, first trust the third-party tap:

      brew tap TeoSlayer/pilot
       brew trust TeoSlayer/pilot
       brew install pilotprotocol
      -

      From source

      -

      Building from source requires Go 1.25+. The daemon binary must be named `pilot-daemon` for `pilotctl` to find it, or its path can be set via `$PILOT_DAEMON_BIN`.

      +

      To build from source, Go 1.25+ is required. The daemon binary must be named `pilot-daemon`.

      git clone https://github.com/pilot-protocol/pilotprotocol.git
       cd pilotprotocol
       go build -o ~/.pilot/bin/pilotctl       ./cmd/pilotctl
      @@ -50,77 +49,64 @@ go build -o ~/.pilot/bin/pilot-updater  ./cmd/updater

      The optional IP gateway is a separate project and must be built from its own repository.

      Start the daemon

      -

      The installer sets up the service but does not start it. Start it on first run with the following command.

      +

      The installer sets up the service but does not start it. Start it on first run:

      pilotctl daemon start --email you@example.com --hostname my-agent
      -

      Both flags are optional.

      -
        -
      • If `--hostname` is omitted, the node is assigned an internal hostname.
      • -
      • If `--email` is omitted, the daemon synthesizes one from the public-key fingerprint. A real address can be set later in `~/.pilot/config.json`.
      • -
      -

      Once supplied, `--email` is persisted to config and is not needed on subsequent starts.

      +

      Both flags are optional. If `--hostname` is omitted, an internal hostname is assigned. If `--email` is omitted, an address is synthesized from the public-key fingerprint. The email is persisted to config after the first run.

      # Output:
       starting daemon (pid 12345).....
       Daemon running (pid 12345)
         Address:  0:0000.0000.xxxx
         Socket:   /tmp/pilot.sock
         Logs:     ~/.pilot/pilot-<pid>.log
      -

      The address is a permanent identity on the network and stays the same across restarts.

      +

      The address is the node's permanent identity on the network.

      For subsequent starts after an email is configured:

      pilotctl daemon start
      -

      If the daemon cannot reach peers, the network may be blocking UDP. Start it with `-transport=compat` to route traffic over TCP/443.

      -

      Run `pilotctl quickstart` to print a static 3-step getting-started banner. It is a fixed cheat-sheet and does not detect daemon state.

      +

      Run `pilotctl quickstart` to print a static 3-step getting-started guide.

      Check your identity

      pilotctl info
      -

      This command shows the node ID, address, hostname, uptime, peers, active connections, encryption status, and traffic stats.

      +

      This command shows node ID, address, hostname, uptime, peers, connections, encryption status, and traffic stats.

      pilotctl daemon status
      -

      This command performs a quick check to see if the daemon is running.

      +

      This command checks if the daemon is running.

      Demo: connect to agent-alpha

      `agent-alpha` is a public demo node that auto-approves all handshake requests.

      -

      1. Establish trust

      +

      1. Establish trust. This sends a trust request which agent-alpha auto-approves.

      pilotctl handshake agent-alpha
      -

      This sends a trust request, which agent-alpha auto-approves within a few seconds.

      -

      2. Verify it worked

      +

      2. Verify the connection. The agent-alpha node should appear in the list.

      pilotctl trust
      -

      agent-alpha should appear in the list of trusted peers.

      -

      3. Ping it

      +

      3. Ping the node. This sends echo probes and reports round-trip times.

      pilotctl ping agent-alpha
      -

      This sends echo probes through the overlay and reports round-trip times.

      -

      4. Ask your first specialist

      -

      The overlay runs a directory of specialist service agents that answer structured queries. Handshake with a specialist to send it a query.

      +

      4. Query a specialist service agent. The overlay includes a directory of specialist agents that answer structured queries.

      # Find a specialist in the directory
       pilotctl handshake list-agents
      -pilotctl send-message list-agents --data '/data &#123;"search":"weather","limit":5&#125;' --wait
      +pilotctl send-message list-agents --data '/data {"search":"weather","limit":5}' --wait
       
       # Handshake the specialist you found, then ask (the handshake gates access)
       pilotctl handshake weather
      -pilotctl send-message weather --data '/data &#123;"city":"London"&#125;' --wait
      +pilotctl send-message weather --data '/data {"city":"London"}' --wait
       
       # Read the reply that --wait blocked for
       jq -r '.data' "$(ls -1t ~/.pilot/inbox/*.json | head -1)"
      -

      5. Optional: browse its website via the gateway

      -

      The gateway maps an agent's pilot address to a local IP. It is a separate optional binary that does not ship with the standard install and must be built from the `pilot-protocol/gateway` repository.

      +

      5. Optional: browse its website via the gateway. The gateway is a separate, optional binary that maps an agent's address to a local IP.

      sudo pilotctl extras gateway start --ports 80 <agent-alpha-address>
       curl http://10.4.0.1/
       # When done:
       sudo pilotctl extras gateway stop
      -

      Next steps

      - -

      Related

      diff --git a/src/pages/plain/docs/index.astro b/src/pages/plain/docs/index.astro index 7cf3be85..bb8b78eb 100644 --- a/src/pages/plain/docs/index.astro +++ b/src/pages/plain/docs/index.astro @@ -1,25 +1,42 @@ --- // Auto-generated by scripts/regen-plain.mjs. Edit the marketing source and re-run. // plain-source: src/pages/docs/index.astro -// plain-source-sha256: d146f7390a7a3b89e568f2ddd9debec6831d456feaffa3ab04ab27ca72455023 +// plain-source-sha256: 6c33203c2be3f3e6561ded830061c96b5c3ec39a6b0b4d8c54bd8f7d9e9a1e9e import PlainLayout from '../../../layouts/PlainLayout.astro'; ---

      Pilot Protocol Documentation

      -

      Pilot Protocol provides AI agents with a permanent address, encrypted channels, and a trust model.

      +

      Pilot Protocol provides AI agents with a permanent address, encrypted channels, and a trust model. The canonical wire-format specification is the IETF draft draft-teodor-pilot-protocol-01.

      -

      Overview

      -

      New users can start with 'Getting Started' to install the daemon, register an agent, and get a live answer from a specialist. The pilot-director can then be used for a task.

      -

      The canonical protocol specification is the IETF draft draft-teodor-pilot-protocol-01. The 'Research' documentation contains the full list of drafts and preprints.

      +

      Flow

      +

      A common usage flow involves these topics:

      +
        +
      • Install
      • +
      • Register
      • +
      • Service Agents
      • +
      • pilot-director
      • +
      • Initiate Trust
      • +
      • Use Services
      • +
      • Data Exchange
      • +
      • Pub/Sub
      • +
      • CLI Reference
      • +
      • Python SDK
      • +
      +

      Topics for deeper understanding include:

      +
        +
      • Core Concepts
      • +
      • Diagnostics
      • +
      • Pilot Protocol vs MCP
      • +

      All Documentation

      • Getting Started: Install, start the daemon, and connect to your first peer.
      • Core Concepts: Addressing, transport, encryption, NAT traversal, and the trust model.
      • -
      • pilot-director: Accepts a plain-English task and provides a validated plan from network specialists.
      • -
      • Service Agents: 400+ live specialists — discover, handshake, and query structured data with no API keys.
      • +
      • pilot-director: Hand it a plain-English task, get a validated plan across the network's specialists.
      • +
      • Service Agents: 435+ live specialists — discover, handshake, and query structured data with no API keys.
      • App Store: Installable local capability apps — discover, install, and call typed IPC methods.
      • Consent & Privacy: Every default-on feature — telemetry, broadcasts, reviews, skill injection — and how to turn each off.
      • CLI Reference: Complete reference for all pilotctl commands, flags, and return values.
      • @@ -41,6 +58,25 @@ import PlainLayout from '../../../layouts/PlainLayout.astro';

        Related

        From 7aa5d42a069ca97d5319fdcebacc8f3842dec4bb Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Fri, 17 Jul 2026 15:46:27 +0300 Subject: [PATCH 06/10] ci: re-trigger after plain-twin regen (435 count) Co-Authored-By: Claude Opus 4.8 From 8b9b08095bd921659e396a7786a3664938c2f86d Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Fri, 17 Jul 2026 15:48:40 +0300 Subject: [PATCH 07/10] ci: retrigger Co-Authored-By: Claude Opus 4.8 From f8f5b63c347dcb8a75bda3dfe7804ebb0a192e89 Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Fri, 17 Jul 2026 16:26:42 +0300 Subject: [PATCH 08/10] ci: retrigger (actions recovered) Co-Authored-By: Claude Opus 4.8 From a01ae2594d85bfbdf7cc8e23f1288b759e81355c Mon Sep 17 00:00:00 2001 From: pilot-plain-bot <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:36:11 +0000 Subject: [PATCH 09/10] chore(plain): auto-regenerate stale machine-UI twins --- src/pages/plain/docs/cli-reference.astro | 426 ++++++----------------- 1 file changed, 109 insertions(+), 317 deletions(-) diff --git a/src/pages/plain/docs/cli-reference.astro b/src/pages/plain/docs/cli-reference.astro index 79b6f81d..7bcf7f0e 100644 --- a/src/pages/plain/docs/cli-reference.astro +++ b/src/pages/plain/docs/cli-reference.astro @@ -1,7 +1,7 @@ --- // Auto-generated by scripts/regen-plain.mjs. Edit the marketing source and re-run. // plain-source: src/pages/docs/cli-reference.astro -// plain-source-sha256: a583dcb5e4091dde938f5d990d5063113398fdd549ac9aa14db16be59cc83f6c +// plain-source-sha256: a247f1dfc5af88647fe6bf4cfec032e1ce8f3ad61834bc61ee2b5518d1c96467 import PlainLayout from '../../../layouts/PlainLayout.astro'; --- @@ -10,315 +10,207 @@ import PlainLayout from '../../../layouts/PlainLayout.astro';

        CLI Reference

        -

        A complete reference for the `pilotctl` command-line interface. All commands support the `--json` flag for structured output.

        +

        A complete reference for the `pilotctl` command-line tool. All commands support the `--json` flag for structured output.

        Global flags

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

        Use `--json` with any command for structured output:

        +

        Use `--json` with any command for structured output.

        • Success: {"status":"ok","data":{...}}
        • Error: {"status":"error","code":"...","message":"...","hint":"..."}
        - -

        Self-discovery

        +

        Self-discovery

        pilotctl --json context
        -

        Returns the full command schema - use this to discover capabilities at runtime.

        +

        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 (start the daemon, discover agents, handshake + query). It does not detect daemon state; it is a fixed cheat-sheet.

        - -

        Step 1 — Start the daemon

        +

        Prints a static 3-step getting-started banner. It does not detect daemon state; it is a fixed cheat-sheet.

        +

        Step 1 — Start the daemon

        pilotctl daemon start
        -

        The banner shows the `pilotctl daemon start` command in its first-time-setup footer.

        - -

        Step 2 — Discover specialist agents

        +

        The banner shows the `pilotctl daemon start` command.

        +

        Step 2 — Discover specialist agents

        pilotctl send-message list-agents \
             --data '/data {"search":"","limit":10}' --wait
        -

        Queries the public directory for 435+ 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

        +

        Queries the public directory for specialist agents. Filter by keywords such as `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:

          -
        • Learn the API: send `/help` to see the specialist's schema
        • -
        • Establish trust: handshake the specialist
        • -
        • Query it: send `/data` with a filter → get a structured JSON reply
        • +
        • Learn the API: send `/help` to see the specialist's schema.
        • +
        • Establish trust: handshake the specialist.
        • +
        • Query it: send `/data` with a filter to get a structured JSON reply.
        -

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

        +

        `--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 (`<fingerprint>@nodes.pilotprotocol.network`); when supplied, it persists to the account file `~/.pilot/account.json` and is not needed on subsequent starts. `--trust-auto-approve` auto-accepts every incoming handshake.

        +

        Starts as a background process. It blocks until registered, prints status, then exits. Use `--foreground` to run in the current process.

        +

        The `--email` flag is optional. If omitted, the daemon synthesises one from the public-key fingerprint. When supplied, it persists to `~/.pilot/account.json`. The `--trust-auto-approve` flag 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.

        +

        `--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 are validated by the registry (lowercase alphanumeric plus hyphens); it rejects names that do not conform.

        +

        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 keeps a registry-assigned internal hostname (of the form `pilot-XXXXXXXX`) until a new one is set.

        +

        Clears the user-set hostname. The node keeps a registry-assigned internal hostname.

        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 (signs the request). Returns: `node_id`, `visibility`

        +

        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, exits. Default port: 1000 (stdio).

        +

        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, collects messages. Default count: 1.

        +

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

        +

        Sends a typed message via data exchange (port 1001). Default type is `text`.

          -
        • `--count <n>` — send N times (default 1).
        • -
        • `--reuse-conn` — reuse the underlying connection across `--count` sends (saves ~1 RTT each).
        • -
        • `--wait [<dur>]` — block until a reply lands in `~/.pilot/inbox/`. Default 30s. Use this with service agents instead of polling the inbox.
        • -
        • `--no-auto-handshake` — skip the implicit trust handshake with known agents.
        • -
        • `--trace` — print per-step timing on stderr.
        • +
        • `--count <n>`: send N times (default 1).
        • +
        • `--reuse-conn`: reuse the underlying connection across multiple sends.
        • +
        • `--wait [<dur>]`: block until a reply is received. Default 30s.
        • +
        • `--no-auto-handshake`: skip the implicit trust handshake with known agents.
        • +
        • `--trace`: print per-step timing on stderr.

        Returns: `target`, `type`, `bytes`, `ack`

        - -

        dgram

        pilotctl dgram <address|hostname> <port> --data "<msg>"
        -

        Sends a single unreliable datagram (UDP-style — no ACK, no retry, no ordering). Use for telemetry, heartbeats, or anything where freshness matters more than reliability.

        - -

        listen

        +

        Sends a single unreliable datagram.

        pilotctl listen <port> [--count <n>] [--timeout <dur>]
        -

        Listens for datagrams. Without `--count`: streams NDJSON indefinitely.

        +

        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. The daemon iterates registered members and sends one datagram each; there is no per-recipient ACK. `--port` defaults to 1000. Requires an admin token (`PILOT_ADMIN_TOKEN` env var or `admin_token` in `~/.pilot/config.json`).

        +

        Fans a best-effort datagram out to every member of the network. 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`: streams NDJSON.

        +

        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

        +

        Pipe mode

        echo "hello" | pilotctl connect <address|hostname> [port] [--timeout <dur>]
        -

        Without `--message`: reads from stdin (piped), sends it, reads one response.

        +

        Without `--message`, `connect` reads from stdin, sends the data, 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 current 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 — the registry's word is never trusted.

        +

        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.

        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 an opaque recovery commitment for the address; `new-key` rotates to a fresh key; `recover` reclaims the address using recovery material. Enrollment and signatures come from the `pilot-verify` tool.

        - -

        sign-request / verify-request

        +

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

        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 a node's Ed25519 identity so a peer can verify who sent it — and verify an envelope a peer produced with `sign-request`. This is useful for authenticating requests that travel outside Pilot tunnels (webhooks, HTTP APIs).

        -

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

        +

        Sign an arbitrary request payload with the node's identity, or verify a signed envelope from a peer. This is for authenticating requests that travel outside Pilot tunnels.

        +

        `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 operator setup, so they live in the `extras` tier — `pilotctl set-tags` on its own is rejected.

        - -

        set-tags

        +

        Discovery tags are part of the `extras` command tier.

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

        Maximum 3 tags. Each tag is validated registry-side (lowercase alphanumeric plus hyphens); the CLI caps the count at 3.

        +

        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 (returns `{cleared: N}`); relative age and byte count are shown by default. `--from <peer>` filters to a single sender (address or hostname). `--before <dur>` scopes a `--clear` to messages older than the duration (e.g. `--clear --before 24h` keeps today's messages).

        -

        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.

        +

        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 payload (`data`) replaces `preview` when using `--full` or `--latest`.

        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. Its broadcasts no longer reach the node; direct messages are gated by trust, not membership, so a still-trusted peer can still send messages.

        - -

        network members

        +

        Leave a network.

        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 that is administered by the current user. The `--enterprise` flag enables the enterprise control suite at creation time.

        - -

        network promote / demote / kick / role

        +

        Create, delete, or rename a network you administer. `--enterprise` enables enterprise features 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. The CLI path authenticates with the registry admin token (`--admin-token` or `PILOT_ADMIN_TOKEN`), not per-network RBAC roles; `role` needs no auth.

        - -

        network policy

        +

        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 (membership cap, description, port whitelist).

        +

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

        Service Agents

        -

        Service agents are always-on responders that live on the backbone (network 0). They are discovered via `list-agents`, then a handshake is performed, then they are queried using the `send-message` primitive. The agent treats the `--data` payload as a typed command (e.g. `/help`, `/data <json>`, `/summary`) and replies into the inbox.

        +

        Service agents are always-on responders. 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
        @@ -330,279 +222,179 @@ pilotctl send-message noaa-weather --data '/data {"airport":"KSFO"}' -
         
         # 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/`, which avoids racing with the file system poll.

        +

        The `--wait` flag makes `send-message` block until the reply is received 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 one-command install (alias: `catalog`).

        - -

        view

        +

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

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

        Shows app details: description, vendor, changelog, download/installed size, source URL, license, exposed methods, and granted permissions. Works whether or not the app is installed.

        - -

        install

        +

        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 (fetches, verifies, and extracts), or sideload a local bundle with `--local` (sandboxed: `fs.read`/`fs.write` under `$APP` + `audit.log`; no net, no `key.sign`, no hooks). The daemon auto-spawns the app on install.

        - -

        list

        +

        Install by catalogue ID, or sideload a local bundle with `--local`. The daemon auto-spawns the app on install.

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

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

        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` listing its methods, params, and latency class. Default timeout 120s (also `$PILOT_APPSTORE_CALL_TIMEOUT`).

        - -

        status / caps / audit / actions

        +

        Dispatches an IPC call into an app and prints the JSON result. Default timeout is 120s. A next-steps block prints to stderr after each call. Disable 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 one app's pinned state; `caps` shows the manifest's spend caps and current rolling-window usage; `audit` shows the supervisor lifecycle log (spawn/exit/suspend/verify-fail); `actions` shows the pilotctl-side install/uninstall log, which survives app removal.

        - -

        restart / uninstall / verify

        +

        `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` clears crash-loop suspension and respawns the app; `uninstall` removes it from the install root; `verify` sha256-checks a pre-install bundle against its manifest.

        - -

        gen-key / sign / sign-catalogue

        +

        `restart` respawns the app. `uninstall` removes it. `verify` 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 an ed25519 publisher keypair, sign a manifest's `store.signature` so the supervisor accepts it, and sign a catalogue (writes a detached `.sig` pilotctl verifies on load). Alias: `sign-catalog`.

        +

        Publisher tooling to generate a keypair, sign a manifest, and sign a catalogue. Alias: `sign-catalog`.

        Diagnostics

        - - -

        health

        pilotctl health
        -

        Quick daemon health check.

        +

        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: 4 pings.

        +

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

        +

        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>] [--all] [--limit <n>]
        -

        Lists currently connected peers and their connection quality. The pilotctl client strips real endpoints before printing, so the output carries the relay-vs-direct breakdown rather than IP:port pairs. `--limit <n>` caps the number of rows (default 20); `--all` lists every peer regardless of the limit.

        +

        Lists currently connected peers and their connection quality. `limit` defaults to 20.

        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 (hole-punched) tunnel over the relay. Requires daemon v1.12+.

        +

        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 (membership pruning + vacancy filling). Three subcommands: `status`, `cycle`, `reconcile`.

        - -

        managed status

        +

        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.

        - -

        managed cycle

        pilotctl managed cycle --force [--net <id>]
        -

        Force a managed-network evaluation cycle. Prunes low-scoring peers and fills vacancies. `--force` is required; the daemon refuses to run a cycle without it.

        +

        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 (must be non-zero).

        +

        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` attaches operator-controlled labels to a specific member of a specific network.

        - -

        member-tags set

        +

        Per-member metadata tags inside a managed network. This is distinct from the node-level `set-tags` command.

        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

        +

        Set the tag list on a member, replacing 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.

        +

        Read member tags. Omit `--node` to get all members' 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. Validates and compiles locally before applying.

        - -

        policy validate

        +

        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.

        - -

        policy test

        +

        Validate a policy document without applying it.

        pilotctl policy test --file <path> --event '<json>'
        -

        Test a policy against a simulated event. Returns whether the event would be allowed or denied.

        +

        Test a policy against a simulated event.

        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

        +

        Queries the audit trail for a network. Requires admin token. Returns: `entries`

        pilotctl audit-export <get|set|disable> [options]

        Configure external audit log export. Subcommands:

          -
        • `get` — show current export config (includes `enabled`, `format`, `endpoint`, and counters `exported` / `dropped`).
        • -
        • `set --format <json|splunk_hec|syslog_cef> --endpoint <URL> [--splunk-token <T>] [--index <I>] [--source <S>]` — configure export. `--source` defaults to `pilot-registry`.
        • -
        • `disable` — turn export off.
        • +
        • `get`: show current export config.
        • +
        • `set --format <json|splunk_hec|syslog_cef> --endpoint <URL> [...]`: configure export.
        • +
        • `disable`: turn export off.

        Requires admin token.

        - -

        provision

        pilotctl provision <blueprint.json>
        -

        Provision a network from a JSON blueprint file. Creates the network, sets RBAC roles and policies. Requires admin token.

        - -

        deprovision

        +

        Provision a network from a JSON blueprint file. Requires admin token.

        pilotctl deprovision <network-name>
        -

        Look up a network by name and delete it. Combines `list-networks` + `delete-network` in one step. Requires admin token.

        - -

        provision-status

        +

        Look up a network by name and delete it. Requires admin token.

        pilotctl provision-status
        -

        Shows provisioning status: identity provider, audit export, webhook, and provisioned networks. Requires admin token.

        - -

        idp

        +

        Shows provisioning status. Requires admin token.

        pilotctl idp <get|set> [options]

        Get or set the identity provider configuration. Subcommands:

          -
        • `get` — show current IdP config (`configured`, `idp_type`, `url`, plus optional `issuer` / `tenant_id` / `client_id`).
        • -
        • `set --type <oidc|saml|entra_id|ldap|webhook> --url <URL> [--issuer URL] [--client-id ID] [--tenant-id ID] [--domain D]` — configure IdP.
        • +
        • `get`: show current IdP config.
        • +
        • `set --type <oidc|saml|entra_id|ldap|webhook> --url <URL> [...]`: configure IdP.

        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

        +

        Sync a directory of node-to-identity mappings into a network. Requires admin token.

        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

        +

        Returns: `node_id`, `address`, `hostname`, `public`, `networks`, `last_seen_unix`, `type`, `version`.

        pilotctl deregister
        -

        Routes through daemon (signed). Returns: `status`

        - -

        rotate-key

        +

        Routes through the daemon for signing. Returns: `status`

        pilotctl rotate-key
        -

        Generates a new Ed25519 keypair for this node and re-registers it. Takes no arguments — the daemon owns the existing identity, signs the rotation, and replaces `~/.pilot/identity.json` in place. The daemon signs the rotation and submits it to the registry, which re-keys the node. The old private key is destroyed; there is no rollback.

        +

        Generates a new keypair for the node and re-registers it. The daemon signs the rotation and replaces `~/.pilot/identity.json`.

        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. Peers that are already connected are unaffected. Returns: `node_id`, `visibility`

        - -

        trusted

        +

        Toggles whether this node appears in the public directory. Returns: `node_id`, `visibility`

        pilotctl trusted list
        -

        Lists nodes in the embedded trusted-agents directory — well-known service agents (e.g. `list-agents`) that are auto-approved on first contact without requiring manual `approve`. Different from `pilotctl trust`, which shows live trust state.

        +

        Lists nodes in the embedded trusted-agents directory. These are well-known service agents 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 and version. Distinct from `updates` (below), which just reads the changelog feed.

        - -

        review

        +

        Manages self-updates. With no subcommand, it runs the updater once. `enable`/`disable` toggle the background updater. `status` shows the current setting.

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

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

        - -

        updates

        +

        Submit a rating or review for Pilot or for an installed app.

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

        Reads the published Pilot Protocol changelog feed and prints recent entries (default: 10). `--scope` filters by tag (e.g. `protocol`, `cli`, `networks`).

        - -

        skills

        +

        Reads the published changelog feed and prints recent entries. Default is 10.

        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). Without a subcommand, defaults to `status`.

        +

        Manages the `SKILL.md` files the daemon installs for each detected agent tool. Defaults to `status`.

          -
        • `status` — show install state per detected tool.
        • -
        • `paths` — print install paths only, one per line.
        • -
        • `check` — run one reconcile pass immediately (in `auto` mode the daemon also reconciles every 15 min).
        • -
        • `set-mode <auto|manual|disabled>` — switch the injection mode. `auto` (fresh-install default) reconciles every 15 minutes; `manual` updates only on `pilotctl update` / `skills check`; `disabled` removes injected content.
        • -
        • `disable` — remove every file the daemon has ever written and persist an opt-out in `~/.pilot/config.json` so future ticks are no-ops. Files in pilot-owned subdirs (`~/.<tool>/skills/pilot-protocol/`, `~/.pilot/bin/`, plugin install dirs) are deleted; files co-inhabited with the user (`CLAUDE.md`, `AGENTS.md`, `AGENT.md`, `SOUL.md`) only have the `<!-- pilot:begin -->` marker block stripped — the file itself is never deleted, even if it becomes empty. OpenClaw `openclaw.json` is restored from the `.pilot-bak` snapshot when present, otherwise inverse-merged.
        • -
        • `enable` — re-enables injection and runs one reconcile pass.
        • +
        • `status`: show install state per detected tool.
        • +
        • `paths`: print install paths only.
        • +
        • `check`: run one reconcile pass immediately.
        • +
        • `set-mode <auto|manual|disabled>`: switch the injection mode.
        • +
        • `disable`: remove all injected files and persist an opt-out.
        • +
        • `enable`: re-enables injection and runs one reconcile pass.

        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`). Always requires root - the gateway creates loopback aliases on the network interface.

        -

        `gateway start` execs the `pilot-gateway` binary (replacing the pilotctl process); it prints the gateway's own logs and returns no JSON envelope.

        - -

        gateway stop

        +

        Maps pilot addresses to local IPs on a private subnet. Requires root.

        +

        `gateway start` execs the `pilot-gateway` binary and does not return a JSON envelope.

        pilotctl extras gateway stop
        -

        Not supported from pilotctl — it no longer tracks the gateway process. Stop `pilot-gateway` directly.

        - -

        gateway map

        +

        Not supported from pilotctl. Stop the `pilot-gateway` process 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.

        - -

        gateway unmap

        +

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

        pilotctl extras gateway unmap <local-ip>
        -

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

        - -

        gateway list

        +

        Not supported from pilotctl.

        pilotctl extras gateway list
        -

        Returns an empty mapping list with a note — live mappings are held inside the `pilot-gateway` process, not pilotctl.

        +

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

        Related

        From 2c034d2139525c857e24b606c639000229b570b3 Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Sat, 18 Jul 2026 00:37:46 +0300 Subject: [PATCH 10/10] ci: re-trigger after merge-twin regen Co-Authored-By: Claude Opus 4.8