privateer-agent 0.15.0 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  <h1 align="center">⚓ Privateer</h1>
6
6
 
7
7
  <p align="center">
8
- <strong>A privacy-first, safe-by-default distribution of the <a href="https://pi.dev">Pi</a> coding agent — bring your own model, keep your own privacy.</strong>
8
+ <strong>A privacy-first, safe-by-default distribution of the <a href="https://pi.dev">Pi</a> coding agent. Bring your own model, keep your own privacy.</strong>
9
9
  </p>
10
10
 
11
11
  <p align="center">
@@ -19,212 +19,133 @@
19
19
  <img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License" />
20
20
  <img src="https://img.shields.io/badge/permissions-safe%20by%20default-2ea44f" alt="Safe by default" />
21
21
  <img src="https://img.shields.io/badge/inference-TEE%20attested%20·%20on--device%20PII%20gate-5b8def" alt="Private inference" />
22
- <img src="https://img.shields.io/badge/providers-OpenRouter%20·%20Anthropic%20·%20OpenAI%20·%20Google%20·%20xAI%20·%20Groq%20·%20Mistral%20·%20Z.ai%20·%20DeepSeek%20·%20Qwen%20·%20Ollama%20·%20NEAR%20AI%20·%20Tinfoil%20·%20Venice-5b8def" alt="Providers" />
22
+ </p>
23
+
24
+ <p align="center">
25
+ <img src="brand/demo.gif" alt="Opening Privateer in a terminal and running a command" width="720" />
23
26
  </p>
24
27
 
25
28
  ```bash
26
- curl -fsSL https://privateer.pro/install.sh | sh # macOS / Linux — installs the `privateer` command
29
+ curl -fsSL https://privateer.pro/install.sh | sh # macOS / Linux: installs the `privateer` command
27
30
  irm https://privateer.pro/install.ps1 | iex # Windows (PowerShell)
28
31
  npx privateer-agent # or run it instantly, nothing installed
29
32
  ```
30
33
 
31
- Point it at a frontier model today and a local Ollama model tomorrow — **OpenRouter**,
32
- **Anthropic**, **OpenAI**, **Google**, **xAI**, **Groq**, **Mistral**, **Z.ai** (GLM),
33
- **DeepSeek**, **Qwen**, local **Ollama**, **NEAR AI** or **Tinfoil** (verifiable TEE
34
- inference), **Venice** / **Fireworks** (no-retention inference), and any **custom
35
- OpenAI-compatible endpoint** (LM Studio, vLLM, llama.cpp…) are interchangeable at
36
- `/model` time, including mid-session. No model lock-in, no separate code paths. MCP
37
- servers, sub-agents, scheduled routines, multi-step workflows, chat-app bridges, and
38
- one-tap approval from your phone are included — and every one of the agent's actions runs
34
+ Use a frontier model today and a local one tomorrow. **OpenRouter**, **Anthropic**,
35
+ **OpenAI**, **Google**, **xAI**, **Groq**, **Mistral**, **Z.ai** (GLM), **DeepSeek**,
36
+ **Qwen**, local **Ollama**, **NEAR AI** and **Tinfoil** (verifiable TEE inference),
37
+ **Venice** and **Fireworks** (no-retention inference), and any **OpenAI-compatible
38
+ endpoint** (LM Studio, vLLM, llama.cpp) are interchangeable with `/model`, even
39
+ mid-session. MCP servers, sub-agents, scheduled routines, workflows, chat-app bridges and
40
+ one-tap approval from your phone are built in, and every action the agent takes passes
39
41
  through a **safe-by-default permission gate**.
40
42
 
41
- Privateer runs in three places, over one account and one config: the **terminal**,
42
- **Harbor** (a background service) for unattended work, and the **Privateer app** on
43
- [phone, web](https://privateer.pro), and [desktop](#the-privateer-app).
44
-
45
- ## Why Privateer?
46
-
47
- - **No lock-in.** One agent, every provider. `/model` swaps mid-session and your config,
48
- commands, and agents come along for the ride. No vendor's models are privileged.
49
- - **No API key required.** Bring your own key from any supported provider, run keyless
50
- against a local Ollama — or `/signin` to bill a Privateer account instead.
51
- - **Safe by default.** Every edit, shell command, and network call is classified and gated
52
- before it runs; destructive commands are blocked even in unattended runs. You stay in
53
- control, whether you're watching or not.
54
- - **Privacy you can verify, not just trust.** Confidential-enclave (TEE) inference is
55
- cryptographically **attested** — not a policy promise — and an **on-device PII gate**
56
- warns before structured personal data ever leaves your machine for an unverified model.
57
- - **A private subagent for your other agents.** Claude Code, Codex, or your own orchestrator
58
- can hand Privateer the files it shouldn't read itself: `privateer -p --private "…"` reads
59
- them on your machine, reasons over them in an attested enclave, and returns only the
60
- answer. See [Hand off sensitive work](#hand-off-sensitive-work-to-privateer).
61
- - **It's Pi underneath.** Privateer is a distribution of the [Pi](https://pi.dev) coding agent —
62
- every Pi extension, skill, and command works, and Privateer's own features are just extensions
63
- you can read, swap, or build on. Nothing to compile. See [Built on Pi](#built-on-pi).
43
+ Privateer runs in three places on one account and one config: the **terminal**,
44
+ **Harbor** (a background service for unattended work), and the **Privateer app** on
45
+ [phone, web](https://privateer.pro) and [desktop](#desktop-app).
64
46
 
65
- ## Built on Pi
47
+ ## What's new in 0.15.0
66
48
 
67
- Privateer is a **distribution of the [Pi](https://pi.dev) coding agent**
68
- (`@earendil-works/pi-coding-agent`): Pi is the runtime, the model routing, the interactive TUI,
69
- and the extension / skill / prompt discovery system — **everything that works in Pi works here.**
70
- What Privateer adds is a *moat* of Pi extensions layered on top:
49
+ - **Pi 1.3 underneath.** Privateer now runs on Pi 1.3.0.
50
+ - **MCP on Pi's built-in support.** Connectors load through Pi's own MCP client instead of
51
+ a separate adapter, and the model calls their tools through **codemode**: it writes a
52
+ short script, and every tool call inside it still goes through the permission gate on
53
+ its own. After upgrading, sign OAuth connectors back in with **`/mcp`**. See
54
+ [Connectors (MCP)](#connectors-mcp).
55
+ - **Sub-agents are back.** Hand work to bounded parallel agents that inherit the moat and
56
+ keep their MCP tools.
71
57
 
72
- | Extension | What it adds |
73
- |---|---|
74
- | `privateer-gate` | safe-by-default permission gate + destructive-command danger filter |
75
- | `privateer-context` | loads `PRIVATEER.md` project context (like `AGENTS.md`/`CLAUDE.md`) + the `/init` command |
76
- | `privateer-privacy` | `pi-privacy` — TEE attestation, ZDR routing, on-device PII gate — bound to the account tier resolver |
77
- | `privateer-account` | `/signin` billed inference against a Privateer account (device flow) |
78
- | `privateer-posture`, `privateer-tools` | live attestation shield + Privateer tool pack |
79
- | `privateer-web` | `web_search`/`web_fetch` — your account's search once signed in, or your own provider (`rpiv-web-tools`: self-hosted SearXNG, Brave, Tavily…) |
80
- | `rpiv-ask-user-question` | `ask_user_question` — a structured questionnaire the agent puts to you instead of guessing |
81
- | `privateer-codemode`, `pi-subagents` | codemode (how MCP tools are called — Pi's built-in MCP support) · bounded parallel sub-agents |
82
-
83
- They're ordinary Pi extensions — inspect them, replace them, or build your own alongside.
84
- **Extend by discovery:** drop an extension into `~/.privateer/agent/extensions/` (move the home
85
- with `PRIVATEER_HOME`), add a skill or prompt beside it, or list an npm/git package under
86
- `packages` in `~/.privateer/agent/settings.json` — Pi auto-loads them on next launch, right next
87
- to Privateer's own. Any extension from the Pi ecosystem loads the same way. (There's no CLI flag
88
- for this — discovery is the entry point.)
89
-
90
- **The floor you can't lower is the safety gate.** While it's loaded, its block on destructive
91
- shell commands, secret exfiltration, and plan-mode escapes sits *above* every relaxation —
92
- `bypass` mode, the approval allowlist, even a phone-approved remote turn can't fire them
93
- silently. The moat is swappable; the floor under it holds.
58
+ Earlier releases are on the [releases page](https://github.com/privateer-agent/privateer-agent/releases).
94
59
 
95
- ## Highlights
60
+ ## Why Privateer?
96
61
 
97
- - **Private, verifiable inference** via **NEAR AI** and **Tinfoil**: every model runs inside
98
- a Trusted Execution Environment, a live status shield reflects the attestation, and
99
- `/verify` fetches and checks the cryptographic report on demand — genuine proof the
100
- inference ran on real confidential hardware, not a terms-of-service page.
101
- - **On-device PII gate.** Before a prompt goes to an *unverified* channel, Privateer scans it
102
- locally for structured personal data (emails, phone numbers, SSNs, cards, IBANs, IPs…) and
103
- offers to redact or hold it — detection never leaves your machine, and an attested TEE
104
- channel skips the check because it provably can't read your data anyway.
105
- - **Honest privacy posture, graded.** A verified TEE and a "we promise not to retain"
106
- policy are **never rendered the same** — the badge tells you exactly how strong the
107
- guarantee is (cryptographically verified → observable → policy → none).
108
- - **Drive it from your phone.** Link the terminal with `/remote-access` (off by default) and
109
- the Privateer app can send prompts, stream output, and Allow/Deny every action — while
110
- execution stays on your machine. Sub-agent actions surface for approval the same way.
111
- - **Manage it from the app.** Extensions, skills, routines, workflows, MCP connectors, and
112
- chat-app channels are all configurable from your phone or the web app, against any linked
113
- terminal. See [The Privateer app](#the-privateer-app).
114
- - **A desktop app.** The same agent hosted inside a local Electron shell — no relay hop, works
115
- offline, multi-window with per-window MCP connectors. Shares your CLI login and config.
116
- - **Scheduled routines.** Harbor, a background service, runs approved tasks unattended — cron or
117
- one-off — and the agent can schedule its own follow-up work. Results deliver to a file,
118
- the next session, your phone, email, or a webhook.
119
- - **Declarative workflows.** Multi-step agent pipelines as YAML — typed steps, conditional
120
- routing between them, and `human_gate` steps that pause for your approval and resume.
121
- - **Chat-app channels.** Bridge the agent into Telegram, Slack, Discord, or WhatsApp with
122
- role-based approval — admins can approve actions, members are read-only.
123
- - **Make images and video.** Signed in, the agent can generate images, video clips, narration
124
- and music on your account — and stitch them together locally with ffmpeg. It plans the whole
125
- piece: render the stills, animate them, carry the last frame of one clip into the next so the
126
- shots stay continuous, cut them together, then score and narrate the result. Generated media
127
- is handed straight back as files on your machine; none of it is stored in our cloud. See
128
- [docs/media-generation.md](docs/media-generation.md).
129
- - **Talk to it.** `/speak on` reads answers aloud as they're written; **alt+t** is push-to-talk
130
- and the mic closes when you stop talking. Your OS voice by default — nothing leaves the
131
- machine — or your account's confidential-compute TTS/STT once you sign in. `/talk loop on`
132
- makes it hands-free. See [Talk to it](#talk-to-it--voice-both-directions).
133
- - **Named terminals.** The agent can open windows you watch — a dev server, a REPL, a second
134
- agent — give each a name, and bring any of them to the front; `/term api` switches you there
135
- yourself. macOS Terminal, iTerm2, and tmux anywhere. See [Named terminals](#named-terminals).
136
- - **MCP servers, sub-agents & skills.** Connect Model Context Protocol servers (local stdio
137
- or remote HTTP with OAuth) with [`/connect`](#connectors--mcp), delegate work to bounded
138
- parallel sub-agents, and drop in skills — all gated like everything else.
139
- - **Zero-Data-Retention surfacing** for OpenRouter — see the selected model's retention
140
- posture before you send, and pin routing to zero-retention endpoints.
141
- - **Plan mode**, checkpoint/rewind, session branching, a modal prompt with `/` command and
142
- `@` file autocomplete, `!` shell passthrough, background shells, and image attachment for
143
- vision-capable models.
62
+ - **No lock-in.** One agent, every provider. `/model` swaps mid-session, and your config,
63
+ commands and agents come along. No vendor's models get special treatment.
64
+ - **No API key required.** Bring a key from any supported provider, run keyless against a
65
+ local Ollama, or `/login` to bill a Privateer account instead.
66
+ - **Safe by default.** Every edit, shell command and network call is classified and gated
67
+ before it runs. Destructive commands stay blocked even in unattended runs.
68
+ - **Privacy you can verify.** Confidential-enclave (TEE) inference is cryptographically
69
+ **attested**, not a policy promise, and an **on-device PII gate** warns before personal
70
+ data leaves your machine for an unverified model.
71
+ - **A private sub-agent for your other agents.** Claude Code, Codex or your own
72
+ orchestrator can hand Privateer the files it shouldn't read itself. `privateer -p
73
+ --private "…"` reads them on your machine, reasons over them in an attested enclave, and
74
+ returns only the answer. See [Hand off sensitive work](#hand-off-sensitive-work).
75
+ - **It's Pi underneath.** Every Pi extension, skill and command works, and Privateer's own
76
+ features are plain extensions you can read, swap or build on. See [Built on Pi](#built-on-pi).
144
77
 
145
78
  ## Quickstart
146
79
 
147
80
  ```bash
148
81
  curl -fsSL https://privateer.pro/install.sh | sh # or: npm install -g privateer-agent
149
- export OPENROUTER_API_KEY=sk-or-... # one provider is enough — or skip and /signin
150
- privateer # launches the interactive agent
82
+ export OPENROUTER_API_KEY=sk-or-... # one provider is enough, or skip it and /login
83
+ privateer # start the interactive agent
151
84
  ```
152
85
 
153
- First run walks you through picking a provider and default model. From there, just type.
154
- No install at all: `npx privateer-agent`.
86
+ The first run walks you through picking a provider and a default model. Then just type.
155
87
 
156
88
  ## Install
157
89
 
158
90
  ```bash
159
- # the one-liner installer — downloads a self-contained bundle, no Node needed:
91
+ # The installer downloads a self-contained bundle. No Node needed.
160
92
  curl -fsSL https://privateer.pro/install.sh | sh # macOS / Linux
161
- irm https://privateer.pro/install.ps1 | iex # Windows (PowerShell)
93
+ irm https://privateer.pro/install.ps1 | iex # Windows (PowerShell)
162
94
 
163
- # or via npm, if you'd rather manage it yourself (needs Node ≥ 22.19):
95
+ # Or manage it with npm yourself (needs Node 22.19 or newer):
164
96
  npm install -g privateer-agent
165
97
  npx privateer-agent # run without installing
166
98
  ```
167
99
 
168
- **Requirements:** macOS (arm64/x64), Linux (x64), or Windows (x64). The installers ship a
169
- **pinned Node runtime inside the bundle**, so you don't need Node or npm on your machine at
170
- all — Node ≥ 22.19.0 is only required for the `npm` / `npx` path.
100
+ **Requirements:** macOS (arm64 or x64), Linux (x64) or Windows (x64). The installers ship
101
+ a pinned Node runtime inside the bundle, so Node is only needed for the npm and npx route.
171
102
 
172
- Update in place with **`privateer update`** (bundle-aware: it re-runs the right installer
173
- for how you installed) or check your version with `privateer --version`.
103
+ Update with **`privateer update`**, which re-runs the right installer for how you
104
+ installed. Check your version with `privateer --version`.
174
105
 
175
- > **Windows:** the agent's command tool needs a bash, which Windows doesn't ship. Install
176
- > Git for Windows (or WSL) and Privateer will find it; the launcher checks at startup and
177
- > tells you how to fix it if not. Override the choice with `shellPath` in
178
- > `~/.privateer/agent/settings.json`. Linux arm64 and Windows arm64 bundles aren't built
179
- > yet — arm64 Windows runs the x64 bundle under emulation.
106
+ > **Windows:** the agent's command tool needs bash, which Windows doesn't ship. Install Git
107
+ > for Windows (or WSL) and Privateer finds it; the launcher checks at startup and tells you
108
+ > how to fix it if not. Override the choice with `shellPath` in
109
+ > `~/.privateer/agent/settings.json`. There are no Linux arm64 or Windows arm64 bundles yet;
110
+ > Windows on arm64 runs the x64 bundle under emulation.
180
111
 
181
- Background-task storage is created only when a task starts, not when you open Privateer.
182
- Tasks normally write logs to `.pi/tasks` in your working directory. If that directory
183
- denies writes (for example, Git Bash opened in `C:\Program Files\Git`), Privateer
184
- uses `~/.privateer/agent/tasks/<project-id>/<run-id>` instead, respecting
185
- `PRIVATEER_HOME`. The task's output path shows the actual location. This does **not**
186
- change the working directory for commands or grant permission to edit protected files.
112
+ Background-task logs go to `.pi/tasks` in your working directory. If that directory isn't
113
+ writable (Git Bash opened in `C:\Program Files\Git`, for example), they go to
114
+ `~/.privateer/agent/tasks/<project-id>/<run-id>` instead. That fallback changes only where
115
+ logs are written, not the working directory or what the agent may edit.
187
116
 
188
- ### Verifying what you're about to run
117
+ ### Verify what you're about to run
189
118
 
190
- Privateer is a coding agent — it runs shell commands and edits files, so "should I trust
191
- this package?" is the right question to ask before `npx`. Two things are checkable
192
- without taking anyone's word for it:
119
+ Privateer runs shell commands and edits files, so it's fair to ask whether you can trust
120
+ the package. Before installing:
193
121
 
194
122
  ```bash
195
- npm view privateer-agent dist.attestations # published from CI with npm provenance:
196
- # a signed link from this tarball to the
197
- # exact commit and build that produced it
198
- npm audit signatures # verify registry signatures + provenance
123
+ npm view privateer-agent dist.attestations # npm provenance: a signed link from this
124
+ # tarball to the commit and CI build behind it
125
+ npm audit signatures # verify registry signatures and provenance
199
126
  ```
200
127
 
201
- And **after** installing — the check nobody else offers, because every signal above is
202
- an install-time one:
128
+ After installing:
203
129
 
204
130
  ```bash
205
- privateer verify # is the install on THIS disk still the one we published?
131
+ privateer verify # is the install on this disk still the one we published?
206
132
  ```
207
133
 
208
- It reports the install shape, whether this exact version is published and carries a
209
- provenance attestation, whether any dependency has drifted from its pinned version,
210
- and which launch-time patches are applied. Inconclusive checks say so rather than
211
- counting as a pass; `--offline` skips the ones that need the registry.
134
+ `privateer verify` reports the install shape, whether this exact version is published with
135
+ a provenance attestation, whether any dependency drifted from its pinned version, and which
136
+ launch-time patches are applied. Inconclusive checks are reported as inconclusive, not as a
137
+ pass; `--offline` skips the ones that need the registry.
212
138
 
213
- The package also declares **no install scripts** — no `postinstall`, nothing — so
214
- nothing we publish executes at install time, and `--ignore-scripts` gives an identical
215
- result. That is a claim about *our* tarball, not your whole install: a handful of
216
- packages in the ~500-package dependency tree do declare install hooks, and none of them
217
- are needed here, so the install we recommend and test is
139
+ The package declares **no install scripts**, so nothing we publish runs at install time. A
140
+ few packages deep in the dependency tree do declare install hooks, and none are needed, so
141
+ the install we recommend and test is:
218
142
 
219
143
  ```bash
220
144
  npm install -g privateer-agent --ignore-scripts
221
145
  ```
222
146
 
223
- Or skip the dependency graph entirely with a bundle (the `curl | sh` one-liner above),
224
- which verifies a published SHA-256 and, from the next release on, a signed build
225
- attestation before it unpacks anything.
226
-
227
- See [SECURITY.md](SECURITY.md) for the threat model, the permission gate, and how to
147
+ The `curl | sh` bundle skips the dependency tree entirely and checks a published SHA-256
148
+ before it unpacks anything. See [SECURITY.md](SECURITY.md) for the threat model and how to
228
149
  report a vulnerability.
229
150
 
230
151
  **From source:**
@@ -233,16 +154,16 @@ report a vulnerability.
233
154
  git clone https://github.com/privateer-agent/privateer-agent.git
234
155
  cd privateer-agent
235
156
  npm install
236
- npm start # launches the interactive agent
157
+ npm start
237
158
  ```
238
159
 
239
160
  ## Configure a provider
240
161
 
241
- Privateer reads credentials from environment variables (or sign in to an account and skip
242
- keys entirely). One provider is enough to start:
162
+ Privateer reads keys from environment variables, or you can `/login` to an account and skip
163
+ keys entirely. One provider is enough:
243
164
 
244
165
  ```bash
245
- export OPENROUTER_API_KEY=sk-or-... # gateway to ~everything
166
+ export OPENROUTER_API_KEY=sk-or-... # gateway to almost everything
246
167
  export ANTHROPIC_API_KEY=sk-ant-...
247
168
  export OPENAI_API_KEY=sk-...
248
169
  export GEMINI_API_KEY=AIza... # Google
@@ -253,555 +174,517 @@ export OLLAMA_BASE_URL=http://localhost:11434/v1 # local, keyless
253
174
  export NEAR_AI_API_KEY=... # verifiable TEE inference (cloud.near.ai)
254
175
  export TINFOIL_API_KEY=... # verifiable TEE inference (tinfoil.sh)
255
176
  export VENICE_API_KEY=vapi_... # no-retention inference
256
- export PRIVATEER_API_KEY=sk-priv-... # Privateer developer API (privateer.pro); or /signin instead
177
+ export PRIVATEER_API_KEY=sk-priv-... # Privateer developer API (privateer.pro)
257
178
  ```
258
179
 
259
- Pick a model with **`/model`** (browse each configured provider's live catalog) or pass one
260
- directly as `provider/model` — e.g. `openrouter/anthropic/claude-opus-5`,
261
- `ollama/qwen3-coder`, `nearai/zai-org/GLM-5.1-FP8`. Any OpenAI-compatible server (LM Studio,
262
- vLLM, llama.cpp) works as a custom provider — just give it a base URL.
180
+ Pick a model with **`/model`**, which browses each provider's live catalog, or pass one as
181
+ `provider/model`: `openrouter/anthropic/claude-opus-5`, `ollama/qwen3-coder`,
182
+ `nearai/zai-org/GLM-5.1-FP8`. Any OpenAI-compatible server works as a custom provider with
183
+ just a base URL. Move the config home with `PRIVATEER_HOME`.
263
184
 
264
- Override the config location with `PRIVATEER_HOME`.
185
+ ## Built on Pi
265
186
 
266
- ## Context files — `PRIVATEER.md`
187
+ Privateer is a distribution of the [Pi](https://pi.dev) coding agent
188
+ (`@earendil-works/pi-coding-agent`). Pi provides the runtime, model routing, the TUI, MCP
189
+ and the extension, skill and prompt discovery, so **everything that works in Pi works
190
+ here**. Privateer adds a *moat* of extensions on top:
267
191
 
268
- Give the agent standing knowledge about your project — conventions, common commands,
269
- domain notes — by dropping a **`PRIVATEER.md`** in the directory. Privateer loads it
270
- automatically at the start of every turn and prepends it to the model's system prompt,
271
- exactly the way Pi loads `AGENTS.md` / `CLAUDE.md` (all three are recognized, and all
272
- matching files are concatenated).
192
+ | Extension | What it adds |
193
+ |---|---|
194
+ | `privateer-gate` | the permission gate and the destructive-command filter |
195
+ | `privateer-context` | `PRIVATEER.md` project context and the `/init` command |
196
+ | `privateer-privacy` | `pi-privacy`: TEE attestation, ZDR routing and the on-device PII gate |
197
+ | `privateer-account` | billed inference on a Privateer account (`/login`, device flow) |
198
+ | `privateer-posture`, `privateer-tools` | the live attestation shield and Privateer's tool pack |
199
+ | `privateer-web` | `web_search` and `web_fetch`, on your account or your own provider |
200
+ | `rpiv-ask-user-question` | a structured questionnaire the agent puts to you instead of guessing |
201
+ | `privateer-codemode`, `pi-subagents` | how the model calls MCP tools, and bounded parallel sub-agents |
202
+
203
+ To add your own, drop an extension into `~/.privateer/agent/extensions/`, put a skill or
204
+ prompt beside it, or list an npm or git package under `packages` in
205
+ `~/.privateer/agent/settings.json`. Pi loads it on the next launch, next to Privateer's own.
206
+
207
+ **The safety floor can't be lowered from inside.** While the gate is loaded, its block on
208
+ destructive shell commands, secret exfiltration and plan-mode escapes sits above every
209
+ relaxation: `bypass` mode, the approval allowlist, even a phone-approved remote turn. The
210
+ moat is swappable; the floor under it holds.
273
211
 
274
- Run **`/init`** to scaffold a starter `PRIVATEER.md` in the current directory, then edit
275
- it. The startup banner shows a **⚓** line with the loaded file's path (and a `+N` count
276
- when ancestor files also apply), or a `/init` hint when none is found.
212
+ ## Highlights
277
213
 
278
- Discovery mirrors Pi's context-file lookup: the global agent dir
279
- (`~/.privateer/agent/PRIVATEER.md`) first, then every directory from the filesystem root
280
- down to the current one — so a repo-root `PRIVATEER.md` applies to every subdirectory, and
281
- a deeper file can refine it. `AGENTS.md` and `CLAUDE.md` continue to work unchanged; use
282
- `--no-context-files` (`-nc`) to disable context-file loading entirely.
214
+ - **Verifiable private inference** on **NEAR AI** and **Tinfoil**. Models run in a Trusted
215
+ Execution Environment, a status shield shows the live attestation, and `/verify` checks
216
+ the cryptographic report on demand.
217
+ - **On-device PII gate.** Prompts headed for an unverified model are scanned locally for
218
+ emails, phone numbers, SSNs, cards, IBANs and IPs, with an offer to redact or hold.
219
+ - **Honest privacy grading.** A verified enclave and a "we promise not to retain" policy
220
+ never look the same: cryptographically verified, observable, policy, or none.
221
+ - **Drive it from your phone.** `/remote-access` (off by default) lets the app send prompts,
222
+ stream output, and Allow or Deny every action while execution stays on your machine.
223
+ - **Manage it from the app.** Extensions, skills, routines, workflows, MCP connectors and
224
+ chat channels are configurable from your phone or the web, for any linked terminal.
225
+ - **A desktop app** that hosts the agent locally: no relay hop, works offline, shares your
226
+ CLI login and config.
227
+ - **Scheduled routines.** Harbor runs approved tasks unattended, on cron or once, and
228
+ delivers results to a file, your next session, your phone, email or a webhook.
229
+ - **Declarative workflows.** Multi-step YAML pipelines with typed steps, conditional routes
230
+ and `human_gate` steps that pause for your approval.
231
+ - **Chat-app channels.** Bridge the agent into Telegram, Slack, Discord or WhatsApp, with
232
+ admins who can approve and members who can't.
233
+ - **Images and video.** Signed in, the agent can generate images, clips, narration and
234
+ music on your account and cut them together locally with ffmpeg. Files come straight back
235
+ to your machine and aren't stored in our cloud. See [docs/media-generation.md](docs/media-generation.md).
236
+ - **Voice, both directions.** `/speak on` reads answers aloud as they're written; **alt+t**
237
+ is push-to-talk. See [Talk to it](#talk-to-it).
238
+ - **Named terminals.** The agent opens windows you watch (a dev server, a REPL, a second
239
+ agent), names them, and `/term api` takes you there. See [Named terminals](#named-terminals).
240
+ - **MCP, sub-agents and skills**, all gated like everything else. See [Connectors (MCP)](#connectors-mcp).
241
+ - **Zero-data-retention routing** for OpenRouter: see a model's retention posture before you
242
+ send, and pin routing to zero-retention endpoints.
243
+ - **The everyday tools:** plan mode, checkpoints and rewind, session branching, `/` command
244
+ and `@` file autocomplete, `!` shell passthrough, background shells, and image input for
245
+ vision models.
246
+
247
+ ## Context files: `PRIVATEER.md`
248
+
249
+ Give the agent standing knowledge about a project (conventions, common commands, domain
250
+ notes) with a **`PRIVATEER.md`** in the directory. It's loaded at the start of every turn and
251
+ added to the system prompt, the same way Pi loads `AGENTS.md` and `CLAUDE.md`. All three
252
+ names are recognized and every matching file is included.
253
+
254
+ **`/init`** scaffolds a starter file. The startup banner shows a **⚓** line with the loaded
255
+ file, the extra files that also apply, and roughly what the context costs per turn.
256
+
257
+ Discovery starts at `~/.privateer/agent/PRIVATEER.md`, then walks every directory from the
258
+ filesystem root down to the current one, so a repo-root file covers every subdirectory and a
259
+ deeper file can refine it. `--no-context-files` (`-nc`) turns it off.
260
+
261
+ ## Private and verifiable inference
262
+
263
+ **NEAR AI Cloud** and **Tinfoil** run every model inside a **Trusted Execution
264
+ Environment**: a confidential VM where TLS ends *inside* the enclave, so prompts, weights
265
+ and outputs are hidden from the infrastructure provider, the model provider and the host.
266
+ Each request can produce a **cryptographic attestation** that it ran on genuine TEE hardware.
267
+
268
+ - The **status shield** shows the selected model's posture: 🟢 verified, 🟡 returned but
269
+ unconfirmed, 🔴 no attestation.
270
+ - **`/verify`** fetches and checks the attestation on demand. For full quote-chain
271
+ validation, take the printed report to the
272
+ [NEAR AI Cloud Verifier](https://github.com/nearai/cloud-verifier) or the
273
+ [Tinfoil verifier](https://github.com/tinfoilsh/tinfoil-cli).
274
+ - **Postures are labeled honestly.** A verified enclave (`cryptographic`), a pinned
275
+ zero-retention route (`observable`) and a provider's retention promise (`policy`) are
276
+ shown differently, so a claim never reads like a proof.
283
277
 
284
- ## Private & verifiable inference
278
+ ## The PII gate
285
279
 
286
- **NEAR AI Cloud** and **Tinfoil** run every model inside a **Trusted Execution Environment** —
287
- a confidential VM where TLS terminates *inside* the enclave, so your prompt's inputs, weights,
288
- and outputs are invisible to the infrastructure provider, the model provider, and the host
289
- itself. It isn't "trust us": each request can produce a **cryptographic attestation** proving
290
- the inference ran on genuine TEE hardware.
280
+ Before a prompt goes to a channel that *isn't* verified private, Privateer scans it
281
+ **locally** for structured personal data: emails, phone numbers, SSNs, card numbers
282
+ (Luhn-checked), IBANs (mod-97), IP and MAC addresses. If it finds any, it offers to
283
+ **redact** or **send as-is**, and can remember your choice for the session. Detection is
284
+ deterministic and on-device, and it's skipped on an attested TEE or local model, which
285
+ can't read your prompt anyway. It's a best-effort safety net, not a guarantee.
291
286
 
292
- - A **status shield** colors the selected model's live posture — 🟢 verified, 🟡 returned but
293
- unconfirmed, 🔴 no attestation material.
294
- - **`/verify`** fetches the attestation on demand and prints the evidence. Privateer does a
295
- pragmatic terminal-suited check; take the printed report to the
296
- [NEAR AI Cloud Verifier](https://github.com/nearai/cloud-verifier) or the
297
- [Tinfoil verifier](https://github.com/tinfoilsh/tinfoil-cli) for full quote-chain validation.
298
- - **The posture is graded honestly.** A verified enclave (`cryptographic`), a pinned
299
- zero-retention route (`observable`), and a provider's retention *promise* (`policy`) are
300
- labeled distinctly — a claim never gets to read like a proof.
287
+ Anything email-*shaped* matches, so some hits aren't personal data. **`/privacy allow
288
+ <value>`** takes an address (`me@acme.com`), a domain (`@acme.com`), an IPv4 block
289
+ (`10.0.0.0/8`), or an exact or globbed value. Entries live in `privacy.piiAllow` in
290
+ `~/.privateer/config.json`, apply from the next turn, and persist. `/privacy` lists them
291
+ and `/privacy unallow <value>` removes one. Reserved shapes like `example.com`, loopback
292
+ and `noreply@…` are allowed by default. `PI_PRIVACY_*` env vars and a
293
+ `pi-privacy.config.json` also work; a project-local file can only make the gate stricter.
301
294
 
302
- ## The PII gate
295
+ Under **no quarter** there's nobody to ask, so the gate redacts, sends, and prints what it
296
+ masked.
297
+
298
+ ## Privateer account
299
+
300
+ Instead of bringing a key, run **`/login`**. Your browser opens an **Authorize this
301
+ terminal?** page on privateer.pro; check the code matches the one in your terminal and
302
+ click Authorize. Over SSH or on a headless machine, the terminal prints the link and code
303
+ to approve from the app instead (`PRIVATEER_NO_BROWSER=1` always does this). No password or
304
+ key ever touches the terminal. Inference is billed to your subscription and defaults to a
305
+ NEAR TEE model. `/logout` signs out; manage linked terminals from the app.
303
306
 
304
- Before any prompt is sent to a channel that *isn't* verified-private, Privateer scans it
305
- **locally** for structured personal data — emails, phone numbers, SSNs, credit-card numbers
306
- (Luhn-checked), IBANs (mod-97), IP and MAC addresses. If it finds any, it warns and offers to
307
- **redact** or **send as-is** (or remember your choice for the session). Detection is
308
- deterministic and on-device — no model ever sees the data in order to find it — and it's
309
- skipped entirely on an attested TEE or on-device channel, which provably can't read your
310
- prompt anyway. It's best-effort structured-PII detection, labeled as such — a safety net, not
311
- a guarantee.
312
-
313
- Pattern detection fires on anything email-*shaped*, so some of what it finds isn't personal
314
- data at all. **`/privacy allow <value>`** is where you say so — an address
315
- (`me@acme.com`), a domain (`@acme.com`), an IPv4 block (`10.0.0.0/8`), or any exact or
316
- globbed value. Entries live in `privacy.piiAllow` in `~/.privateer/config.json`, apply from
317
- the next turn (no relaunch), and persist across sessions; `/privacy` on its own lists them
318
- and `/privacy unallow <value>` puts one back under the gate. Reserved shapes —
319
- `example.com`, loopback, `noreply@…`, `@users.noreply.github.com` — are allowed out of the
320
- box. `PI_PRIVACY_*` env vars and a `pi-privacy.config.json` are honoured too (a
321
- project-local file can only ever make the gate *stricter*).
322
-
323
- Under **no quarter** the gate doesn't ask — there's nobody to ask — so it redacts and sends,
324
- and prints what it masked. That's the one case where a false positive changes what the model
325
- sees without you seeing it first, which is why the notice tells you `/privacy allow` exists.
326
-
327
- ## Privateer account (billed inference)
328
-
329
- Instead of bringing your own key, run **`/signin`** to sign into a Privateer account. Your
330
- browser opens straight onto an **Authorize this terminal?** page on privateer.pro — check the
331
- code on the page matches the one in your terminal and click Authorize; the terminal signs
332
- itself in moments later. (Over SSH or on a headless box the terminal prints the link and code
333
- to approve from the app instead — set `PRIVATEER_NO_BROWSER=1` to always do that.) Wallet and
334
- email accounts work identically and no password or key ever touches the terminal. Inference
335
- is then billed to your subscription and defaults to a **NEAR TEE** model. Sign out any time
336
- with `/signout`; manage linked terminals from the app.
337
-
338
- > **Only approve a sign-in code you generated yourself.** The code authorizes *this* terminal
339
- > to spend on your account. If someone sends you a code and asks you to approve it, don't —
340
- > that hands *them* a billed session on *your* account.
341
-
342
- ## Talk to it — voice, both directions
343
-
344
- `/speak on` and answers are read aloud **as they are written**, sentence by sentence, with
345
- code blocks, tables and URLs stripped. Press **alt+t** and talk; the mic closes when you
346
- stop talking and the transcript lands in the composer for you to read before Enter sends it.
307
+ > **Only approve a code you generated yourself.** The code lets *this* terminal spend on
308
+ > your account. Approving a code someone sent you gives *them* a billed session on yours.
309
+
310
+ ## Talk to it
311
+
312
+ `/speak on` reads answers aloud **as they're written**, sentence by sentence, skipping code
313
+ blocks, tables and URLs. Press **alt+t** and talk; the mic closes when you stop, and the
314
+ transcript lands in the composer for you to check before Enter sends it.
347
315
 
348
316
  ```
349
- /speak on read answers aloud alt+t push to talk (press again to send)
350
- /speak voice <name> pick a speaker /talk the same thing, typed
351
- /speak rate <n> 0.5–3× pace /talk loop on conversation mode, hands-free
352
- /speak stream off wait for the full answer instead of speaking as it arrives
353
- /speak provider list engines (→ marks the active one); /talk provider does the same
317
+ /speak on read answers aloud alt+t push to talk (press again to send)
318
+ /speak voice <name> pick a speaker /talk the same thing, typed
319
+ /speak rate <n> 0.5x to 3x pace /talk loop on hands-free conversation
320
+ /speak stream off wait for the full answer before speaking
321
+ /speak provider list engines; /talk provider does the same
354
322
  ```
355
323
 
356
324
  Out of the box it uses your **OS voice** (`say`, `espeak-ng`, System.Speech) and nothing
357
- leaves the machine. Signed in, both directions quietly upgrade to your account's
358
- **confidential-compute TTS and STT** — attested-enclave models, the same ones the app's voice
359
- features use, inherited entitlement and billing. That is an upgrade, not a stomp: a provider
360
- you picked deliberately stays picked, and `/speak provider local` pins the offline voice for
361
- good. Be clear-eyed about the difference — the local voice never speaks to the network, while
362
- the account voice sends the utterance text to an enclave we can't read into but that is still
363
- off your machine.
364
-
365
- One caveat while the account endpoints catch up: `/speak rate` and `/talk vocab` are honored
366
- by the local and OpenAI-compatible engines, not yet by the account's TTS/STT.
367
-
368
- Voice is **off by default and interactive-only** — harbor, ACP and channel sessions never
369
- speak. The mic opens only on something you did (`/talk`, the push-to-talk key, a
370
- conversation turn you switched on, or switching to a window while dictation or conversation
371
- mode is on); there is no wake word, capture is hard-capped, audio is
372
- held in memory and never written to disk, and a mis-heard transcript is still just a prompt —
373
- every tool call it leads to hits the same permission gate as anything you type. Recording
374
- needs a capture tool on PATH: `sox` anywhere, or `arecord`/`parecord`/`ffmpeg` on Linux,
375
- `ffmpeg` on macOS. Everything is stored in `~/.privateer/speak.json`; the engine itself is the
376
- standalone [`privateer-speak`](https://www.npmjs.com/package/privateer-speak) package, usable
377
- in any Pi agent.
325
+ leaves the machine. Signed in, both directions switch to your account's
326
+ **confidential-compute TTS and STT**, unless you picked a provider yourself;
327
+ `/speak provider local` pins the offline voice. The account voice sends text to an enclave
328
+ we can't read, but it does leave your machine. `/speak rate` and `/talk vocab` don't apply
329
+ to the account engines yet.
330
+
331
+ Voice is **off by default and interactive only**: Harbor, ACP and channel sessions never
332
+ speak. The mic opens only on something you did. There's no wake word, capture is capped,
333
+ audio stays in memory, and a misheard transcript is just a prompt that hits the same gate as
334
+ anything you type. Recording needs `sox`, or `arecord`/`parecord`/`ffmpeg` on Linux and
335
+ `ffmpeg` on macOS. Settings live in `~/.privateer/speak.json`. The engine is the standalone
336
+ [`privateer-speak`](https://www.npmjs.com/package/privateer-speak) package.
378
337
 
379
338
  ## Named terminals
380
339
 
381
- Ask for "a terminal running the dev server" and the agent opens a new window, names it, and
382
- puts it in front of you. Every Privateer window names itself too (after its folder, or the
383
- name the agent gave it), so you and the agent can hop between them by name:
340
+ Ask for "a terminal running the dev server" and the agent opens a window, names it, and puts
341
+ it in front of you. Every Privateer window names itself too, so you can hop between them:
384
342
 
385
343
  ```
386
- /term pick a terminal to switch to
387
- /term api switch to "api"
344
+ /term pick a terminal to switch to
345
+ /term api switch to "api"
388
346
  /term open api npm run dev open one yourself
389
- /term name backend rename this window
390
- /term close api close it, ending what runs there
391
- /term list every named terminal (← marks this one)
347
+ /term name backend rename this window
348
+ /term close api close it and end what runs there
349
+ /term list every named terminal
392
350
  ```
393
351
 
394
- The agent does the same through its `terminal` tool. Opening a window with a command goes
395
- through the permission gate exactly like running that command in bash; switching and listing
396
- don't ask. The agent can't read what a window prints: that's what bash and background tasks
397
- are for. These windows are for you.
398
-
399
- Voice follows you between windows. Every window shares one voice setup, so with
400
- dictation or conversation mode on, the window you switch to listens for your next prompt,
401
- including a new agent the moment its window opens in front. The window you left pauses
402
- its mic. (That's [privateer-speak](https://www.npmjs.com/package/privateer-speak)'s focus
403
- awareness; it needs a terminal that reports focus.)
404
-
405
- Works in **macOS Terminal**, **iTerm2**, **Git Bash's own window (mintty)** on Windows, and
406
- inside **tmux** on any platform; other terminals get told so. macOS may ask once for permission
407
- to let the terminal control itself. In Git Bash, new windows are mintty windows like the one
408
- you started in, and since mintty doesn't tell the program inside when it gains or loses focus,
409
- Privateer watches which window Windows has in front (a small PowerShell loop, one per window)
410
- so the voice still follows you. Names are
411
- shared across every Privateer on the machine (`~/.privateer/terminals.json`), and a window
412
- that's been closed drops off the list on its own.
352
+ Opening a window with a command goes through the gate like running it in bash; switching and
353
+ listing don't ask. The agent can't read what a window prints. These windows are for you.
413
354
 
414
- ## The Privateer app
355
+ Voice follows you: with dictation on, the window you switch to listens and the one you left
356
+ pauses. Works in **macOS Terminal**, **iTerm2**, **Git Bash (mintty)** on Windows, and
357
+ **tmux** anywhere. macOS may ask once for permission to let the terminal control itself.
358
+ Names are shared across the machine in `~/.privateer/terminals.json`.
415
359
 
416
- The same account drives Privateer from **iOS, Android, [the web app](https://privateer.pro),
417
- and a desktop app**. The terminal stays where the work happens — the app is a remote control
418
- and a management surface for it.
360
+ ## The Privateer app
419
361
 
420
- ### Linking a terminal
362
+ The same account drives Privateer from **iOS, Android, [the web](https://privateer.pro) and
363
+ desktop**. The terminal is where the work happens; the app is its remote control and
364
+ settings screen.
421
365
 
422
- 1. Run **`privateer`** and **`/signin`**. Your browser opens an authorize page — check the
423
- code matches the terminal's and click **Authorize**. (No browser handy? The terminal also
424
- prints the link and code: open the app → **Link a terminal** and enter it there.) No
425
- password or wallet key ever touches the terminal, and the app pins the terminal's public
426
- key on first link.
427
- 3. In the terminal, turn on **`/remote-access`** (off by default). The terminal now shows
428
- **Online** in the app.
366
+ ### Link a terminal
429
367
 
430
- > **Only approve a code you generated yourself.** Approving someone else's code hands *them*
431
- > a billed session on *your* account.
368
+ 1. Run **`privateer`**, then **`/login`**, and approve the code in your browser or in the app
369
+ under **Link a terminal**. The app pins the terminal's public key on first link.
370
+ 2. Turn on **`/remote-access`** (off by default). The terminal shows as **Online** in the app.
432
371
 
433
372
  ### What you can do from the app
434
373
 
435
374
  | | |
436
375
  |---|---|
437
- | **Drive a session** | Send prompts, watch streamed output, and **Allow/Deny** each proposed action — including actions from sub-agents the session spawned |
438
- | **Spawn an agent** | Start a one-shot task on the harbor: *background* (headless, read-only toolset, result sealed to your outbox) or *live* (a fresh drivable session) |
439
- | **Routines** | Create, edit, pause, run, and delete scheduled unattended tasks |
440
- | **Workflows** | List, run, and monitor multi-step workflows; answer `human_gate` steps to resume a paused run |
441
- | **MCP connectors** | Add, edit, and enable MCP servers; credentials are sealed to the terminal and write-only |
442
- | **Channels** | Configure the Telegram / Slack / Discord / WhatsApp bridges — admins, members, posture, tool ceiling, model |
443
- | **Extensions & skills** | Install Pi extensions from the catalog; create, edit, and run `SKILL.md` skills |
444
-
445
- Config changes that carry secrets or executable content (MCP credentials, channel bot
446
- tokens, workflows with `script` steps) are **sealed to the terminal's pinned key and signed
447
- by your account** — the relay forwards them blind and can neither read nor forge them.
448
-
449
- The relay itself is live-only (nothing is archived), carries no API keys, and output is
450
- size-truncated and run through a best-effort secret redactor before it leaves your machine.
376
+ | **Drive a session** | Send prompts, watch output stream, and **Allow or Deny** each action, including ones from sub-agents |
377
+ | **Spawn an agent** | Start a one-shot task on Harbor: *background* (headless, read-only, result sealed to your outbox) or *live* (a fresh session you drive) |
378
+ | **Routines** | Create, edit, pause, run and delete scheduled tasks |
379
+ | **Workflows** | List, run and monitor workflows; answer `human_gate` steps |
380
+ | **MCP connectors** | Add, edit and enable servers; credentials are sealed to the terminal and write-only |
381
+ | **Channels** | Configure Telegram, Slack, Discord and WhatsApp: admins, members, posture, tool ceiling, model |
382
+ | **Extensions and skills** | Install Pi extensions from the catalog; create, edit and run `SKILL.md` skills |
383
+
384
+ Changes that carry secrets or executable content (MCP credentials, bot tokens, workflows
385
+ with `script` steps) are **sealed to the terminal's key and signed by your account**, so the
386
+ relay forwards them blind and can't read or forge them. The relay keeps nothing, carries no
387
+ API keys, and output is truncated and run through a secret redactor before it leaves.
451
388
 
452
389
  ### Desktop app
453
390
 
454
- The desktop app hosts the agent **in-process** and talks to it over loopback IPC — no relay,
455
- no network hop, and it works offline. It reads the same `~/.privateer` home, so it shares
456
- your CLI login, model config, and MCP catalog. Multi-window, with a per-window subset of
457
- your MCP connectors and a native folder picker.
391
+ The desktop app hosts the agent **in-process** over loopback IPC: no relay, no network hop,
392
+ works offline. It reads the same `~/.privateer` home, so it shares your login, model config
393
+ and MCP catalog. It supports multiple windows, each with its own subset of connectors.
458
394
 
459
- Download for [macOS](https://privateer.pro/download/mac) (Apple silicon),
460
- [macOS Intel](https://privateer.pro/download/mac-intel), or
461
- [Windows](https://privateer.pro/download/windows).
395
+ Download for [macOS (Apple silicon)](https://privateer.pro/download/mac),
396
+ [macOS (Intel)](https://privateer.pro/download/mac-intel) or
397
+ [Windows](https://privateer.pro/download/windows). Once installed, **`/desktop`** opens it.
398
+ It hosts its own session, so pick your folder from **File ▸ Spawn Privateer at…** and it
399
+ starts with this terminal's model and connectors.
462
400
 
463
- Once it's installed, **`/desktop`** in the terminal brings it up — no Spotlight detour. It
464
- opens the app, not a copy of this conversation: the desktop hosts its own session, so pick
465
- the folder you were working in from **File ▸ Spawn Privateer at…** and it starts on the same
466
- model and connectors this terminal uses (the per-folder defaults live in `~/.privateer`,
467
- which both read).
401
+ It's an early release and **not yet code-signed or notarized**, so macOS warns on first
402
+ open. Routines and channels belong to Harbor, not the desktop app.
468
403
 
469
- It's an early release and **not yet code-signed or notarized** — macOS will warn on first
470
- open. Routines and channels deliberately aren't hosted here: those belong to the always-on
471
- harbor, so background work still wants `privateer harbor install`.
404
+ ## Harbor: run it unattended
472
405
 
473
- ## Run it unattended — Harbor
474
-
475
- **Harbor** is a resident background service that runs scheduled routines, executes workflows,
476
- and accepts task spawns from the app — with no terminal open.
406
+ **Harbor** is a background service that runs scheduled routines and workflows and accepts
407
+ tasks from the app, with no terminal open.
477
408
 
478
409
  ```bash
479
- privateer harbor install # install as a login service (auto-starts, reachable from the app)
480
- privateer harbor status # service installed? harbor answering?
481
- privateer harbor run # or just run it in the foreground
410
+ privateer harbor install # install as a login service
411
+ privateer harbor status # installed? answering?
412
+ privateer harbor run # or run it in the foreground
482
413
  privateer harbor uninstall
483
414
  ```
484
415
 
485
- Installs as a **launchd user agent** on macOS or a **`systemd --user` unit** on Linux — no
486
- root, no sudo. (There's no Windows service path yet; use `privateer harbor run`.) Logs go to
487
- `~/.privateer/harbor.log` on macOS (kept under 5 MB, one previous copy as `harbor.log.1`) and
488
- to the journal on Linux: `journalctl --user -u privateer-harbor`.
416
+ It installs as a **launchd user agent** on macOS or a **`systemd --user` unit** on Linux, no
417
+ root needed. There's no Windows service yet; use `privateer harbor run`. Logs go to
418
+ `~/.privateer/harbor.log` on macOS and to `journalctl --user -u privateer-harbor` on Linux.
489
419
 
490
- Everything the harbor does still runs through the permission gate. Actions needing approval
491
- surface in the app; routines you approved once run on their own schedule. Unattended runs
492
- are confined to their working directory and can't read credential stores (`~/.ssh`,
493
- `~/.aws`, Privateer's own login and config files), whatever tools they're allowed.
420
+ Everything Harbor does goes through the gate. Approvals surface in the app, and routines you
421
+ approved once run on schedule. Unattended runs are confined to their working directory and
422
+ can't read credential stores (`~/.ssh`, `~/.aws`, Privateer's own login), whatever tools
423
+ they're allowed.
494
424
 
495
- **Chat channels** (Telegram, Slack, Discord, WhatsApp) run beside it, as their own service:
425
+ **Chat channels** run beside it as their own service:
496
426
 
497
427
  ```bash
498
- privateer channels install # login service; re-run after changing channels from the app
499
- privateer channels status # which platforms are live right now
500
- privateer channels run # or in the foreground
428
+ privateer channels install # re-run after changing channels from the app
429
+ privateer channels status
430
+ privateer channels run
501
431
  ```
502
432
 
503
- **On a VPS:** run both as a dedicated, unprivileged user, never root. A routine you allow
504
- `bash` runs with that user's full rights. Sign in over SSH with `privateer` and `/login` (it
505
- prints a code to approve in the app). Nothing needs an inbound port, except WhatsApp's
506
- webhook. The Linux unit sets `NoNewPrivileges`, `UMask=0077` and a restart limit. It skips
507
- systemd's namespace sandboxing on purpose, because that fails to start on kernels without
508
- unprivileged user namespaces. In a container with no systemd, use `privateer harbor run`
509
- under the container's own restart policy.
433
+ **On a VPS**, run both as a dedicated unprivileged user, never root: a routine allowed
434
+ `bash` has that user's full rights. Log in over SSH with `privateer` and `/login`. Nothing
435
+ needs an inbound port except WhatsApp's webhook. In a container without systemd, use
436
+ `privateer harbor run` under the container's restart policy.
510
437
 
511
438
  ## Workflows
512
439
 
513
- A workflow is a **YAML file describing a multi-step agent pipeline** — a flat graph of typed
514
- steps (`agent`, `script`, `human_gate`) with conditional routes between them and `{{ }}`
515
- templating to pass values along. A `human_gate` step pauses the run for your approval and
516
- resumes when you answer it, including from your phone.
517
-
518
- The engine ships in the standalone
519
- [`privateer-workflow`](https://www.npmjs.com/package/privateer-workflow) package. Today the
520
- user-facing surface is the **app** (save, run, monitor, share) and the **harbor** that
521
- executes them — there's no `/workflow` command in the terminal yet. Schedule one by pointing
522
- a routine at it.
440
+ A workflow is a **YAML pipeline**: typed steps (`agent`, `script`, `human_gate`), conditional
441
+ routes between them, and `{{ }}` templating to pass values along. A `human_gate` step pauses
442
+ the run until you answer, from your phone if you like.
523
443
 
524
- Because a workflow can carry `script` steps, saving one from the app requires your **account
525
- signature** — the server can't inject a workflow onto your harbor.
444
+ The engine is the [`privateer-workflow`](https://www.npmjs.com/package/privateer-workflow)
445
+ package. You save, run and monitor workflows in the app, and Harbor executes them; there's no
446
+ `/workflow` command in the terminal yet. To schedule one, point a routine at it. Saving a
447
+ workflow with `script` steps needs your **account signature**, so the server can't inject one.
526
448
 
527
449
  ## Chat-app channels
528
450
 
529
- Bridge the agent into **Telegram, Slack, Discord, or WhatsApp** so you can hand it work from
530
- a group chat. Each channel has:
451
+ Bridge the agent into **Telegram, Slack, Discord or WhatsApp** and hand it work from a group
452
+ chat. Each channel has:
531
453
 
532
- - **Roles** — `admins` can approve actions; `members` are always read-only, no exceptions.
533
- - **A posture** — `readonly`, `approve` (default), or `auto`.
534
- - **A hard tool ceiling** — a per-channel allowlist the agent can't exceed even in `auto`.
454
+ - **Roles:** `admins` can approve actions; `members` are always read-only.
455
+ - **A posture:** `readonly`, `approve` (default) or `auto`.
456
+ - **A tool ceiling:** a per-channel allowlist the agent can't exceed, even in `auto`.
535
457
 
536
- Configure a channel from the app, or by hand in the `channels` block of
537
- `~/.privateer/config.json`. Changes take effect on restart, by design. Bot tokens set from
538
- the app are write-only — the app can name them but never read them back. Note that tokens
539
- live in plaintext in `config.json` on your machine, and every channel action is appended to
540
- `~/.privateer/channels-audit.log`.
458
+ Configure channels in the app or in the `channels` block of `~/.privateer/config.json`;
459
+ changes apply on restart. Tokens set from the app are write-only, but they're stored in
460
+ plaintext in `config.json`. Every channel action is logged to `~/.privateer/channels-audit.log`.
541
461
 
542
- ## Drive it from Buzz or Zed — ACP
462
+ ## ACP: drive it from Buzz, Zed or your own program
543
463
 
544
464
  Privateer speaks the [Agent Client Protocol](https://agentclientprotocol.com) (ACP v1 over
545
- stdio). Any ACP host — [Buzz](https://buzz.xyz), Block's team messenger where agents are
546
- teammates, or the [Zed](https://zed.dev) editor — can spawn `privateer acp` and drive it:
547
- prompts stream back, tool activity shows live, and the host's model picker lists Privateer's
548
- catalog with TEE-backed models labelled **confidential (TEE)**.
549
-
550
- The part we care about: **the host renders the UI, but authority never leaves your machine.**
551
-
552
- - Every action is classified by Privateer's own permission gate — ACP's
553
- `session/request_permission` only delivers the prompt.
554
- - The **tool ceiling** comes from your local config, not the host, and ships **read-only**
555
- (`read`, `grep`, `find`, `ls`). The host cannot widen it.
556
- - Filesystem access is **confined to one directory root**; out-of-tree access is refused,
557
- not prompted.
558
- - Every ambiguous outcome — unreachable host, cancelled dialog, unknown answer, aborted
559
- turn — resolves to **deny**.
560
- - "Allow for this session" lives in memory and dies with the session; dangerous shell
561
- (`curl … | sh` and friends) can never become standing permission.
562
-
563
- Zed setup (`settings.json`):
465
+ stdio). An ACP host such as [Buzz](https://buzz.xyz) or [Zed](https://zed.dev) can run
466
+ `privateer acp` and drive it: prompts stream back, tool activity shows live, and the model
467
+ picker labels TEE-backed models **confidential (TEE)**.
468
+
469
+ **The host draws the UI; authority stays on your machine.**
470
+
471
+ - Privateer's own gate classifies every action. ACP only delivers the prompt.
472
+ - The **tool ceiling** comes from your local config and defaults to **read-only** (`read`,
473
+ `grep`, `find`, `ls`). The host can't widen it.
474
+ - File access is **confined to one root**; anything outside is refused.
475
+ - Anything ambiguous (unreachable host, cancelled dialog, aborted turn) resolves to **deny**.
476
+ - "Allow for this session" dies with the session, and dangerous shell never becomes
477
+ standing permission.
478
+
479
+ Zed `settings.json`:
564
480
 
565
481
  ```json
566
482
  { "agent_servers": { "Privateer": { "command": "privateer", "args": ["acp"] } } }
567
483
  ```
568
484
 
569
- Honest caveat for Buzz: **Buzz currently auto-approves permission prompts**, so under Buzz
570
- the tool ceiling *is* the control — which is exactly why the default is read-only. Full
571
- setup, config, and limitations: [`docs/acp.md`](docs/acp.md).
572
-
573
- Driving Privateer from **your own program or agent**? ACP is how that program gets asked:
574
- every approval arrives as a `session/request_permission` call it answers. The wire format,
575
- option ids and a minimal client are in [`docs/acp.md`](docs/acp.md#driving-privateer-from-another-agent).
576
- Handing it data your program shouldn't see? Set `"private": true` in the `acp` block; see
577
- [Hand off sensitive work](#hand-off-sensitive-work-to-privateer).
485
+ **Buzz currently auto-approves permission prompts**, so under Buzz the tool ceiling is the
486
+ control, which is why it defaults to read-only. Driving Privateer from your own program
487
+ works the same way: every approval arrives as a `session/request_permission` call. Setup,
488
+ wire format and a minimal client are in [`docs/acp.md`](docs/acp.md). Set `"private": true`
489
+ in the `acp` block to hand it data your program shouldn't see.
578
490
 
579
491
  ### One-shot runs (`-p`) and spending
580
492
 
581
- A `privateer -p "…"` run has no screen, so anything that needs approval is **denied**. That
582
- includes every billed media tool, and the run says so when it starts. Two flags change it,
583
- and both apply to that one invocation only. Nothing is saved, and an exported environment
584
- variable can't turn either on.
493
+ `privateer -p "…"` has no screen, so anything that needs approval is **denied**, including
494
+ every billed media tool. Two flags change that for one invocation only; nothing is saved and
495
+ no environment variable can turn them on.
585
496
 
586
497
  ```bash
587
498
  # pre-approve named billed tools, capped by calls and/or estimated dollars
588
499
  privateer -p --allow-spend generate_video --max-calls 1 --max-spend 1.00 "make a 6s intro clip"
589
500
 
590
- # or ask on your phone: approvals go to the Privateer app, denied if unanswered in time
501
+ # or approve on your phone; unanswered approvals are denied after the timeout
591
502
  privateer -p --approve-in-app --approval-timeout 300 "make a 6s intro clip"
592
503
  ```
593
504
 
594
- `--max-spend` is checked before each call against the server's own estimate for that exact
595
- call. `media_capabilities` shows the same prices. A call that can't be priced is refused
596
- under a dollar cap rather than let through. `--approve-in-app` reaches the app while it's
597
- open or running in the background.
505
+ `--max-spend` is checked before each call against the server's estimate for that call
506
+ (`media_capabilities` shows the same prices). A call that can't be priced is refused.
598
507
 
599
- ## Hand off sensitive work to Privateer
508
+ ## Hand off sensitive work
600
509
 
601
- Your coding agent's context goes to its provider. When a task touches files that
602
- shouldn't (patient records, a customer export, payroll, a database dump), the agent can
603
- hand that part to Privateer instead of reading the files itself:
510
+ Your coding agent's context goes to its provider. When a task touches files that shouldn't
511
+ (patient records, a customer export, payroll), the agent can hand that part to Privateer:
604
512
 
605
513
  ```bash
606
514
  privateer -p --private --model privateer/tinfoil/gemma4-31b \
607
515
  "Read customers/export.csv. Reply with the number of customers per country. No row-level data."
608
516
  ```
609
517
 
610
- The calling agent passes file *names*. Privateer reads the files on this machine, reasons
611
- over them on a verified-private model, and prints only the answer. `--private` is what
612
- makes that a guarantee rather than a hope:
518
+ The calling agent passes file *names*. Privateer reads the files locally, reasons over them
519
+ on a verified-private model, and prints only the answer. `--private` makes that a guarantee:
613
520
 
614
521
  - **No file reaches an unverified model.** Before every tool call the model must be
615
- `tee-verified` (an enclave quote Privateer checked itself) or `local`. A ZDR route, a
616
- standard provider, or a failed attestation refuses the tool.
617
- - **Nothing leaves through a tool.** Only on-machine tools run. Web, MCP, media, uploads
618
- and network shell commands (`curl`, `ssh`, `git push`, …) are refused.
522
+ `tee-verified` (an enclave quote Privateer checked itself) or `local`.
523
+ - **Nothing leaves through a tool.** Web, MCP, media, uploads and network shell commands
524
+ (`curl`, `ssh`, `git push`) are refused.
619
525
  - **Nothing lifts it.** It sits above permission modes and approvals, `--no-quarter`
620
- included, and subagents inherit it.
621
- - **The caller sees only the answer.** `-p` prints the reply. `--private --mode json`,
622
- which would stream the file contents, is refused.
526
+ included, and sub-agents inherit it.
527
+ - **The caller sees only the answer.** `--private --mode json`, which would stream file
528
+ contents, is refused.
623
529
 
624
- The reply itself is the one channel left, so ask for aggregates, yes/no answers, or a
625
- summary, and have Privateer write detail to a file. Setup for Claude Code and other agents,
626
- the ACP route for your own programs, prompt patterns, and the honest limits are in
627
- [`docs/private-handoff.md`](docs/private-handoff.md).
530
+ The reply is the one channel left, so ask for aggregates, yes/no answers or summaries, and
531
+ have Privateer write details to a file. Setup for Claude Code and other agents, prompt
532
+ patterns and the limits are in [`docs/private-handoff.md`](docs/private-handoff.md).
628
533
 
629
- ## Connectors — MCP
534
+ ## Connectors (MCP)
630
535
 
631
- Privateer is an **MCP client**. Point it at a [Model Context Protocol](https://modelcontextprotocol.io)
632
- server and that server's tools become first-class agent tools, gated exactly like the
633
- built-ins. Two kinds:
536
+ Privateer is an **MCP client**, built on Pi's own MCP support. Point it at a
537
+ [Model Context Protocol](https://modelcontextprotocol.io) server and its tools become agent
538
+ tools, gated like the built-ins.
634
539
 
635
540
  | | |
636
541
  |---|---|
637
- | **Local — `stdio`** | Privateer spawns the server as a child process on this machine. Nothing leaves the box except what that server itself chooses to send. |
638
- | **Remote — `http`** | An `https` endpoint somebody else hosts. It authenticates with `oauth` (you authorize in a browser on **this** machine), a static `bearer` token, or nothing at all. Whatever the agent hands that server leaves your machine — the app shows a "sends data to *host*" badge for exactly this reason. |
542
+ | **Local (`stdio`)** | Privateer starts the server as a process on this machine. Nothing leaves except what that server sends. |
543
+ | **Remote (`http`)** | A streamable-HTTP endpoint someone else hosts, using OAuth (you authorize in a browser on this machine), a bearer token, or no auth. Whatever the agent sends it leaves your machine, which is why the app badges it "sends data to *host*". SSE-only endpoints aren't supported. |
639
544
 
640
545
  ### Add one
641
546
 
642
547
  ```
643
- /connect # add, enable, disable, or remove connectors
644
- /mcp # Pi's own status view — what connected; `/mcp login <name>` to sign in
548
+ /connect add, enable, disable or remove connectors
549
+ /mcp Pi's status view: what connected, and sign-in for OAuth servers
550
+ privateer mcp list the same from the shell (also: login, logout, add, remove)
645
551
  ```
646
552
 
647
- `/connect` opens a picker over a curated catalog of 21 connectors — GitHub, Slack, Notion,
648
- Linear, Jira & Confluence, Sentry, Stripe, Asana, Supabase, Figma, Gmail, Google Drive,
649
- PostgreSQL, Playwright, Filesystem, … — plus a **Custom connector** entry for anything
650
- else: any stdio command line, or any `https://` URL. Pick one, fill in the token or path it
651
- asks for, and the adapter reloads in place, so the new tools are live in the session you're
652
- already sitting in. You can do the same from [the app](#the-privateer-app) or the desktop
653
- app; all three edit the same files.
553
+ `/connect` opens a catalog of 23 connectors (GitHub, Slack, Notion, Linear, Atlassian,
554
+ Sentry, Stripe, Asana, Supabase, Figma, Gmail, Google Drive, PostgreSQL, Playwright,
555
+ Filesystem and more) plus a **Custom connector** for any stdio command or `https://` URL.
556
+ New tools are live in the session you're already in. The app and desktop app edit the same
557
+ config.
558
+
559
+ > **Upgrading from 0.14?** OAuth connectors need signing in once more on the new MCP client.
560
+ > Run `/mcp` and sign each one back in.
654
561
 
655
- ### One config, three surfaces
562
+ ### Config files
656
563
 
657
564
  ```
658
- ~/.privateer/agent/mcp-desktop.json # source of truth — every connector, each with `enabled`
659
- ~/.privateer/agent/mcp.json # projection: enabled connectors only, in the standard
660
- # { "mcpServers": … } shape the adapter reads
565
+ ~/.privateer/agent/mcp-desktop.json # source of truth: every connector, each with `enabled`
566
+ ~/.privateer/agent/mcp.json # generated for Pi from the file above
661
567
  ```
662
568
 
663
- Don't hand-edit the projection — it is rewritten from the source on every change. Edit
664
- `mcp-desktop.json`, or just use `/connect`.
665
-
666
- Both files live in the shared `~/.privateer` home, so a connector you add in the terminal is
667
- already there for the harbor's unattended routine runs and for the desktop app's windows.
668
- One machine, one coherent connector config, however you reached it.
569
+ Don't edit `mcp.json` by hand; it's rewritten on every change (a file from an older
570
+ release is converted once at launch). Edit `mcp-desktop.json` or use `/connect`. Both live
571
+ in `~/.privateer`, so a connector you add in the terminal is also there for Harbor and the
572
+ desktop app.
669
573
 
670
- ### Tools and the moat
574
+ ### Tools and the gate
671
575
 
672
- By default the adapter exposes MCP through a **single proxy tool named `mcp`** — one grant
673
- covers every server you've enabled. When a routine carries a per-connector allow-list,
674
- Privateer scopes that run down to exactly the selected servers and tools instead, each
675
- registered under its own `<server>_<tool>` name, so an unattended task can hold GitHub's
676
- `create_issue` without holding all of MCP.
576
+ The model reaches MCP tools through **codemode**: it writes a short script that calls them.
577
+ Each call inside that script reaches the gate on its own as `mcp__<server>__<tool>`, so
578
+ **every MCP tool goes through the same permission gate as the built-ins**. Configuring a
579
+ server doesn't make its tools trusted. Codemode scripts can't run models with your keys.
677
580
 
678
- Either way, **every MCP tool goes through the same permission gate as the built-ins.** A
679
- tool is not trusted because you configured the server it came from.
581
+ A routine can carry a per-connector allow-list, so an unattended task can hold GitHub's
582
+ `create_issue` without holding all of MCP. A routine with no allow-list gets no MCP tools.
680
583
 
681
584
  ### Credentials
682
585
 
683
- A connector's secrets — env values, a bearer token, an `Authorization:` header — are written
684
- in **plaintext** to `mcp-desktop.json` on this machine. That's unavoidable: the adapter has
685
- to hand the real token to the server. `/connect` masks the field while you type, which is
686
- shoulder-surfing and screen-share hygiene, not a storage claim. Protect that file the way you
687
- protect `~/.aws/credentials`.
586
+ Connector secrets (env values, bearer tokens, `Authorization` headers) are stored in
587
+ **plaintext** in `mcp-desktop.json` and `mcp.json`, because the server needs the real
588
+ token. `/connect` masks the field while you type, but that's screen hygiene, not storage
589
+ protection. Guard those files like `~/.aws/credentials`.
688
590
 
689
- Editing connectors **from the app** is a different story: over the relay secrets are
690
- write-only in both directions. A listing returns env/header *names* and which of them are
691
- set — never a value — and a value you type on your phone is sealed to that terminal's pinned
692
- key before it leaves the device, so the relay forwards it blind. See
693
- [What you can do from the app](#what-you-can-do-from-the-app).
591
+ From **the app**, secrets are write-only: listings show which names are set, never values,
592
+ and a value you type is sealed to the terminal's key before it leaves your phone.
694
593
 
695
- A hand-written `.mcp.json` in a project directory is a **protected path**: the agent can be
696
- asked to edit one, but never does it silently, in any mode.
594
+ A project's `.mcp.json` or `.pi/mcp.json` is a **protected path**: the agent can be asked to
595
+ edit one, but never silently.
697
596
 
698
- > **Hosted harbors are OAuth-only by design** — no stdio child processes, no stored tokens,
699
- > because a hosted tenant's home is tmpfs and a durable secret would have to rest somewhere
700
- > we could read. In the current preview they carry no connectors at all; mirroring your
701
- > catalog into a hosted agent isn't wired up yet.
597
+ > **Hosted harbors are OAuth-only by design**: no stdio processes and no stored tokens. In
598
+ > the current preview they carry no connectors at all.
702
599
 
703
600
  ## Permission modes
704
601
 
705
602
  | Mode | Behavior |
706
603
  |---|---|
707
- | `default` | prompt before edits and shell commands |
708
- | `acceptEdits` | auto-approve file edits; still prompt for shell commands |
604
+ | `default` | ask before edits and shell commands |
605
+ | `acceptEdits` | auto-approve file edits; still ask for shell commands |
709
606
  | `bypass` | no prompts (destructive commands are *still* blocked) |
710
- | `plan` | read-only; the agent presents a plan, then you approve to proceed |
607
+ | `plan` | read-only; the agent presents a plan for you to approve |
711
608
 
712
- Switch with **`/mode`**. Even in `bypass`, a danger filter blocks destructive shell commands,
713
- and protected files (`.env`, shell rc files…) are guarded — the gate is never fully off.
609
+ Switch with **`/mode`**. Even in `bypass`, destructive shell commands are blocked and
610
+ protected files (`.env`, shell rc files) are guarded.
714
611
 
715
- ### No quarter — lower the moat entirely
612
+ ### No quarter: lower the moat entirely
716
613
 
717
- This is the one exception to "the gate is never fully off." It disables the permission
718
- gate for the **whole session** — every action auto-approves with no prompt, including
719
- destructive shell commands, out-of-cwd access, and protected files. Subagents spawned
720
- after it goes on inherit it (env `PRIVATEER_NO_QUARTER=1`). Only for a directory and a
721
- task you fully trust.
722
-
723
- Three ways in, all the same switch:
614
+ The one exception. **No quarter** turns the gate off for the **whole session**: every action
615
+ auto-approves, including destructive commands, access outside the working directory, and
616
+ protected files. Sub-agents started after it's on inherit it. Use it only for a directory
617
+ and a task you fully trust.
724
618
 
725
619
  | | |
726
620
  |---|---|
727
- | **shift+tab** | toggle it mid-session — hit it and walk away, and the agent runs the task to the end instead of stopping at the next approval |
621
+ | **shift+tab** | toggle it mid-session; the agent then runs to the end instead of stopping at the next approval |
728
622
  | `/no-quarter [on\|off]` | the typed equivalent |
729
623
  | `privateer --no-quarter` | start a session with the moat already down |
730
624
 
731
- It's never quietly in effect: the launch flag prints a red warning banner, the toggle
732
- posts a warning to the transcript, and while it's on the footer carries a permanent red
733
- `⚑ no quarter — permission gate OFF` indicator. shift+tab again raises the moat.
734
-
735
- Toggling takes effect from the next gated action — an approval already on screen still
736
- needs an answer. It's a physical-terminal switch: a phone driving this terminal over
737
- `/remote-access` can't reach it. The app has its own no-quarter toggle for driven turns,
738
- and it means the same thing this flag does: the moat down, dangerous shell and destructive
739
- actions included — stronger than `/mode bypass`, which keeps those two above it. A hard
740
- plan-mode deny is the one thing it doesn't talk around.
625
+ It's never quiet: the flag prints a red warning, the toggle posts one to the transcript, and
626
+ the footer shows `⚑ no quarter, permission gate OFF` while it's on. An approval already on
627
+ screen still needs an answer, and a phone driving the terminal can't flip it (the app has
628
+ its own toggle for driven turns). A hard plan-mode deny still holds.
741
629
 
742
- > shift+tab is Pi's default "cycle thinking level" chord; Privateer takes it for this.
743
- > Thinking level is still under `/settings`, or bind `app.thinking.cycle` to another key
744
- > in `~/.privateer/agent/keybindings.json`.
630
+ > shift+tab is Pi's default "cycle thinking level" key. Thinking level is still under
631
+ > `/settings`, or bind `app.thinking.cycle` to another key in
632
+ > `~/.privateer/agent/keybindings.json`.
745
633
 
746
634
  ## Extend it
747
635
 
748
- Everything below is a **Pi extension** loaded by discovery (see [Built on Pi](#built-on-pi)) —
749
- drop your own into `~/.privateer/agent/extensions/` and it loads the same way, gated like the rest.
750
-
751
- - **MCP servers** (Pi's built-in MCP support) — declare them and the model reaches their tools
752
- through codemode, each call gated like the rest (local stdio, or remote streamable HTTP with
753
- interactive OAuth). Add them with `/connect`; see [Connectors — MCP](#connectors--mcp).
754
- - **Sub-agents** (`pi-subagents`) — delegate investigations to bounded parallel agents. Children
755
- run as headless child processes that **inherit the moat**, so their actions hit the same
756
- permission gate and their approvals surface on your phone.
757
- - **Routines** — saved tasks the harbor runs unattended; ask the agent to schedule work and
758
- approve it once.
759
- - **Workflows** — declarative multi-step pipelines the harbor executes; see
760
- [Workflows](#workflows).
761
- - **Web tools** (`privateer-web`) — `web_search` and `web_fetch`, by one of two routes. Sign in
762
- and they run on your Privateer account: no API key to obtain or keep on the machine, metered
763
- against the account's daily web allowance, with the search itself made server-side (the derived
764
- query is visible to Privateer — the page you fetch and the conversation around it are not).
765
- Configure a provider of your own with `/web-tools` and that wins instead — `rpiv-web-tools` with
766
- pluggable backends, including self-hosted SearXNG for fully private search, which is why a
767
- provider you chose is never overridden. `PRIVATEER_WEB_SEARCH=privateer` picks the account route
768
- even when you hold a key. Unattended runs (harbor, channels, ACP) always take the account route:
769
- a routine must not hold a provider key it could be prompt-injected into leaking.
770
- - **Ask user question** (`rpiv-ask-user-question`) — when a request is underspecified the agent
771
- raises a structured questionnaire (typed options, multi-select, markdown previews, or type your
772
- own answer) instead of guessing. Ungated by design — it only asks you something.
636
+ Everything here is a Pi extension loaded by discovery (see [Built on Pi](#built-on-pi)), and
637
+ yours load the same way, gated like the rest.
638
+
639
+ - **MCP servers** through Pi's built-in support and codemode. See [Connectors (MCP)](#connectors-mcp).
640
+ - **Sub-agents** (`pi-subagents`): delegate to bounded parallel agents. Children run as
641
+ headless processes that **inherit the moat** and keep MCP, so their actions hit the same
642
+ gate and their approvals reach your phone.
643
+ - **Routines:** tasks Harbor runs unattended. Ask the agent to schedule work and approve it once.
644
+ - **Workflows:** multi-step pipelines Harbor executes. See [Workflows](#workflows).
645
+ - **Web tools** (`privateer-web`): `web_search` and `web_fetch`. Signed in, they run on your
646
+ account with no key to manage; the search query is visible to Privateer, the pages and
647
+ conversation aren't. Set your own provider with `/web-tools` (`rpiv-web-tools`, including
648
+ self-hosted SearXNG) and it takes over. Unattended runs always use the account route, so a
649
+ routine never holds a provider key it could be tricked into leaking.
650
+ - **Ask user question** (`rpiv-ask-user-question`): when a request is unclear, the agent asks
651
+ a structured question with options, multi-select or free text, instead of guessing.
773
652
 
774
653
  ## Command reference
775
654
 
776
655
  | Command | What it does |
777
656
  |---|---|
778
- | `/model` · `/models` | switch model; `/models` is a searchable picker with TEE/ZDR privacy shields |
657
+ | `/model` · `/models` | switch model; `/models` is a searchable picker with TEE/ZDR shields |
779
658
  | `/mode` | switch permission mode |
780
- | `/no-quarter` | lower the moat for this session and run unattended (**shift+tab**) |
659
+ | `/no-quarter` | turn the gate off for this session (**shift+tab**) |
781
660
  | `/verify` | fetch and check the TEE attestation for the current model |
782
- | `/signin` · `/signout` | sign in to a Privateer account (device flow) / sign out |
783
- | `/remote-access` | link this terminal to the app and allow it to drive (off by default) |
784
- | `/connect` · `/mcp` | add, enable, or remove MCP connectors / see what actually connected |
661
+ | `/login` · `/logout` | log in to a Privateer account (device flow) / log out |
662
+ | `/remote-access` | let the app drive this terminal (off by default) |
663
+ | `/connect` · `/mcp` | manage MCP connectors / see what connected and sign in |
785
664
  | `/speak` · `/talk` | read answers aloud / voice input (**alt+t** is push-to-talk) |
786
- | `/mood` | pick a voice mood (focused, relaxed, hands-free, quiet, or your own; `/mood save <name>` keeps the current setup) |
787
- | `/fresh` | replace this agent with a new process: everything it started (dev servers, watchers, subagents) is stopped, and the new agent has no link to the old one (`/resume` still reaches the old session). Saying "fresh start" does the same |
665
+ | `/mood` | pick a voice mood, or `/mood save <name>` to keep your current setup |
666
+ | `/fresh` | replace this agent with a new process and stop everything it started (`/resume` still reaches the old session) |
788
667
  | `/extensions` | list loaded Pi extensions |
789
- | `/web-tools` | point `web_search`/`web_fetch` at a search provider of your own (signed in, they already work on your account) |
790
- | `/init` | scaffold a starter `PRIVATEER.md` in this directory |
791
- | `/desktop` | open the [desktop app](#desktop-app) — same login, same per-folder defaults |
792
- | `/update` · `/privateer` | update to the latest release / Privateer status and posture |
793
-
794
- Shell subcommands: `privateer` (interactive), `privateer update`, `privateer harbor …`,
795
- `privateer fresh [n]` (swap a running terminal's agent from another terminal, even when that
796
- agent is stuck),
797
- `privateer acp` (serve the agent to an ACP host like Buzz or Zed — see
798
- [`docs/acp.md`](docs/acp.md)), `privateer auth status` (is this machine signed in?),
799
- `privateer -p … [--allow-spend …] [--approve-in-app]` (see
800
- [one-shot runs](#one-shot-runs--p-and-spending)), `privateer --private` (tools run only on a
801
- verified-private model and never reach the network; see
802
- [Hand off sensitive work](#hand-off-sensitive-work-to-privateer)), `privateer --no-quarter`,
803
- `privateer --version`.
804
- An unknown subcommand of `auth` is an error. It is never sent to the model as a prompt.
668
+ | `/web-tools` | point web search and fetch at your own provider |
669
+ | `/init` | scaffold a starter `PRIVATEER.md` |
670
+ | `/desktop` | open the [desktop app](#desktop-app) |
671
+ | `/update` · `/privateer` | update to the latest release / account status and posture |
672
+
673
+ Shell commands:
674
+
675
+ | Command | What it does |
676
+ |---|---|
677
+ | `privateer` | start the interactive agent |
678
+ | `privateer update` · `privateer --version` | update / show the version |
679
+ | `privateer verify` | check this install against what was published |
680
+ | `privateer auth status` | is this machine logged in? |
681
+ | `privateer harbor …` · `privateer channels …` | manage the background services |
682
+ | `privateer mcp list\|login\|logout\|add\|remove` | manage MCP servers from the shell |
683
+ | `privateer acp` | serve the agent to an ACP host ([`docs/acp.md`](docs/acp.md)) |
684
+ | `privateer fresh [n]` | swap a running terminal's agent from another terminal, even a stuck one |
685
+ | `privateer -p "…"` | one-shot run ([spending flags](#one-shot-runs--p-and-spending)) |
686
+ | `privateer --private` | tools only on a verified-private model, never the network ([details](#hand-off-sensitive-work)) |
687
+ | `privateer --no-quarter` | start with the gate off |
805
688
 
806
689
  ## Develop
807
690
 
@@ -810,12 +693,6 @@ npm run typecheck
810
693
  npm test
811
694
  ```
812
695
 
813
- ## Changelog
814
-
815
- Release notes and what's new in each version live on the
816
- [**GitHub releases page**](https://github.com/privateer-agent/privateer-agent/releases).
817
- Privateer keeps its startup clean — the app won't dump a changelog into your terminal.
818
-
819
696
  ## License
820
697
 
821
698
  [MIT](LICENSE) © Patrick