diff --git a/src/pages/docs/consent.astro b/src/pages/docs/consent.astro index dd62a53..f905a0d 100644 --- a/src/pages/docs/consent.astro +++ b/src/pages/docs/consent.astro @@ -2,152 +2,258 @@ import DocLayout from "../../layouts/DocLayout.astro"; const bodyContent = `
Four opt-out features ship on by default. Here is exactly what each one does, what data it touches, and how to disable it — individually or all at once.
+Four features ship on by default. Each one is transparent about what it does, who benefits, and what you're accepting. This page explains each in plain English so you can make an informed choice.
All four features below are on by default (opt-out, not opt-in). Disabling any of them does not affect core messaging or networking — your daemon keeps routing, your tunnels keep running, your agents keep talking. The opt-out flags are stored in ~/.pilot/config.json under the consent key and are read at runtime:
All four features are on by default. They exist because they make Pilot more useful — for you, for the network, and for developers building on top of it. But each comes with a data and trust cost you should understand before accepting it. Disabling any of them does not affect core messaging, peer routing, or tunnel encryption.
+ +The three consent flags live in ~/.pilot/config.json under a consent key:
{
"consent": {
- "telemetry": false,
- "broadcasts": false,
- "reviews": false
+ "telemetry": true,
+ "broadcasts": true,
+ "reviews": true
}
}
- Skill injection has its own key and CLI commands (see Skill injection below).
+Set any of them to false to opt out. Skill injection has its own key and CLI — see Skill injection below.
Risk level: Low
-What it does: When you browse the app store or install an app, a signed event is sent to telemetry.pilotprotocol.network indicating the app ID and the action (view or install). This tells app developers how many agents have looked at or installed their app. No message contents, no personal data, no IP address beyond what TLS inherently reveals.
When you browse or install apps from the app store, a small signed event is sent to telemetry.pilotprotocol.network. Three events are emitted:
catalogue_viewed — fired once when you run pilotctl appstore catalogue. No payload beyond a timestamp and your identity signature.appstore_view — fired when you run pilotctl appstore view <app-id>. Payload: the app ID you viewed.app_installed — fired after a successful pilotctl appstore install <app-id>. Payload: app ID, version installed, and install source (catalogue or local).Each event is signed with your daemon's Ed25519 identity key before transmission. The telemetry server verifies the signature and rejects unsigned or tampered events.
-Events emitted:
+catalogue_viewed — fired once when you run pilotctl appstore catalogueappstore_view — fired when you run pilotctl appstore view <app-id>, carries the app IDapp_installed — fired after a successful install, carries app ID, version, and source (catalogue or local)Signature: Each event is signed with your daemon's Ed25519 identity key. The server verifies the signature before accepting the event, preventing spoofing.
+What we receive: The app ID, the action type, and a signature from your Ed25519 key. Your Ed25519 public key is a pseudonymous identifier — it has no name or email unless you registered with one via -email. Your IP address is visible to the telemetry server during the TLS connection, as with any HTTPS request.
What we do not receive: Message contents, agent conversation data, peer history, or any data about what your agent is actually doing.
+Who should turn this off: Users operating in high-sensitivity environments with strict no-telemetry policies, users who don't want any third party to know which apps they've looked at, or users running automated pipelines where even low-volume outbound telemetry is undesirable.
+ +# These commands trigger telemetry events when consent is on
+pilotctl appstore catalogue # → catalogue_viewed event
+pilotctl appstore view io.pilot.cosift # → appstore_view event (carries app ID)
+pilotctl appstore install io.pilot.cosift # → app_installed event (carries app ID + version)
- To disable:
- {"consent": {"telemetry": false}}
- Set in ~/.pilot/config.json. The telemetry client becomes a hard no-op — no dial, no buffer, no goroutine. Takes effect immediately for CLI commands; restart the daemon for daemon-side events.
+# Opt out — no dial, no buffer, no goroutine spawned
+# Set in ~/.pilot/config.json:
+# {"consent": {"telemetry": false}}
+
+ Takes effect immediately for CLI commands. Restart the daemon for daemon-side events.
+ +Risk level: Medium
+ +Network administrators holding a valid admin token can send a single datagram to every agent in a network simultaneously — without iterating over each peer. When your daemon receives a broadcast, it checks the admin token, then forwards the datagram payload to your agent on the specified port.
+ +What you're accepting: Any party holding the network's admin token can deliver arbitrary data to your agent. The admin token is set by whoever configured the network — usually the person who started the daemon with -admin-token. Your agent code is responsible for handling the incoming payload correctly.
The realistic threat: If the admin token is compromised — leaked in a config file, rotated without your knowledge, or held by a bad actor — an attacker could send broadcast payloads to your agent. Broadcasts are authenticated (no valid token, no delivery) but the authentication is only as strong as your token handling practices.
+Who should turn this off: Users joining networks whose administrators they do not know or trust. Users running solo (no fleet, no admin) who will never send or receive broadcasts — turning it off eliminates an attack surface that offers you no benefit. Users in high-security environments where any unsolicited inbound data channel is unacceptable.
+ +# Send a broadcast (requires admin token — you are the operator)
+pilotctl broadcast <net-id> <dst-port> <data> --admin-token <token>
- What it does: Network administrators holding an admin token can send a datagram to every agent in a network simultaneously. This is used to deliver time-sensitive updates, push configuration changes, or coordinate actions across a fleet. When your daemon receives a broadcast, it processes and forwards it to your agent.
+# Receiving is handled automatically by the daemon
+# Opt out — incoming datagrams are silently dropped before reaching your agent
+# Set in ~/.pilot/config.json:
+# {"consent": {"broadcasts": false}}
- Authentication: Broadcasts require a valid admin token set on the sending daemon. Without a matching token, the send is rejected. Your daemon's consent flag is an additional, independent gate.
+Restart the daemon for the change to take effect. The sender receives no error when you opt out — by design, to avoid a noisy failure cascade across large fleets.
-To disable:
-{"consent": {"broadcasts": false}}
- When off, incoming broadcast datagrams are silently dropped before reaching your agent. The sender receives no error (by design — mass fan-outs would otherwise generate noisy failures). Restart the daemon for the change to take effect.
+Risk level: Low
-What it does: Two optional review-prompt behaviours are consent-gated:
+Two review-prompt behaviours are consent-gated, plus an explicit review command:
pilotctl send-message calls, a short prompt appears on stderr suggesting you leave a review. Pressing Enter or just running your next command continues normally. The prompt never appears in stdout and never pollutes --json output.pilotctl appstore call invocations, the output is replaced with a review prompt for the called app. Disabling reviews suppresses this entirely.pilotctl send-message calls, a short prompt appears on stderr suggesting you leave a review of Pilot itself. Pressing Enter or just running your next command skips it. The prompt never appears in stdout and never corrupts --json output.pilotctl appstore call invocations, the output is replaced by a review prompt for the called app. Your call result is shown first; the prompt appears after.pilotctl review <subject> lets you submit a review at any time, independently of the above prompts.What is sent when you leave a review: The subject (the pilot command or app ID), an optional star rating (1–5), and optional free-text. No session context, no command history.
+What we receive when you submit a review: The subject (an app ID or the string pilot), an optional star rating (1–5), and optional free-text you typed. No session context, no command history, no automatically-captured data — everything in a review is what you explicitly provided.
The main operational risk: The 5% intercept replaces pilotctl appstore call stdout with a review prompt. If you run appstore call in a shell script or pipeline, this can corrupt your output. Disable reviews if you run pilotctl in automation.
Who should turn this off: Users running pilotctl in scripts or CI pipelines where stdout must be clean. Users who don't want any unsolicited prompts during normal operation.
# Submit a review explicitly
+pilotctl review pilot # review Pilot itself (no rating)
+pilotctl review pilot --rating 5 # with a star rating
+pilotctl review io.pilot.cosift --rating 4 --text "Fast search, clean API"
- pilotctl review <subject> [--rating 1-5] [--text "..."] — the explicit review command — also respects this consent flag; when off it accepts input locally but sends nothing to the telemetry endpoint.
+# View the review prompt explicitly (for testing)
+# The --json flag suppresses all prompts in any command
+pilotctl --json appstore call io.pilot.cosift cosift.help '{}'
- To disable:
- {"consent": {"reviews": false}}
- Takes effect immediately for CLI commands.
+# Opt out — no prompts, no intercepts, no review data sent
+# Set in ~/.pilot/config.json:
+# {"consent": {"reviews": false}}
+
+ Takes effect immediately for all CLI commands.
+ +Risk level: Medium
-What it does: The daemon automatically writes a SKILL.md file and heartbeat directives into the well-known configuration directories of supported agent toolchains (Claude Code, Cursor, OpenHands, OpenClaw, Hermes). This is what makes those agents discover Pilot Protocol tools automatically — it is the "set Pilot as default" mechanism.
The daemon writes a SKILL.md file and a short heartbeat directive into the well-known configuration directories of supported agent toolchains — Claude Code (~/.claude/CLAUDE.md), Cursor (.cursor/rules), OpenHands, OpenClaw, and Hermes. This is what makes those agents discover Pilot tools automatically and reach for Pilot first instead of falling back to slower, less-structured tools like web_search or curl.
The injector writes only inside a clearly-delimited marker block (<!-- pilot-inject:start --> / <!-- pilot-inject:end -->). It never touches any content outside that block. On every tick it re-fetches the latest skill content and rewrites its own block.
Everything injected is open source and fetched at runtime from the public repository. The injector only writes its own marker block and never touches anything else in the configuration file. It rewrites that block on every tick to keep it current.
+What you're accepting: The injector fetches content at runtime from the public TeoSlayer/pilot-skills repository and writes it to your agent's config directory. In auto mode, this happens every 15 minutes. The injected content influences what tools your agent reaches for and what instructions it follows.
The realistic threat: If the pilot-skills repository is compromised, injected content could modify your agent's behavior — potentially instructing it to use Pilot tools in unintended ways, or expanding the set of actions it takes. This is a supply-chain risk: you're trusting the integrity of a third-party repository. The injector does not execute anything, but agent toolchains do execute the injected instructions.
Mitigation: In manual mode (the default on fresh install), content is only applied when you explicitly trigger it with pilotctl update — giving you full control over when updates land. You can inspect what would be injected by reading the skills repo before updating.
Who should turn this off: Users with strict control requirements over their agent configs who prefer to manage skill content manually. Users operating in environments where any external write to agent config directories is a compliance violation. Users who have already managed their CLAUDE.md and don't want it modified.
-Three modes:
+| Mode | Behaviour | |||
|---|---|---|---|---|
| Mode | Behavior | Best for | ||
manual (default on fresh install) |
- Skills are installed once when the daemon first starts, and reinstalled when you run pilotctl update. No background ticker. |
+ manual (default on fresh install) |
+ Skills are installed once when the daemon first starts. Updated only when you explicitly run pilotctl update or pilotctl skills check. No background ticker. |
+ Users who want Pilot tools available but want to review updates before they land. Maximum control, minimal surprise. |
auto |
- The daemon runs a reconcile pass every 15 minutes, keeping skills continuously up to date with whatever is in the current skill repository. | +A reconcile pass runs every 15 minutes. Your skills are always current with whatever is in the skill repository. | +Users who trust the skill repository and want always-current skills without manual intervention. | |
disabled |
- No skills are installed or updated. Equivalent to pilotctl skills disable all. |
+ No injection. No updates. Existing injected files are removed immediately on mode switch. | +Users who manage their agent config themselves, or who are not using any supported toolchain. |
To change the mode:
-# Check current mode
+ Commands
+ # Check current mode, see which files are managed and their paths
pilotctl skills status
-# Switch to auto (continuous background updates)
+# Switch to auto — skills reconcile every 15 minutes in the background
pilotctl skills set-mode auto
-# Switch to manual (install once, refresh on update)
+# Switch to manual — skills installed once, updated only on your command
pilotctl skills set-mode manual
-# Disable entirely (removes injected files)
+# Disable entirely — removes all injected content, stops all ticks
pilotctl skills set-mode disabled
-# or equivalently:
+
+# Enable (shorthand — sets mode to auto)
+pilotctl skills enable all
+
+# Disable (shorthand — same as set-mode disabled)
pilotctl skills disable all
-# Re-enable (sets mode to auto)
-pilotctl skills enable all
+# Force an immediate skill refresh regardless of current mode
+# Works in auto and manual. In disabled mode, outputs a message but does nothing.
+pilotctl update
+pilotctl skills check # alias for the same operation
- The mode is persisted in ~/.pilot/config.json under skill_inject.mode. The daemon reads it at each tick decision; no restart needed when changing from auto ↔ manual. Switching to disabled removes all injected files immediately.
Mode changes take effect immediately — no daemon restart required. The mode is stored in ~/.pilot/config.json under skill_inject.mode.
Everything injected is open source: pilot-protocol/skillinject (the injector code), TeoSlayer/pilot-skills (the content that gets injected).
-What it does: The -sandbox flag restricts the daemon's file system access to a single confinement directory. Any explicitly-passed path (config, identity, socket) that resolves outside the sandbox directory is rejected at startup with a fatal error, before the daemon reads or writes anything.
Not a privacy feature — a security hardening tool
-# Run the daemon confined to /opt/pilot-data
-pilotd -sandbox -sandbox-dir /opt/pilot-data
+ What it does
+ The -sandbox flag on the pilotd daemon restricts all filesystem access to a single confinement directory. Any path flag (-config, -identity, -socket) that resolves to a location outside the sandbox directory causes a fatal error at startup — before the daemon reads or writes anything. Unset path flags are automatically redirected to their counterpart inside the sandbox directory.
-# Default sandbox-dir is ~/.pilot when not specified
+ Who benefits and why
+ Sandbox mode does not change what data is collected or sent. It limits the blast radius if the daemon binary is compromised. A process confined to ~/.pilot cannot write to your agent configs, your SSH keys, or your project files — even if an attacker achieves code execution inside the daemon. It's defense-in-depth: independent of network-level security, relevant when you deploy the daemon in shared or less-trusted environments.
+
+ Commands
+ # Confine daemon to ~/.pilot (default sandbox-dir)
pilotd -sandbox
-# Explicit paths inside the sandbox are fine
-pilotd -sandbox -sandbox-dir /opt/pilot-data \
- -identity /opt/pilot-data/identity.json \
- -socket /opt/pilot-data/pilot.sock
+# Confine to a custom directory — useful for multi-tenant or containerized deployments
+pilotd -sandbox -sandbox-dir /opt/pilot-data
+
+# Pass explicit paths that must resolve inside the sandbox (violations are fatal)
+pilotd -sandbox -sandbox-dir /opt/pilot-data \\
+ -identity /opt/pilot-data/identity.json \\
+ -socket /opt/pilot-data/pilot.sock
+
+# Unset path flags are redirected automatically:
+# -config → <sandbox-dir>/config.json
+# -identity → <sandbox-dir>/identity.json
+# -socket → <sandbox-dir>/pilot.sock
- When -sandbox is active and a path flag was not explicitly passed, the daemon automatically redirects the default to inside the sandbox directory. For example, -identity defaults to <sandbox-dir>/identity.json instead of the global default.
Network paths (registry, beacon, telemetry endpoint) are unaffected by sandbox mode.
-Network paths (registry, beacon, telemetry endpoint) are unaffected by sandbox mode — only filesystem paths are checked.
+To turn off all opt-out features in one edit:
+To opt out of all four features in a single config edit:
{
- "registry": "...",
- "beacon": "...",
"consent": {
"telemetry": false,
"broadcasts": false,
@@ -156,16 +262,25 @@ pilotd -sandbox -sandbox-dir /opt/pilot-data \
"skill_inject": {"mode": "disabled"}
}
- Then restart the daemon. Core messaging, networking, and peer discovery are unaffected.
+Set in ~/.pilot/config.json and restart the daemon. Peer routing, tunnel encryption, and peer-to-peer messaging are unaffected.