@persistmemory/cli 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PersistMemory
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,366 @@
1
+ # @persistmemory/cli
2
+
3
+ **`pm`** — capture and search your memory from a terminal.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@persistmemory/cli.svg)](https://www.npmjs.com/package/@persistmemory/cli)
6
+ [![node](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](https://nodejs.org)
7
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
8
+
9
+ Memory that persists across every model, tool and session you use — reachable from the one
10
+ place you already are.
11
+
12
+ - **Browser sign-in, OAuth 2.1 + PKCE** — your password is never typed into a terminal
13
+ - **One dependency-free binary** — the SDK is bundled in; a global install pulls down one thing
14
+ - **Scriptable** — `--output json|yaml|csv|tsv`, and JSON automatically when piped
15
+ - **Spaces** — keep work, personal and per-client memory apart
16
+ - **File requests** — approve, from your terminal, what an assistant is allowed to read
17
+ - **macOS, Linux, Windows** — the same `dist/bin.js` on all three
18
+
19
+ ---
20
+
21
+ ## Table of contents
22
+
23
+ 1. [Install](#install)
24
+ 2. [Sign in](#sign-in)
25
+ 3. [Get an API key (CI and headless)](#get-an-api-key-ci-and-headless)
26
+ 4. [First five minutes](#first-five-minutes)
27
+ 5. [Spaces](#spaces)
28
+ 6. [Commands](#commands)
29
+ 7. [Output formats and scripting](#output-formats-and-scripting)
30
+ 8. [Profiles](#profiles)
31
+ 9. [The agent, and file requests](#the-agent-and-file-requests)
32
+ 10. [Environment variables](#environment-variables)
33
+ 11. [Where your files live](#where-your-files-live)
34
+ 12. [Security](#security)
35
+ 13. [Troubleshooting](#troubleshooting)
36
+ 14. [Uninstall](#uninstall)
37
+
38
+ ---
39
+
40
+ ## Install
41
+
42
+ **macOS and Linux**
43
+ ```bash
44
+ curl -fsSL https://persistmemory.com/install.sh | sh
45
+ ```
46
+
47
+ **Windows (PowerShell)**
48
+ ```powershell
49
+ irm https://persistmemory.com/install.ps1 | iex
50
+ ```
51
+
52
+ **Any platform, with npm**
53
+ ```bash
54
+ npm install -g @persistmemory/cli
55
+
56
+ # or run it without installing anything
57
+ npx @persistmemory/cli auth login
58
+ ```
59
+
60
+ Node 20 or newer is the only requirement.
61
+
62
+ Piping a script into a shell is worth being careful about, so read ours first —
63
+ [install.sh](https://persistmemory.com/install.sh) and
64
+ [install.ps1](https://persistmemory.com/install.ps1). Both refuse to run rather than guessing
65
+ when they cannot find a supported platform or a recent enough Node, neither escalates to
66
+ `sudo` or Administrator on your behalf, and both tell you what to do instead when npm's global
67
+ directory is not yours to write to.
68
+
69
+ Two commands are installed: **`pm`** (what you will type) and **`persistmemory`** (the same
70
+ thing, for when `pm` collides with something else on your machine).
71
+
72
+ ---
73
+
74
+ ## Sign in
75
+
76
+ ```bash
77
+ pm auth login
78
+ ```
79
+
80
+ Your browser opens, you approve the scopes on a consent screen, and the terminal says who you
81
+ are. There is **no key to create and no password to paste** — that is the point.
82
+
83
+ ```bash
84
+ pm auth status # who am I, and does the server still accept it
85
+ pm auth logout # forget the stored credential
86
+ ```
87
+
88
+ If you have no account yet, sign up at <https://persistmemory.com/signup> first (Google works),
89
+ then run `pm auth login`.
90
+
91
+ ---
92
+
93
+ ## Get an API key (CI and headless)
94
+
95
+ A browser sign-in needs a browser. On a build agent or a server over SSH, use a key instead.
96
+
97
+ 1. Sign in at <https://persistmemory.com/signin>.
98
+ 2. Open **Settings** from the header, or go to <https://persistmemory.com/settings#keys>.
99
+ 3. Under **API keys**, name the key after the machine or job that will use it — `ci`,
100
+ `deploy-bot`, `home-server` — not after yourself. The name is how you decide which one to
101
+ revoke later.
102
+ 4. Press **Create** and copy it at once. It looks like `pm_live_` plus 43 characters, is stored
103
+ only as a hash, and cannot be shown to you again. A lost key is revoked and replaced.
104
+ 5. Use it:
105
+
106
+ ```bash
107
+ export PERSISTMEMORY_API_KEY=pm_live_...
108
+ pm search "release checklist" --output json
109
+ ```
110
+
111
+ `PERSISTMEMORY_API_KEY` takes precedence over any stored login, which is what makes CI
112
+ predictable. Or store it in a profile instead:
113
+
114
+ ```bash
115
+ pm auth login --api-key
116
+ ```
117
+
118
+ Revoke a key any time in **Settings → API keys → Revoke**; whatever was using it stops
119
+ working immediately. A key can read and write your memories and spaces — it cannot change your
120
+ password or mint another key.
121
+
122
+ ---
123
+
124
+ ## First five minutes
125
+
126
+ ```bash
127
+ pm auth login
128
+
129
+ pm remember "we chose Postgres with pgvector over Pinecone — cost and lock-in"
130
+ pm remember --file ./notes/architecture.md
131
+ git log -1 --format=%B | pm remember - # capture whatever is piped in
132
+
133
+ pm search "why postgres"
134
+ pm list memories --limit 20
135
+ pm get memory <id>
136
+
137
+ pm # just start talking
138
+ ```
139
+
140
+ Running `pm` with no arguments starts an interactive session: ask a question in plain
141
+ English and it answers out of your own memory.
142
+
143
+ > **`remember` is asynchronous.** It hands the text to the pipeline and returns. Extraction and
144
+ > consolidation happen afterwards, so a memory may take a moment to become searchable — and the
145
+ > same fact captured twice becomes one memory with two pieces of evidence, not two memories.
146
+
147
+ ---
148
+
149
+ ## Spaces
150
+
151
+ A **space** is a boundary. Search inside one and you see only what is in it — that is how work
152
+ stays out of personal and one client stays out of another.
153
+
154
+ ```bash
155
+ pm list spaces # what you have, with their ids
156
+ ```
157
+
158
+ `--space` takes **space ids**, comma-separated — the ids `pm list spaces` prints, not the
159
+ display names:
160
+
161
+ ```bash
162
+ # Capture into a space
163
+ pm remember "Acme's cutover is the 14th" --space space_a1b2c3
164
+
165
+ # Search only there
166
+ pm search "cutover date" --space space_a1b2c3
167
+
168
+ # Several at once
169
+ pm search "deadline" --space space_a1b2c3,space_d4e5f6
170
+ ```
171
+
172
+ Creating a space is not a CLI command yet. Make one with the SDK or the API:
173
+
174
+ ```ts
175
+ import { PersistMemory } from "@persistmemory/sdk";
176
+ const client = new PersistMemory({ apiKey: process.env.PERSISTMEMORY_API_KEY! });
177
+ const acme = await client.spaces.create({ name: "Acme", kind: "project" });
178
+ console.log(acme.id);
179
+ ```
180
+
181
+ ```bash
182
+ curl -s https://api.persistmemory.com/api/v1/spaces \
183
+ -H "authorization: Bearer $PERSISTMEMORY_API_KEY" \
184
+ -H "content-type: application/json" \
185
+ -d '{"name":"Acme","kind":"project"}'
186
+ ```
187
+
188
+ Leaving `--space` off searches everything you have.
189
+
190
+ ---
191
+
192
+ ## Commands
193
+
194
+ | Command | What it does |
195
+ | --- | --- |
196
+ | `pm` | Start an interactive session and just ask |
197
+ | `pm chat` | The same, explicitly |
198
+ | `pm chat --resume <id>` | Pick up an earlier session |
199
+ | `pm auth login` | Sign in through the browser |
200
+ | `pm auth login --api-key` | Sign in with a key, for CI and headless machines |
201
+ | `pm auth status` | Who am I, and does the server still accept it |
202
+ | `pm auth logout` | Forget the stored credential |
203
+ | `pm remember <text>` | Capture text |
204
+ | `pm remember -` | Capture whatever is piped in |
205
+ | `pm remember --file <path>` | Capture a file's contents |
206
+ | `pm search <query>` | Search your memory |
207
+ | `pm list memories` | The most recent memories |
208
+ | `pm list spaces` | Your spaces |
209
+ | `pm get memory <id>` | One memory, in full |
210
+ | `pm status` | Is the service healthy |
211
+ | `pm requests` | File requests waiting for you to approve |
212
+ | `pm agent --root <dir>` | Answer file requests, reading only inside the folders you name |
213
+
214
+ Flags: `--output`, `--profile`, `--api-url`, `--limit`, `--space`, `--quiet`, `--version`,
215
+ `--help`. `pm --help` prints the whole thing, always up to date with the version you have.
216
+
217
+ ---
218
+
219
+ ## Output formats and scripting
220
+
221
+ ```bash
222
+ pm search "postgres" --output json | jq '.results[].memory.title'
223
+ pm list memories --output csv > memories.csv
224
+ pm list spaces --output yaml
225
+ ```
226
+
227
+ The default is a **table on a terminal and JSON when piped**, so a command you typed stays
228
+ readable and the same command in a script stays parseable — without you remembering a flag.
229
+
230
+ Exit codes are meaningful: `0` success, non-zero on failure, so `set -e` behaves.
231
+
232
+ ---
233
+
234
+ ## Profiles
235
+
236
+ More than one account — your own and a work one, or production and staging:
237
+
238
+ ```bash
239
+ pm auth login --profile work
240
+ pm search "roadmap" --profile work
241
+ export PERSISTMEMORY_PROFILE=work # or set it for the shell
242
+ ```
243
+
244
+ Each profile keeps its own credential. `--profile` beats the environment variable, which beats
245
+ the stored default.
246
+
247
+ ---
248
+
249
+ ## The agent, and file requests
250
+
251
+ `pm agent` lets an assistant — in Claude, ChatGPT, Telegram, wherever you are — ask for a file
252
+ from *this* machine. It reads **only inside the folders you name**, and nothing is read until
253
+ you approve it.
254
+
255
+ ```bash
256
+ pm agent --root ~/projects --root ~/Documents
257
+ ```
258
+
259
+ Then, from anywhere: *"get me the deploy checklist from my laptop"*. The request appears here:
260
+
261
+ ```bash
262
+ pm requests # what is waiting
263
+ ```
264
+
265
+ and on the web at <https://persistmemory.com/dashboard/requests>.
266
+
267
+ **A request made by a model is never fulfilled automatically.** A live read is something you
268
+ approve, every time, because the thing asking may be repeating an instruction it found in
269
+ somebody else's email.
270
+
271
+ ---
272
+
273
+ ## Environment variables
274
+
275
+ | Variable | Meaning |
276
+ | --- | --- |
277
+ | `PERSISTMEMORY_API_KEY` | A key, taking precedence over any stored login. This is what CI should set. |
278
+ | `PERSISTMEMORY_API_URL` | The server to talk to. Default `https://api.persistmemory.com` |
279
+ | `PERSISTMEMORY_PROFILE` | Which stored profile to use |
280
+ | `PERSISTMEMORY_HOME` | Where config, credentials and transcripts live. Default `~/.persistmemory` |
281
+ | `PERSISTMEMORY_CLIENT_ID` | Override the OAuth client id, for a self-hosted deployment |
282
+
283
+ ---
284
+
285
+ ## Where your files live
286
+
287
+ ```
288
+ ~/.persistmemory/
289
+ ├── config.json profiles and the current one
290
+ ├── credentials.json tokens — treat this like an SSH key
291
+ └── sessions/ transcripts of your interactive sessions
292
+ ```
293
+
294
+ Move all of it with `PERSISTMEMORY_HOME`.
295
+
296
+ ---
297
+
298
+ ## Security
299
+
300
+ - **The browser holds the password, not the CLI.** Sign-in is OAuth 2.1 with PKCE. Your password
301
+ is never typed into a terminal and never passes through this program. What comes back is a
302
+ token scoped to what you approved on the consent screen.
303
+ - **A stolen code is worthless on its own.** The CLI invents a one-time secret, sends only its
304
+ hash to the browser, and reveals the secret when redeeming the code. Anything that intercepts
305
+ the redirect on a shared machine gets a code it cannot exchange.
306
+ - **The callback is loopback-only** — `http://127.0.0.1:<random port>`, listening for one
307
+ request and then closed.
308
+ - **Credentials are files with your permissions**, not entries in a shared keychain another
309
+ process can read without asking.
310
+ - **Nothing is read from your disk without you saying so.** See file requests, above.
311
+
312
+ Found a security problem? <mailto:hello@persistmemory.com>. Please do not open it in public.
313
+
314
+ ---
315
+
316
+ ## Troubleshooting
317
+
318
+ **`pm: command not found` after `npm install -g`**
319
+ npm's global bin directory is not on your `PATH`. `npm bin -g` prints it; add that to your
320
+ shell profile. The install script sets this up for you, which is why it exists.
321
+
322
+ **`EACCES` during a global install**
323
+ Do not reach for `sudo`. Either use the install script, or point npm at a directory you own:
324
+ `npm config set prefix ~/.npm-global` and add `~/.npm-global/bin` to your `PATH`.
325
+
326
+ **`pm auth login` opens the browser and nothing happens**
327
+ The callback is on `127.0.0.1`. A VPN, a proxy that captures loopback, or a browser on a
328
+ *different machine* than the CLI will break it. On a remote box use `pm auth login --api-key`
329
+ instead — that is exactly what it is for.
330
+
331
+ **"Session expired"**
332
+ An OAuth token lasts an hour and renews itself; if renewal fails, `pm auth login` again. An API
333
+ key does not expire on a schedule — if a key stops working, it was revoked.
334
+
335
+ **`pm search` finds nothing you just captured**
336
+ `remember` is asynchronous. Give the pipeline a moment, then search again.
337
+
338
+ **Everything fails with a connection error**
339
+ `pm status` reports whether the service is reachable. Check `PERSISTMEMORY_API_URL` is not left
340
+ over from a local experiment.
341
+
342
+ **Node is too old**
343
+ `node --version` must be 20 or newer. The CLI refuses to run rather than failing later in a
344
+ confusing way.
345
+
346
+ ---
347
+
348
+ ## Uninstall
349
+
350
+ ```bash
351
+ npm uninstall -g @persistmemory/cli
352
+ rm -rf ~/.persistmemory # optional: credentials, config and transcripts
353
+ ```
354
+
355
+ ---
356
+
357
+ ## Links
358
+
359
+ - CLI documentation — <https://persistmemory.com/docs/cli>
360
+ - TypeScript SDK — [`@persistmemory/sdk`](https://www.npmjs.com/package/@persistmemory/sdk)
361
+ - API keys — <https://persistmemory.com/settings#keys>
362
+ - Support — <mailto:hello@persistmemory.com>
363
+
364
+ ## License
365
+
366
+ MIT © PersistMemory