@connortessaro/pai 0.4.2 → 0.5.0

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
@@ -15,9 +15,9 @@
15
15
 
16
16
  <p align="center">
17
17
  <a href="https://github.com/connortessaro/pai/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/connortessaro/pai/ci.yml?branch=main&label=CI&color=161b22&labelColor=0d1117" alt="CI"></a>&nbsp;
18
- <a href="package.json"><img src="https://img.shields.io/badge/version-0.3.0-161b22?labelColor=0d1117" alt="Version 0.3.0"></a>&nbsp;
18
+ <a href="https://www.npmjs.com/package/@connortessaro/pai"><img src="https://img.shields.io/npm/v/@connortessaro/pai?label=version&color=161b22&labelColor=0d1117" alt="npm version"></a>&nbsp;
19
19
  <a href="package.json"><img src="https://img.shields.io/badge/node-%3E%3D24-161b22?labelColor=0d1117" alt="Node >= 24"></a>&nbsp;
20
- <a href="docs/reference.md#mcp-tools"><img src="https://img.shields.io/badge/MCP-16_tools-161b22?labelColor=0d1117" alt="MCP Compatible"></a>&nbsp;
20
+ <a href="docs/reference.md#mcp-tools"><img src="https://img.shields.io/badge/MCP-server-161b22?labelColor=0d1117" alt="MCP Compatible"></a>&nbsp;
21
21
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-161b22?labelColor=0d1117" alt="MIT License"></a>
22
22
  </p>
23
23
 
@@ -28,25 +28,29 @@
28
28
  <a href="#features">Features</a> •
29
29
  <a href="#commands">Commands</a> •
30
30
  <a href="#use-with-an-mcp-client">MCP Server</a> •
31
- <a href="docs/reference.md">API Reference</a>
31
+ <a href="https://connortessaro.github.io/pai/">Docs</a>
32
32
  </p>
33
33
 
34
34
  ---
35
35
 
36
36
  `pai` runs on your machine and manages a [Phantom AI](https://phantom.codes) key.
37
- Your agent can hand each subagent a child key with its own spending limit, lifetime, and rate cap.
38
- It also sets plans and model routing, pays for credit from an agent wallet, and checks which model answered a call.
37
+ Your agent can give each subagent a child key with its own spending limit, lifetime, and rate cap.
38
+ `pai` also sets plans and model routing, buys credit from an agent wallet, and checks which model answered a call.
39
39
 
40
- `pi`, `Claude Code`, `Codex`, and `Cursor` drive it through a skill, and any MCP client can use `pai mcp`.
40
+ `pi`, `Claude Code`, `Codex`, and `Cursor` drive it through a skill. Any MCP client can use `pai mcp`.
41
41
 
42
42
  The CLI is MIT licensed. The Phantom AI API it calls is a hosted service.
43
43
 
44
+ **Docs:** [connortessaro.github.io/pai](https://connortessaro.github.io/pai/) has guides to how
45
+ keys, payments, caps and the local tools behave, the full interface reference (commands,
46
+ flags, MCP tools, HTTP calls, environment variables), and the code reference.
47
+
44
48
  ## How It Works
45
49
 
46
50
  ```text
47
51
  ┌────────────────────────┐
48
52
  │ Main Phantom Key │
49
- │ (prepaid, no id) │
53
+ │ (prepaid, no account) │
50
54
  └───────────┬────────────┘
51
55
  │
52
56
  ┌───────────────────────┼───────────────────────┐
@@ -62,18 +66,18 @@ The CLI is MIT licensed. The Phantom AI API it calls is a hosted service.
62
66
  └───────────┬───────────┘
63
67
  ▼
64
68
  ┌───────────────────────┐
65
- │ Phantom AI Gateway │ ──> https://phantom.codes/v1
66
- │ (zero prompt logs) │ ──> Ed25519 signed receipts
69
+ │ Phantom AI API │ ──> https://phantom.codes/v1
70
+ │ (stores no prompts) │ ──> signed receipt per call
67
71
  └───────────────────────┘
68
72
  ```
69
73
 
70
74
  ## Features
71
75
 
72
- - **Scoped Subagent Keys** — Create child keys that spend the parent's balance up to a limit, with lifetimes and rate caps (`pai child`). Revoke one with `pai burn`.
73
- - **Autonomous Agent Wallet** — Local Solana keypairs allow running agents to self-fund inference on chain. Capped by environment-only limits (`PHANTOM_WALLET_MAX_USD`).
74
- - **Multi-Agent Skill & MCP** — Native skill installation for `pi`, `Claude Code`, `Codex`, and `Cursor`, plus a 16-tool Model Context Protocol (MCP) server over stdio.
75
- - **Cryptographic Receipts** — Upstream responses return an Ed25519 signature verifying the model served, actual token counts, and cost (`pai verify`).
76
- - **Local Tooling Suite** — Private local markdown memory notebooks, throwaway Docker sandboxes, and safe IMAP/SMTP mail drafting.
76
+ - **Child keys.** `pai child` creates a key that spends the parent's balance up to a limit, with a lifetime and a per-minute cap. `pai burn` revokes one.
77
+ - **Agent wallet.** `pai wallet` keeps Solana wallets on this machine, so an agent can buy its own credit. `PHANTOM_WALLET_MAX_USD` caps each payment, and only the environment can set it.
78
+ - **Skill and MCP server.** `pai setup` installs a skill for `pi`, `Claude Code`, `Codex`, and `Cursor`. `pai mcp` runs an MCP server over stdio.
79
+ - **Signed receipts.** Phantom AI signs each paid response with the model that answered, the token counts, and the cost. `pai verify` checks that signature.
80
+ - **Local tools.** Markdown notes, throwaway Docker containers, and a mail client that drafts by default. None of them send data to Phantom AI.
77
81
 
78
82
  ## Install
79
83
 
@@ -88,32 +92,32 @@ The package also installs the same CLI as `phantom-key`, its earlier name.
88
92
  ## Quickstart
89
93
 
90
94
  ```bash
91
- # 1. Login once and install the skill for your installed agents
92
- pai login # paste your key once; pai saves it with mode 600
93
- pai setup # configures pi, Claude Code, Codex, and Cursor
95
+ # 1. Save your key once, and install the skill for the agents you have
96
+ pai login # paste your key; pai saves it (see Saved secrets below)
97
+ pai setup # sets up pi, Claude Code, Codex, and Cursor, where found
94
98
 
95
- # 2. Check balance and active caps
99
+ # 2. Check the balance and any caps
96
100
  pai balance
97
101
 
98
- # 3. Mint a child key for an autonomous subagent
102
+ # 3. Create a child key for a subagent: $0.50, 6 hours, $0.10 a minute
99
103
  pai child --limit 0.50 --ttl 6 --rate 0.10 --save researcher
100
104
 
101
- # 4. Run the subagent as the scoped child
105
+ # 4. Start the subagent as that child
102
106
  PHANTOM_KEY_NAME=researcher claude
103
107
  ```
104
108
 
105
109
  ## Use It From an Agent
106
110
 
107
111
  `pai setup` installs the `phantom-ai` skill for each agent it finds in your
108
- home directory (`pi`, `Claude Code`, `Codex`, `Cursor`). You can then prompt your agent in
109
- plain words, for example:
112
+ home folder (`pi`, `Claude Code`, `Codex`, `Cursor`). Then you can ask your
113
+ agent in plain words, for example:
110
114
 
111
115
  > *"Give a subagent $0.50 for 6 hours with a $0.10/min rate cap."*
112
116
 
113
117
  - `--agent pi` (or `claude`, `codex`, `cursor`) sets up one agent.
114
- - `--mcp` also registers the MCP server with Claude Code, Codex, and Cursor.
115
- - `--agent claude --provider` runs Claude Code's own model calls on Phantom AI: it sets `ANTHROPIC_BASE_URL`, turns on tool search, and gives Claude Code the key through `apiKeyHelper` (`pai key show`), so the key never lands in `settings.json`. Add `--model auto` or any model id; `--provider off` undoes it.
116
- - `pi` has no MCP and uses the CLI through the skill; install there with:
118
+ - `--mcp` also adds the MCP server to Claude Code, Codex, and Cursor.
119
+ - `--agent claude --provider` sends Claude Code's own model calls to Phantom AI. It sets `ANTHROPIC_BASE_URL`, turns on tool search, and gives Claude Code the key through `apiKeyHelper` (`pai key show`), so the key stays out of `settings.json`. Add `--model auto` or any model id. `--provider off` undoes it.
120
+ - `pi` has no MCP support and uses the CLI through the skill. Install it there with:
117
121
  ```bash
118
122
  pi install npm:@connortessaro/pai
119
123
  ```
@@ -121,16 +125,17 @@ plain words, for example:
121
125
  ## Commands
122
126
 
123
127
  `pai --help` prints every command and flag. [docs/reference.md](docs/reference.md)
124
- has the complete text, the MCP tools, and the environment variables, all generated
125
- from the code.
128
+ lists every command with the flags it reads, every MCP tool with its inputs, every
129
+ call `pai` makes to Phantom AI, and the environment variables. `npm run docs`
130
+ writes that file from the code.
126
131
 
127
132
  | Group | Commands | What they do |
128
133
  | --- | --- | --- |
129
134
  | **Setup** | `login`, `logout`, `setup` | Save your key, and install the skill for your agents |
130
135
  | **Keys** | `balance`, `child`, `children`, `key`, `rotate`, `burn` | Show credit, create child keys paid from this key, save keys by name, and replace or revoke a key |
131
- | **Caps and plans** | `budget`, `plan` | Set a monthly cap and a per-minute cap, or money for a period |
136
+ | **Caps and plans** | `budget`, `plan` | Set a monthly cap and a per-minute cap, or an amount for a set period |
132
137
  | **Routing** | `route` | Choose which models `model: "auto"` can run, and the rules that pick one |
133
- | **Credit** | `buy`, `payment` | Buy credit with crypto |
138
+ | **Credit** | `buy`, `payment` | Buy credit with USDC, USDT, or SOL on Solana |
134
139
  | **Agent wallet** | `wallet`, `autotopup`, `buy --pay` | Keep Solana wallets and pay for credit from them. See [Let the agent pay](#let-the-agent-pay) |
135
140
  | **Receipts** | `verify` | Check which model answered a call, from its signed receipt |
136
141
  | **Local tools** | `memory`, `mail`, `browser`, `sandbox` | See the sections below |
@@ -142,7 +147,7 @@ as `PHANTOM_API_KEY`, then as the `login` key. A subagent started with
142
147
 
143
148
  ## Memory
144
149
 
145
- Each agent gets a private notebook on this machine. Notes are markdown files in
150
+ Each agent gets its own notebook on this machine. Notes are markdown files in
146
151
  `~/.config/phantom-key/memory/<space>/`, so you can read, edit, or commit them.
147
152
  `pai` sends none of them anywhere.
148
153
 
@@ -158,18 +163,24 @@ key name (`PHANTOM_KEY_NAME`), then `main`, so each subagent keeps its own.
158
163
 
159
164
  ## Mail
160
165
 
161
- `pai` reads your own mailbox over IMAP and SMTP. It saves the login, with an app
162
- password, in `~/.config/phantom-key/mail.json` (mode 600). Gmail, Outlook,
163
- iCloud, and Fastmail addresses have presets; for any other provider, pass
164
- `--imap host:port --smtp host:port`.
166
+ `pai` reads your own mailbox over IMAP and sends over SMTP, with an app
167
+ password. It saves the login as described in [Saved secrets](#saved-secrets).
168
+ Gmail, Outlook, iCloud, and Fastmail addresses have presets. For any other
169
+ provider, pass `--imap host:port --smtp host:port`.
165
170
 
166
171
  | Command | What it does |
167
172
  | --- | --- |
168
- | `mail setup --user you@gmail.com` | Checks the login by listing one message, then saves it. A wrong password is not saved. The password comes from a prompt or `PAI_MAIL_PASSWORD` |
173
+ | `mail setup --user you@gmail.com` | Checks the login by listing one message, then saves it. `pai` does not save a wrong password. The password comes from a prompt or `PAI_MAIL_PASSWORD` |
169
174
  | `mail status` | Shows the mailbox and whether sending is on |
170
175
  | `mail list [--unread] [--from x] [--limit n] [--folder f]` / `mail search <words>` / `mail read <uid>` | Reads mail from `INBOX` by default. `list` returns 20 messages by default. `read` cuts a message at 20,000 characters |
171
- | `mail draft --to a --subject s [--reply <uid>] [--body "..."]` | Saves a draft in your Drafts folder and sends nothing. Without `--body`, pai reads the body from stdin |
172
- | `mail send` (same flags) | Sends only when `PAI_MAIL_SEND=1`, to at most `PAI_MAIL_MAX_PER_DAY` recipients (default 10) in 24 hours, and only to `PAI_MAIL_SEND_TO` (addresses or `@domain`s) when set. pai reads all three from the environment, so an agent can't turn sending on with a flag. With sending on, the `create_child_key` tool requires `save_as`, so a new key never lands in the agent's context. SMTP on 587 and IMAP on 143 require STARTTLS |
176
+ | `mail draft --to a --subject s [--reply <uid>] [--body "..."]` | Saves a draft in your Drafts folder and sends nothing. Without `--body`, `pai` reads the body from stdin |
177
+ | `mail send` (same flags) | Sends only when `PAI_MAIL_SEND=1`, to at most `PAI_MAIL_MAX_PER_DAY` recipients (default 10) in 24 hours, and only to `PAI_MAIL_SEND_TO` (addresses or `@domain`s) when set |
178
+
179
+ `pai` reads the three `mail send` settings from the environment only, so an
180
+ agent can't turn sending on with a flag. While sending is on, the
181
+ `create_child_key` MCP tool requires `save_as`, which keeps a new key out of the
182
+ agent's context. On any port other than 993 or 465, `pai` requires STARTTLS
183
+ (switching the connection to encrypted) before it sends the password.
173
184
 
174
185
  ## Browser and Sandbox
175
186
 
@@ -184,9 +195,9 @@ iCloud, and Fastmail addresses have presets; for any other provider, pass
184
195
 
185
196
  ## Output Format
186
197
 
187
- Commands print JSON on stdout, so you can pipe into `jq`. `--table` prints
188
- a formatted table for human inspection. `browser` and `sandbox run` pass through the exit code of the
189
- command they ran.
198
+ Commands print JSON on stdout, so you can pipe them into `jq`. `--table` prints
199
+ a table for people to read. `browser` and `sandbox run` pass through the exit
200
+ code of the command they ran.
190
201
 
191
202
  | Exit code | Meaning |
192
203
  | --- | --- |
@@ -209,39 +220,47 @@ command they ran.
209
220
  }
210
221
  ```
211
222
 
212
- [docs/reference.md](docs/reference.md#mcp-tools) lists every tool with its
213
- inputs and whether it is read-only or destructive.
223
+ [docs/reference.md](docs/reference.md#mcp-tools) lists each tool with its
224
+ inputs, and marks the read-only and destructive ones.
214
225
 
215
- `delete_key` authenticates as the key you pass in `api_key` or `key_name` and
226
+ `delete_key` signs in as the key you pass in `api_key` or `key_name` and
216
227
  deletes that key. It refuses the key the server runs as; use `pai burn` for
217
228
  that.
218
229
 
219
230
  ## Let the Agent Pay
220
231
 
221
- The agent can maintain its own Solana wallets and buy credit with them. Each wallet
222
- is a Solana keypair in `~/.config/phantom-key/wallets/` (mode 600). The wallet
223
- pays Phantom AI's Solana address, and Phantom AI finds the payment on chain.
232
+ The agent can keep its own Solana wallets and buy credit with them. Each wallet
233
+ is a Solana keypair, saved as described in [Saved secrets](#saved-secrets).
234
+ The wallet pays Phantom AI's Solana address, and Phantom AI finds the payment
235
+ on chain.
224
236
 
225
- 1. **Create a wallet**, and back up its file:
237
+ 1. **Create a wallet**, and back up its secret key:
226
238
  ```bash
227
239
  pai wallet create --table # saved as "main"
228
240
  pai wallet create --name work --table # a second one
229
241
  ```
230
- 2. **Fund the address** with USDC on Solana, plus some SOL for fees (at least 0.003 SOL).
242
+ On macOS the file in `~/.config/phantom-key/wallets/` only points to the
243
+ Keychain, so copying it backs up nothing. Export the key itself:
244
+ ```bash
245
+ security find-generic-password -s pai -w \
246
+ -a "$(cut -d: -f2 ~/.config/phantom-key/wallets/main.json)" | base64 -d > main-backup.json
247
+ ```
248
+ With `PAI_KEYCHAIN=0`, or on other systems, `wallets/main.json` holds the key, and a copy of it is the backup.
249
+ 2. **Fund the address** with USDC on Solana, plus about 0.003 SOL for fees.
231
250
  3. **Set the safety cap**:
232
251
  ```bash
233
252
  export PHANTOM_WALLET_MAX_USD=10
234
253
  ```
235
- Without this variable, `pai` refuses to pay. The total over 24 hours is
236
- capped by `PHANTOM_WALLET_MAX_USD_PER_DAY`, which defaults to the same
237
- amount: one payment a day. Raise it for `autotopup`.
254
+ Without this variable, `pai` refuses to pay. `PHANTOM_WALLET_MAX_USD_PER_DAY`
255
+ caps the total over 24 hours and defaults to the same amount, which allows
256
+ one payment a day. Raise it for `autotopup`.
238
257
  4. **Pay**:
239
258
  ```bash
240
259
  pai buy --amount 5 --pay
241
260
  ```
242
261
  With more than one wallet saved, `pai` asks in a terminal which one pays. It
243
262
  then reports each step:
244
- 1. Getting a payment request from Phantom AI (amount, recipient, and unique reference)
263
+ 1. Getting a payment request from Phantom AI (amount, recipient, and a unique reference)
245
264
  2. Sending USDC or SOL from your wallet
246
265
  3. Confirming on Solana
247
266
  4. Phantom AI finding the payment on chain by its reference
@@ -249,10 +268,10 @@ pays Phantom AI's Solana address, and Phantom AI finds the payment on chain.
249
268
 
250
269
  A payment request expires after 30 minutes.
251
270
 
252
- You can also prompt your agent: *"Top up my Phantom AI key with $5 from my Phantom agent wallet."*
253
- Over MCP it calls `list_wallets`, asks which wallet if not specified, then calls `pay_for_credit`.
271
+ You can also ask your agent: *"Top up my Phantom AI key with $5 from my Phantom agent wallet."*
272
+ Over MCP it calls `list_wallets`, asks which wallet if you didn't say, then calls `pay_for_credit`.
254
273
 
255
- To refill automatically when the balance runs low:
274
+ To refill when the balance runs low:
256
275
 
257
276
  ```bash
258
277
  pai autotopup --below 1 --amount 5 --wallet main --every 10
@@ -261,35 +280,55 @@ pai autotopup --below 1 --amount 5 --wallet main --every 10
261
280
  ### Safeguards
262
281
 
263
282
  - `pai` pays the recipient and exact amount the payment request names, with that request's reference attached.
264
- - `pai` reads `PHANTOM_WALLET_MAX_USD` and `PHANTOM_WALLET_MAX_USD_PER_DAY` strictly from the environment; no flag or tool argument can raise them.
283
+ - `pai` reads `PHANTOM_WALLET_MAX_USD` and `PHANTOM_WALLET_MAX_USD_PER_DAY` from the environment only; no flag or tool argument can raise them.
265
284
  - Before signing, `pai` checks the payment request against what it asked for: the coin, the USDC mint, and an amount no more than requested (for SOL, within 10% of Coinbase's price). A wrong or hostile `PHANTOM_BASE_URL` cannot make it sign more.
266
- - One payment runs at a time, across processes.
267
- - `pai` verifies the wallet balance before requesting a payment.
268
- - `pai` records payments in `~/.config/phantom-key` before sending, and keeps the record until Phantom AI reports the payment credited or dead. If a run crashes, times out or loses the connection, the next run waits for that payment instead of paying again.
269
- - These limits bind an agent that reaches pai through MCP. An agent with its own shell can set environment variables and edit the state folder, so give such an agent a wallet holding only what you are willing for it to spend.
270
- - Store wallet secrets in a local secrets manager (e.g. [KRU](https://github.com/omaekumiko2-create/kru)) and inject `PHANTOM_WALLET_KEY` at runtime.
285
+ - `pai` runs one payment at a time, across processes.
286
+ - `pai` checks the wallet balance before it asks for a payment request.
287
+ - `pai` records each payment in `~/.config/phantom-key` before sending, and keeps the record until Phantom AI reports the payment credited or dead. If a run crashes, times out, or loses the connection, the next run waits for that payment instead of paying again.
288
+ - These limits bind an agent that reaches `pai` through MCP. An agent with its own shell can set environment variables and edit the state folder, so give such an agent a wallet that holds only what you are willing to let it spend.
289
+ - To keep a wallet's secret out of `pai`'s state folder, pass it at run time in `PHANTOM_WALLET_KEY`, for example from a local secrets manager such as [KRU](https://github.com/omaekumiko2-create/kru).
290
+
291
+ ## Saved Secrets
292
+
293
+ `pai` keeps its files in `~/.config/phantom-key`, or in `PHANTOM_STATE_DIR` if
294
+ you set it. The paths in this README assume the default.
295
+
296
+ On macOS, `pai` puts saved keys, wallets, and the mail login in your login
297
+ Keychain. The file in the state folder then holds only a pointer to the
298
+ Keychain item. The Keychain keeps these secrets out of files, backups, and sync
299
+ folders. Any program running as you can still read them. If the Keychain is
300
+ locked, as it often is over SSH, run `security unlock-keychain`.
301
+
302
+ Set `PAI_KEYCHAIN=0` to save them to files instead. On other systems `pai`
303
+ uses files. Only your user can read them (mode 600).
271
304
 
272
305
  ## Configuration
273
306
 
274
307
  `pai` reads its settings from environment variables. Run `pai --help` or see
275
- [docs/reference.md#environment-variables](docs/reference.md#environment-variables) for the full list,
276
- including secrets, environment-only flags, and caps.
308
+ [docs/reference.md](docs/reference.md#environment-variables) for the full list,
309
+ including secrets, environment-only settings, and caps.
310
+
311
+ `PHANTOM_BASE_URL` must start with `https://`. `pai` sends your API key there,
312
+ so it refuses plain `http://`, even on localhost.
277
313
 
278
314
  ## Requirements
279
315
 
280
316
  - **Node 24** or newer
281
- - Runtime dependencies: `@modelcontextprotocol/sdk` and `zod` for `mcp`, `@solana/kit` for wallet payments, and `imapflow`, `mailparser`, `nodemailer` for `mail`.
317
+ - Runtime dependencies: `@modelcontextprotocol/sdk` and `zod` for `mcp`, `@solana/kit` for wallet payments, and `imapflow`, `mailparser`, and `nodemailer` for `mail`.
282
318
 
283
- Read [phantom.codes/docs/concepts](https://phantom.codes/docs/concepts) for key lifecycle and subagent hierarchy details.
319
+ [phantom.codes/docs/concepts](https://phantom.codes/docs/concepts) explains how keys and child keys work on the Phantom AI side.
284
320
 
285
321
  ## Development
286
322
 
287
323
  ```bash
288
324
  npm ci
289
- npm test # vitest
325
+ npm run build # compile src/ to dist/
290
326
  npm run typecheck
291
- npm run docs # regenerate docs/reference.md
292
- node src/pai.mts --help # run from source
327
+ npm test # vitest; never touches the real Keychain
328
+ npm run coverage # vitest with coverage; fails under 80%
329
+ npm run docs # rewrite docs/reference.md and build the docs site in docs/site (not committed)
330
+ node scripts/gen-docs.mjs --check # fail if docs/reference.md is out of date or the docs disagree with the code
331
+ node src/pai.mts --help # run from source
293
332
  ```
294
333
 
295
334
  ## Contributing
@@ -299,7 +338,7 @@ command or MCP tool. [CHANGELOG.md](CHANGELOG.md) lists changes by release.
299
338
 
300
339
  ## Security
301
340
 
302
- Report vulnerabilities privately through a
341
+ Report vulnerabilities through a private
303
342
  [GitHub security advisory](https://github.com/connortessaro/pai/security/advisories/new).
304
343
  See [SECURITY.md](SECURITY.md).
305
344