privateer-agent 0.6.6 → 0.6.8
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 +163 -22
- package/SECURITY.md +5 -1
- package/bin/privateer-launch.mjs +31 -23
- package/extensions/privateer-brand.ts +147 -60
- package/package.json +1 -1
- package/patches/@earendil-works+pi-coding-agent+0.80.3.patch +110 -3
- package/src/auth/accountSessions.ts +157 -0
- package/src/auth/privateer.ts +225 -41
- package/src/cli/chat.ts +3 -3
- package/src/config/paths.ts +9 -0
- package/src/daemon/index.ts +4 -4
- package/src/providers/account.ts +167 -17
- package/src/providers/defaultModel.ts +42 -26
package/README.md
CHANGED
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
</p>
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
curl -fsSL https://privateer.pro/install.sh | sh # installs the `privateer` command
|
|
26
|
+
curl -fsSL https://privateer.pro/install.sh | sh # macOS / Linux — installs the `privateer` command
|
|
27
|
+
irm https://privateer.pro/install.ps1 | iex # Windows (PowerShell)
|
|
27
28
|
npx privateer-agent # or run it instantly, nothing installed
|
|
28
29
|
```
|
|
29
30
|
|
|
@@ -33,9 +34,13 @@ Point it at a frontier model today and a local Ollama model tomorrow — **OpenR
|
|
|
33
34
|
inference), **Venice** / **Fireworks** (no-retention inference), and any **custom
|
|
34
35
|
OpenAI-compatible endpoint** (LM Studio, vLLM, llama.cpp…) are interchangeable at
|
|
35
36
|
`/model` time, including mid-session. No model lock-in, no separate code paths. MCP
|
|
36
|
-
servers, sub-agents, scheduled routines,
|
|
37
|
-
included — and every one of the agent's actions runs
|
|
38
|
-
permission gate**.
|
|
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
|
|
39
|
+
through a **safe-by-default permission gate**.
|
|
40
|
+
|
|
41
|
+
Privateer runs in three places, over one account and one config: the **terminal**, a
|
|
42
|
+
**background daemon** for unattended work, and the **Privateer app** on
|
|
43
|
+
[phone, web](https://privateer.pro), and [desktop](#the-privateer-app).
|
|
39
44
|
|
|
40
45
|
## Why Privateer?
|
|
41
46
|
|
|
@@ -95,12 +100,21 @@ silently. The moat is swappable; the floor under it holds.
|
|
|
95
100
|
- **Honest privacy posture, graded.** A verified TEE and a "we promise not to retain"
|
|
96
101
|
policy are **never rendered the same** — the badge tells you exactly how strong the
|
|
97
102
|
guarantee is (cryptographically verified → observable → policy → none).
|
|
98
|
-
- **
|
|
99
|
-
|
|
100
|
-
stays on your machine
|
|
103
|
+
- **Drive it from your phone.** Link the terminal with `/remote-access` (off by default) and
|
|
104
|
+
the Privateer app can send prompts, stream output, and Allow/Deny every action — while
|
|
105
|
+
execution stays on your machine. Sub-agent actions surface for approval the same way.
|
|
106
|
+
- **Manage it from the app.** Extensions, skills, routines, workflows, MCP connectors, and
|
|
107
|
+
chat-app channels are all configurable from your phone or the web app, against any linked
|
|
108
|
+
terminal. See [The Privateer app](#the-privateer-app).
|
|
109
|
+
- **A desktop app.** The same agent hosted inside a local Electron shell — no relay hop, works
|
|
110
|
+
offline, multi-window with per-window MCP connectors. Shares your CLI login and config.
|
|
101
111
|
- **Scheduled routines.** A background daemon runs approved tasks unattended — cron or
|
|
102
112
|
one-off — and the agent can schedule its own follow-up work. Results deliver to a file,
|
|
103
113
|
the next session, your phone, email, or a webhook.
|
|
114
|
+
- **Declarative workflows.** Multi-step agent pipelines as YAML — typed steps, conditional
|
|
115
|
+
routing between them, and `human_gate` steps that pause for your approval and resume.
|
|
116
|
+
- **Chat-app channels.** Bridge the agent into Telegram, Slack, Discord, or WhatsApp with
|
|
117
|
+
role-based approval — admins can approve actions, members are read-only.
|
|
104
118
|
- **MCP servers, sub-agents & skills.** Connect Model Context Protocol servers (local stdio
|
|
105
119
|
or remote HTTP with OAuth), delegate work to bounded parallel sub-agents, and drop in
|
|
106
120
|
skills — all gated like everything else.
|
|
@@ -124,14 +138,27 @@ No install at all: `npx privateer-agent`.
|
|
|
124
138
|
## Install
|
|
125
139
|
|
|
126
140
|
```bash
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
141
|
+
# the one-liner installer — downloads a self-contained bundle, no Node needed:
|
|
142
|
+
curl -fsSL https://privateer.pro/install.sh | sh # macOS / Linux
|
|
143
|
+
irm https://privateer.pro/install.ps1 | iex # Windows (PowerShell)
|
|
144
|
+
|
|
145
|
+
# or via npm, if you'd rather manage it yourself (needs Node ≥ 22.19):
|
|
146
|
+
npm install -g privateer-agent
|
|
147
|
+
npx privateer-agent # run without installing
|
|
132
148
|
```
|
|
133
149
|
|
|
134
|
-
**Requirements:** macOS
|
|
150
|
+
**Requirements:** macOS (arm64/x64), Linux (x64), or Windows (x64). The installers ship a
|
|
151
|
+
**pinned Node runtime inside the bundle**, so you don't need Node or npm on your machine at
|
|
152
|
+
all — Node ≥ 22.19.0 is only required for the `npm` / `npx` path.
|
|
153
|
+
|
|
154
|
+
Update in place with **`privateer update`** (bundle-aware: it re-runs the right installer
|
|
155
|
+
for how you installed) or check your version with `privateer --version`.
|
|
156
|
+
|
|
157
|
+
> **Windows:** the agent's command tool needs a bash, which Windows doesn't ship. Install
|
|
158
|
+
> Git for Windows (or WSL) and Privateer will find it; the launcher checks at startup and
|
|
159
|
+
> tells you how to fix it if not. Override the choice with `shellPath` in
|
|
160
|
+
> `~/.privateer/agent/settings.json`. Linux arm64 and Windows arm64 bundles aren't built
|
|
161
|
+
> yet — arm64 Windows runs the x64 bundle under emulation.
|
|
135
162
|
|
|
136
163
|
### Verifying what you're about to run
|
|
137
164
|
|
|
@@ -248,13 +275,106 @@ with `/signout`; manage linked terminals from the app.
|
|
|
248
275
|
> to spend on your account. If someone sends you a code and asks you to approve it, don't —
|
|
249
276
|
> that hands *them* a billed session on *your* account.
|
|
250
277
|
|
|
251
|
-
##
|
|
278
|
+
## The Privateer app
|
|
279
|
+
|
|
280
|
+
The same account drives Privateer from **iOS, Android, [the web app](https://privateer.pro),
|
|
281
|
+
and a desktop app**. The terminal stays where the work happens — the app is a remote control
|
|
282
|
+
and a management surface for it.
|
|
283
|
+
|
|
284
|
+
### Linking a terminal
|
|
285
|
+
|
|
286
|
+
1. Run **`privateer`** and **`/signin`**. It prints a short device code.
|
|
287
|
+
2. Open the app → **Link a terminal**, enter the code (or tap the deep link). No password or
|
|
288
|
+
wallet key ever touches the terminal, and the app pins the terminal's public key on first
|
|
289
|
+
link.
|
|
290
|
+
3. In the terminal, turn on **`/remote-access`** (off by default). The terminal now shows
|
|
291
|
+
**Online** in the app.
|
|
292
|
+
|
|
293
|
+
> **Only approve a code you generated yourself.** Approving someone else's code hands *them*
|
|
294
|
+
> a billed session on *your* account.
|
|
295
|
+
|
|
296
|
+
### What you can do from the app
|
|
297
|
+
|
|
298
|
+
| | |
|
|
299
|
+
|---|---|
|
|
300
|
+
| **Drive a session** | Send prompts, watch streamed output, and **Allow/Deny** each proposed action — including actions from sub-agents the session spawned |
|
|
301
|
+
| **Spawn an agent** | Start a one-shot task on the daemon: *background* (headless, read-only toolset, result sealed to your outbox) or *live* (a fresh drivable session) |
|
|
302
|
+
| **Routines** | Create, edit, pause, run, and delete scheduled unattended tasks |
|
|
303
|
+
| **Workflows** | List, run, and monitor multi-step workflows; answer `human_gate` steps to resume a paused run |
|
|
304
|
+
| **MCP connectors** | Add, edit, and enable MCP servers; credentials are sealed to the terminal and write-only |
|
|
305
|
+
| **Channels** | Configure the Telegram / Slack / Discord / WhatsApp bridges — admins, members, posture, tool ceiling, model |
|
|
306
|
+
| **Extensions & skills** | Install Pi extensions from the catalog; create, edit, and run `SKILL.md` skills |
|
|
307
|
+
|
|
308
|
+
Config changes that carry secrets or executable content (MCP credentials, channel bot
|
|
309
|
+
tokens, workflows with `script` steps) are **sealed to the terminal's pinned key and signed
|
|
310
|
+
by your account** — the relay forwards them blind and can neither read nor forge them.
|
|
311
|
+
|
|
312
|
+
The relay itself is live-only (nothing is archived), carries no API keys, and output is
|
|
313
|
+
size-truncated and run through a best-effort secret redactor before it leaves your machine.
|
|
314
|
+
|
|
315
|
+
### Desktop app
|
|
316
|
+
|
|
317
|
+
The desktop app hosts the agent **in-process** and talks to it over loopback IPC — no relay,
|
|
318
|
+
no network hop, and it works offline. It reads the same `~/.privateer` home, so it shares
|
|
319
|
+
your CLI login, model config, and MCP catalog. Multi-window, with a per-window subset of
|
|
320
|
+
your MCP connectors and a native folder picker.
|
|
321
|
+
|
|
322
|
+
Download for [macOS](https://privateer.pro/download/mac) (Apple silicon),
|
|
323
|
+
[macOS Intel](https://privateer.pro/download/mac-intel), or
|
|
324
|
+
[Windows](https://privateer.pro/download/windows).
|
|
325
|
+
|
|
326
|
+
It's an early release and **not yet code-signed or notarized** — macOS will warn on first
|
|
327
|
+
open. Routines and channels deliberately aren't hosted here: those belong to the always-on
|
|
328
|
+
daemon, so background work still wants `privateer daemon install`.
|
|
252
329
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
330
|
+
## Run it unattended — the daemon
|
|
331
|
+
|
|
332
|
+
A resident background daemon runs scheduled routines, executes workflows, and accepts task
|
|
333
|
+
spawns from the app — with no terminal open.
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
privateer daemon install # install as a login service (auto-starts, reachable from the app)
|
|
337
|
+
privateer daemon status # service installed? daemon answering?
|
|
338
|
+
privateer daemon run # or just run it in the foreground
|
|
339
|
+
privateer daemon uninstall
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Installs as a **launchd user agent** on macOS or a **`systemd --user` unit** on Linux — no
|
|
343
|
+
root, no sudo. (There's no Windows service path yet; use `privateer daemon run`.)
|
|
344
|
+
|
|
345
|
+
Everything the daemon does still runs through the permission gate. Actions needing approval
|
|
346
|
+
surface in the app; routines you approved once run on their own schedule.
|
|
347
|
+
|
|
348
|
+
## Workflows
|
|
349
|
+
|
|
350
|
+
A workflow is a **YAML file describing a multi-step agent pipeline** — a flat graph of typed
|
|
351
|
+
steps (`agent`, `script`, `human_gate`) with conditional routes between them and `{{ }}`
|
|
352
|
+
templating to pass values along. A `human_gate` step pauses the run for your approval and
|
|
353
|
+
resumes when you answer it, including from your phone.
|
|
354
|
+
|
|
355
|
+
The engine ships in the standalone
|
|
356
|
+
[`privateer-workflow`](https://www.npmjs.com/package/privateer-workflow) package. Today the
|
|
357
|
+
user-facing surface is the **app** (save, run, monitor, share) and the **daemon** that
|
|
358
|
+
executes them — there's no `/workflow` command in the terminal yet. Schedule one by pointing
|
|
359
|
+
a routine at it.
|
|
360
|
+
|
|
361
|
+
Because a workflow can carry `script` steps, saving one from the app requires your **account
|
|
362
|
+
signature** — the server can't inject a workflow onto your daemon.
|
|
363
|
+
|
|
364
|
+
## Chat-app channels
|
|
365
|
+
|
|
366
|
+
Bridge the agent into **Telegram, Slack, Discord, or WhatsApp** so you can hand it work from
|
|
367
|
+
a group chat. Each channel has:
|
|
368
|
+
|
|
369
|
+
- **Roles** — `admins` can approve actions; `members` are always read-only, no exceptions.
|
|
370
|
+
- **A posture** — `readonly`, `approve` (default), or `auto`.
|
|
371
|
+
- **A hard tool ceiling** — a per-channel allowlist the agent can't exceed even in `auto`.
|
|
372
|
+
|
|
373
|
+
Configure a channel from the app, or by hand in the `channels` block of
|
|
374
|
+
`~/.privateer/config.json`. Changes take effect on restart, by design. Bot tokens set from
|
|
375
|
+
the app are write-only — the app can name them but never read them back. Note that tokens
|
|
376
|
+
live in plaintext in `config.json` on your machine, and every channel action is appended to
|
|
377
|
+
`~/.privateer/channels-audit.log`.
|
|
258
378
|
|
|
259
379
|
## Permission modes
|
|
260
380
|
|
|
@@ -289,14 +409,35 @@ Everything below is a **Pi extension** loaded by discovery (see [Built on Pi](#b
|
|
|
289
409
|
drop your own into `~/.privateer/agent/extensions/` and it loads the same way, gated like the rest.
|
|
290
410
|
|
|
291
411
|
- **MCP servers** (`pi-mcp-adapter`) — declare them and their tools become first-class, gated
|
|
292
|
-
like the rest (local stdio, or remote HTTP with interactive OAuth).
|
|
293
|
-
-
|
|
294
|
-
|
|
412
|
+
like the rest (local stdio, or remote HTTP with interactive OAuth). One catalog at
|
|
413
|
+
`~/.privateer/agent/mcp-desktop.json` is shared by the CLI, the daemon, and the desktop
|
|
414
|
+
app, so a machine has one coherent connector config.
|
|
415
|
+
- **Sub-agents** (`pi-subagents`) — delegate investigations to bounded parallel agents. Children
|
|
416
|
+
run as headless child processes that **inherit the moat**, so their actions hit the same
|
|
417
|
+
permission gate and their approvals surface on your phone.
|
|
295
418
|
- **Routines** — saved tasks the daemon runs unattended; ask the agent to schedule work and
|
|
296
419
|
approve it once.
|
|
420
|
+
- **Workflows** — declarative multi-step pipelines the daemon executes; see
|
|
421
|
+
[Workflows](#workflows).
|
|
297
422
|
- **Web tools** (`rpiv-web-tools`) — private-by-default web search/fetch with pluggable backends
|
|
298
423
|
(self-hosted SearXNG for fully private search).
|
|
299
424
|
|
|
425
|
+
## Command reference
|
|
426
|
+
|
|
427
|
+
| Command | What it does |
|
|
428
|
+
|---|---|
|
|
429
|
+
| `/model` · `/models` | switch model; `/models` is a searchable picker with TEE/ZDR privacy shields |
|
|
430
|
+
| `/mode` | switch permission mode |
|
|
431
|
+
| `/verify` | fetch and check the TEE attestation for the current model |
|
|
432
|
+
| `/signin` · `/signout` | sign in to a Privateer account (device flow) / sign out |
|
|
433
|
+
| `/remote-access` | link this terminal to the app and allow it to drive (off by default) |
|
|
434
|
+
| `/extensions` | list loaded Pi extensions |
|
|
435
|
+
| `/init` | scaffold a starter `PRIVATEER.md` in this directory |
|
|
436
|
+
| `/update` · `/privateer` | update to the latest release / Privateer status and posture |
|
|
437
|
+
|
|
438
|
+
Shell subcommands: `privateer` (interactive), `privateer update`, `privateer daemon …`,
|
|
439
|
+
`privateer --no-quarter`, `privateer --version`.
|
|
440
|
+
|
|
300
441
|
## Develop
|
|
301
442
|
|
|
302
443
|
```bash
|
package/SECURITY.md
CHANGED
|
@@ -30,7 +30,11 @@ npm audit signatures # verifies registry signatures + p
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
If a version lacks provenance, it did not come from this workflow. Treat that as
|
|
33
|
-
suspicious and report it.
|
|
33
|
+
suspicious and report it — with one documented exception: **0.6.7 is the first release
|
|
34
|
+
published this way.** Trusted publishing was misconfigured until then, so every earlier
|
|
35
|
+
version (through 0.6.6) was published by hand from a maintainer's machine and carries no
|
|
36
|
+
attestation. Those are not forgeries, but they are not independently verifiable either.
|
|
37
|
+
If that distinction matters to you, use 0.6.7 or later.
|
|
34
38
|
|
|
35
39
|
## The permission gate
|
|
36
40
|
|
package/bin/privateer-launch.mjs
CHANGED
|
@@ -214,28 +214,39 @@ else {
|
|
|
214
214
|
// auto-install. Fire-and-forget: the event loop stays alive while the TUI child runs.
|
|
215
215
|
refreshUpdateCache();
|
|
216
216
|
|
|
217
|
-
// Default model.
|
|
218
|
-
//
|
|
219
|
-
//
|
|
217
|
+
// Default model. Mirrors src/providers/defaultModel.ts resolveDefaultModel() — keep
|
|
218
|
+
// the two in step. Tinfoil's GLM 5.2 is the default either way: direct when the user
|
|
219
|
+
// has a Tinfoil key (pi-privacy can client-attest the enclave), over the Privateer
|
|
220
|
+
// subscription otherwise.
|
|
221
|
+
//
|
|
222
|
+
// The last branch is the important one. A signed-out, keyless terminal used to launch
|
|
223
|
+
// on `openrouter/openai/gpt-4o-mini`, which it had no key for — so the first prompt
|
|
224
|
+
// died on "No API key found for openrouter", /login couldn't fix it (nothing switched
|
|
225
|
+
// the live model), and the error named a provider the user had never heard of. It now
|
|
226
|
+
// launches on the SAME account model it will use once signed in: nothing to switch,
|
|
227
|
+
// the status bar shows what they're about to get, and the error until then names
|
|
228
|
+
// Privateer and points at /login.
|
|
220
229
|
const CRED = path.join(PRIVATEER_HOME, "credentials.json");
|
|
221
230
|
const signedIn = fs.existsSync(CRED);
|
|
231
|
+
const ACCOUNT_MODEL = "privateer/tinfoil/glm-5-2";
|
|
222
232
|
const MODEL = process.env.PRIVATEER_MODEL
|
|
223
233
|
? process.env.PRIVATEER_MODEL
|
|
224
234
|
: haveTinfoilKey()
|
|
225
235
|
? "tinfoil/glm-5-2"
|
|
226
236
|
: signedIn
|
|
227
|
-
?
|
|
228
|
-
: "
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
|
|
237
|
+
? ACCOUNT_MODEL
|
|
238
|
+
: haveKey("ANTHROPIC_API_KEY")
|
|
239
|
+
? "anthropic/claude-opus-4-8"
|
|
240
|
+
: haveKey("OPENAI_API_KEY")
|
|
241
|
+
? "openai/gpt-5.5"
|
|
242
|
+
: haveKey("OPENROUTER_API_KEY")
|
|
243
|
+
? "openrouter/openai/gpt-4o-mini"
|
|
244
|
+
: ACCOUNT_MODEL;
|
|
245
|
+
|
|
246
|
+
// Nothing to run with: no model named, no BYO key, not signed in. The TUI still boots
|
|
247
|
+
// (that's where /login lives), but say why up front — a returning user whose login
|
|
248
|
+
// file vanished otherwise has no way to tell a cleared session from a first run.
|
|
249
|
+
if (!signedIn && !process.env.PRIVATEER_MODEL && !haveByoKey()) {
|
|
239
250
|
warnKeylessLaunch();
|
|
240
251
|
}
|
|
241
252
|
|
|
@@ -367,20 +378,17 @@ function warnKeylessLaunch() {
|
|
|
367
378
|
? [
|
|
368
379
|
"",
|
|
369
380
|
" ⚓ Your Privateer login is missing — this terminal isn't signed in.",
|
|
370
|
-
` (no ${path.join(PRIVATEER_HOME, "credentials.json")})`,
|
|
371
381
|
"",
|
|
372
|
-
"
|
|
373
|
-
"
|
|
374
|
-
" prompting fails with \"No API key found\" because no model key is set.",
|
|
382
|
+
" Run /login and approve the code in the Privateer app. You'll be back on your",
|
|
383
|
+
" subscription models straight away — no API key needed.",
|
|
375
384
|
"",
|
|
376
385
|
]
|
|
377
386
|
: [
|
|
378
387
|
"",
|
|
379
|
-
" ⚓
|
|
388
|
+
" ⚓ Welcome aboard. Run /login to connect your Privateer account.",
|
|
380
389
|
"",
|
|
381
|
-
"
|
|
382
|
-
"
|
|
383
|
-
" prompting fails with \"No API key found\".",
|
|
390
|
+
" One approval in the Privateer app and you're running Tinfoil GLM 5.2 in a",
|
|
391
|
+
" trusted enclave — no API key needed. Prefer your own key? /login keys.",
|
|
384
392
|
"",
|
|
385
393
|
];
|
|
386
394
|
process.stderr.write(lines.join("\n") + "\n");
|