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 +447 -570
- package/extensions/privateer-brand.ts +9 -9
- package/package.json +1 -1
- package/src/cli/chat.ts +22 -10
- package/src/config/whatsNew.json +3 -3
- package/src/mcp/catalog.ts +479 -0
- package/src/remote/liveTaskSession.ts +12 -1
- package/src/remote/remoteBridge.ts +83 -22
- package/src/ui/palette.ts +17 -0
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
32
|
-
**
|
|
33
|
-
**
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
|
42
|
-
**Harbor** (a background service
|
|
43
|
-
[phone, web](https://privateer.pro)
|
|
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
|
-
##
|
|
47
|
+
## What's new in 0.15.0
|
|
66
48
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
60
|
+
## Why Privateer?
|
|
96
61
|
|
|
97
|
-
- **
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
- **
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
|
150
|
-
privateer #
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
|
93
|
+
irm https://privateer.pro/install.ps1 | iex # Windows (PowerShell)
|
|
162
94
|
|
|
163
|
-
#
|
|
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
|
|
169
|
-
|
|
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
|
|
173
|
-
|
|
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
|
|
176
|
-
>
|
|
177
|
-
>
|
|
178
|
-
> `~/.privateer/agent/settings.json`. Linux arm64
|
|
179
|
-
>
|
|
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
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
###
|
|
117
|
+
### Verify what you're about to run
|
|
189
118
|
|
|
190
|
-
Privateer
|
|
191
|
-
|
|
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 #
|
|
196
|
-
#
|
|
197
|
-
|
|
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
|
-
|
|
202
|
-
an install-time one:
|
|
128
|
+
After installing:
|
|
203
129
|
|
|
204
130
|
```bash
|
|
205
|
-
privateer verify # is the install on
|
|
131
|
+
privateer verify # is the install on this disk still the one we published?
|
|
206
132
|
```
|
|
207
133
|
|
|
208
|
-
|
|
209
|
-
provenance attestation, whether any dependency
|
|
210
|
-
|
|
211
|
-
|
|
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
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
|
|
224
|
-
|
|
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
|
|
157
|
+
npm start
|
|
237
158
|
```
|
|
238
159
|
|
|
239
160
|
## Configure a provider
|
|
240
161
|
|
|
241
|
-
Privateer reads
|
|
242
|
-
keys entirely
|
|
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
|
|
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-...
|
|
177
|
+
export PRIVATEER_API_KEY=sk-priv-... # Privateer developer API (privateer.pro)
|
|
257
178
|
```
|
|
258
179
|
|
|
259
|
-
Pick a model with **`/model
|
|
260
|
-
|
|
261
|
-
`
|
|
262
|
-
|
|
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
|
-
|
|
185
|
+
## Built on Pi
|
|
265
186
|
|
|
266
|
-
|
|
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
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
|
|
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
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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
|
-
##
|
|
278
|
+
## The PII gate
|
|
285
279
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
|
350
|
-
/speak voice <name> pick a speaker /talk
|
|
351
|
-
/speak rate <n> 0.
|
|
352
|
-
/speak stream off wait for the full answer
|
|
353
|
-
/speak provider list engines
|
|
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
|
|
358
|
-
**confidential-compute TTS and STT
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
off
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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
|
|
382
|
-
|
|
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
|
|
387
|
-
/term 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
|
|
390
|
-
/term close api
|
|
391
|
-
/term list
|
|
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
|
-
|
|
395
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
431
|
-
|
|
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
|
|
438
|
-
| **Spawn an agent** | Start a one-shot task on
|
|
439
|
-
| **Routines** | Create, edit, pause, run
|
|
440
|
-
| **Workflows** | List, run
|
|
441
|
-
| **MCP connectors** | Add, edit
|
|
442
|
-
| **Channels** | Configure
|
|
443
|
-
| **Extensions
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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**
|
|
455
|
-
|
|
456
|
-
|
|
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)
|
|
460
|
-
[macOS Intel](https://privateer.pro/download/mac-intel)
|
|
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
|
-
|
|
464
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
480
|
-
privateer harbor status #
|
|
481
|
-
privateer harbor run # or
|
|
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
|
-
|
|
486
|
-
root
|
|
487
|
-
`~/.privateer/harbor.log` on macOS
|
|
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
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
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**
|
|
425
|
+
**Chat channels** run beside it as their own service:
|
|
496
426
|
|
|
497
427
|
```bash
|
|
498
|
-
privateer channels install #
|
|
499
|
-
privateer channels status
|
|
500
|
-
privateer channels run
|
|
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
|
|
504
|
-
`bash`
|
|
505
|
-
|
|
506
|
-
|
|
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
|
|
514
|
-
|
|
515
|
-
|
|
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
|
-
|
|
525
|
-
|
|
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
|
|
530
|
-
|
|
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
|
|
533
|
-
- **A posture
|
|
534
|
-
- **A
|
|
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
|
|
537
|
-
|
|
538
|
-
|
|
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
|
-
##
|
|
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).
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
-
|
|
553
|
-
`
|
|
554
|
-
-
|
|
555
|
-
|
|
556
|
-
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
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
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
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
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
|
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
|
|
595
|
-
|
|
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
|
|
508
|
+
## Hand off sensitive work
|
|
600
509
|
|
|
601
|
-
Your coding agent's context goes to its provider. When a task touches files that
|
|
602
|
-
|
|
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
|
|
611
|
-
|
|
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`.
|
|
616
|
-
|
|
617
|
-
|
|
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
|
|
621
|
-
- **The caller sees only the answer.**
|
|
622
|
-
|
|
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
|
|
625
|
-
|
|
626
|
-
|
|
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
|
|
534
|
+
## Connectors (MCP)
|
|
630
535
|
|
|
631
|
-
Privateer is an **MCP client
|
|
632
|
-
server and
|
|
633
|
-
built-ins.
|
|
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
|
|
638
|
-
| **Remote
|
|
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
|
|
644
|
-
/mcp
|
|
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
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
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
|
-
###
|
|
562
|
+
### Config files
|
|
656
563
|
|
|
657
564
|
```
|
|
658
|
-
~/.privateer/agent/mcp-desktop.json # source of truth
|
|
659
|
-
~/.privateer/agent/mcp.json #
|
|
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
|
|
664
|
-
`mcp-desktop.json
|
|
665
|
-
|
|
666
|
-
|
|
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
|
|
574
|
+
### Tools and the gate
|
|
671
575
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
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
|
-
|
|
679
|
-
|
|
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
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
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
|
-
|
|
690
|
-
|
|
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
|
|
696
|
-
|
|
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
|
|
699
|
-
>
|
|
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` |
|
|
708
|
-
| `acceptEdits` | auto-approve file edits; still
|
|
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
|
|
607
|
+
| `plan` | read-only; the agent presents a plan for you to approve |
|
|
711
608
|
|
|
712
|
-
Switch with **`/mode`**. Even in `bypass`,
|
|
713
|
-
|
|
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
|
|
612
|
+
### No quarter: lower the moat entirely
|
|
716
613
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
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
|
|
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
|
|
732
|
-
|
|
733
|
-
|
|
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"
|
|
743
|
-
>
|
|
744
|
-
>
|
|
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
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
- **MCP servers**
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
- **
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
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
|
|
657
|
+
| `/model` · `/models` | switch model; `/models` is a searchable picker with TEE/ZDR shields |
|
|
779
658
|
| `/mode` | switch permission mode |
|
|
780
|
-
| `/no-quarter` |
|
|
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
|
-
| `/
|
|
783
|
-
| `/remote-access` |
|
|
784
|
-
| `/connect` · `/mcp` |
|
|
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
|
|
787
|
-
| `/fresh` | replace this agent with a new process
|
|
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
|
|
790
|
-
| `/init` | scaffold a starter `PRIVATEER.md`
|
|
791
|
-
| `/desktop` | open the [desktop app](#desktop-app)
|
|
792
|
-
| `/update` · `/privateer` | update to the latest release /
|
|
793
|
-
|
|
794
|
-
Shell
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
`privateer
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
`privateer
|
|
804
|
-
|
|
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
|