myagentmemory 0.4.16 → 0.4.17

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.
@@ -18,29 +18,27 @@ const MISSING_ENTITLEMENT = {
18
18
  state: "missing",
19
19
  features: [],
20
20
  capabilities: {},
21
- reason: "Enter an email address to activate the free daily session allowance",
21
+ reason: "Install the no-account Pro preview to activate local recall and learning",
22
22
  };
23
23
  function cloneEntitlement(value) {
24
24
  return structuredClone(value);
25
25
  }
26
- function freeEntitlement(dailySessionLimit) {
26
+ function freeEntitlement() {
27
27
  return {
28
28
  plan: "free",
29
29
  state: "active",
30
30
  features: ["session-intelligence", "web-console"],
31
31
  capabilities: {
32
32
  "session-index": { enabled: true },
33
- "session-worker": {
34
- enabled: true,
35
- quota: { limit: dailySessionLimit, window: "day", scope: "account" },
36
- },
37
- learning: { enabled: true },
33
+ recall: { enabled: true, quota: { limit: 10, window: "day", scope: "device" } },
34
+ "session-worker": { enabled: false },
35
+ learning: { enabled: true, quota: { limit: 1, window: "day", scope: "device" } },
38
36
  "retrieval-evaluation": { enabled: true },
39
37
  "operational-metrics": { enabled: true },
40
38
  "web-console": { enabled: true },
41
39
  "memory-explorer": { enabled: true },
42
40
  },
43
- reason: `${dailySessionLimit} free agent sessions per UTC day`,
41
+ reason: "Free preview: 10 recalls and 1 learning scan per local day; indexing and dashboard access remain available",
44
42
  };
45
43
  }
46
44
  function isEmail(value) {
@@ -346,41 +344,27 @@ export class TemporaryPluginBackend {
346
344
  this.artifactOrigin = options.artifactOrigin ?? ARTIFACT_ORIGIN;
347
345
  this.fetchImplementation = options.fetch ?? globalThis.fetch;
348
346
  this.openUrl = options.openUrl ?? openLoopbackUrl;
349
- this.activate = options.activate ?? (() => collectTemporaryActivation(this.openUrl));
347
+ this.activate = options.activate ?? (async () => `am_install_${randomBytes(24).toString("base64url")}`);
350
348
  }
351
349
  async getLocalEntitlement() {
352
350
  const activation = this.readActivation();
353
- return activation ? freeEntitlement(activation.dailySessionLimit) : cloneEntitlement(MISSING_ENTITLEMENT);
351
+ return activation ? freeEntitlement() : cloneEntitlement(MISSING_ENTITLEMENT);
354
352
  }
355
353
  async resolveAccess(request) {
356
354
  const activation = this.readActivation();
357
- let email = activation?.email;
358
- if (!email) {
359
- if (!request.allowAuthentication)
360
- return {
361
- kind: "auth_required",
362
- entitlement: cloneEntitlement(MISSING_ENTITLEMENT),
363
- nextAction: {
364
- kind: "authenticate",
365
- url: "https://jayzeng.github.io/agentmemory/",
366
- message: "Run plugin install in an interactive terminal to enter an email address",
367
- },
368
- };
369
- email = await this.activate();
370
- }
355
+ const installationId = activation?.installationId ?? (await this.activate());
371
356
  const response = await this.request(`${this.apiOrigin}/v1/plugin/access`, {
372
357
  method: "POST",
373
358
  headers: { "Content-Type": "application/json" },
374
359
  body: JSON.stringify({
375
- schemaVersion: 1,
376
- email,
360
+ schemaVersion: 2,
361
+ installationId,
377
362
  bundleId: request.bundleId,
378
363
  installedVersion: request.installedVersion ?? null,
379
364
  coreVersion: this.coreVersion,
380
365
  channel: request.channel,
381
366
  platform: process.platform,
382
367
  architecture: process.arch,
383
- consentVersion: "activation-v2",
384
368
  }),
385
369
  });
386
370
  const value = (await readJson(response));
@@ -389,14 +373,20 @@ export class TemporaryPluginBackend {
389
373
  throw new PluginBootstrapFailure("service_response_invalid", "The access response omitted its artifact grant");
390
374
  if (typeof value.usageCredential !== "string" || !ACTIVATION_CREDENTIAL.test(value.usageCredential))
391
375
  throw new PluginBootstrapFailure("service_response_invalid", "The access response omitted its usage credential");
392
- const freeQuota = value.entitlement.capabilities["session-worker"]?.quota;
376
+ const recallQuota = value.entitlement.capabilities.recall?.quota;
377
+ const learningQuota = value.entitlement.capabilities.learning?.quota;
393
378
  if (value.entitlement.plan !== "free" ||
394
379
  value.entitlement.state !== "active" ||
395
- !freeQuota ||
396
- freeQuota.scope !== "account" ||
397
- freeQuota.window !== "day")
398
- throw new PluginBootstrapFailure("service_response_invalid", "The free session policy is invalid");
399
- this.writeActivation(email, value.usageCredential, freeQuota.limit);
380
+ !recallQuota ||
381
+ recallQuota.scope !== "device" ||
382
+ recallQuota.window !== "day" ||
383
+ !learningQuota ||
384
+ learningQuota.scope !== "device" ||
385
+ learningQuota.window !== "day" ||
386
+ value.entitlement.capabilities["session-index"]?.enabled !== true ||
387
+ value.entitlement.capabilities["web-console"]?.enabled !== true)
388
+ throw new PluginBootstrapFailure("service_response_invalid", "The free preview policy is invalid");
389
+ this.writeActivation(installationId, value.usageCredential, 1);
400
390
  return { kind: "granted", entitlement: value.entitlement, artifactGrant: value.artifactGrant };
401
391
  }
402
392
  async reserveSession(operationId) {
@@ -451,8 +441,9 @@ export class TemporaryPluginBackend {
451
441
  if (!stat.isFile() || stat.isSymbolicLink() || (process.platform !== "win32" && (stat.mode & 0o077) !== 0))
452
442
  return null;
453
443
  const value = JSON.parse(fs.readFileSync(activationPath, "utf-8"));
454
- if (value.schemaVersion !== 2 ||
455
- !isEmail(value.email) ||
444
+ if (value.schemaVersion !== 3 ||
445
+ typeof value.installationId !== "string" ||
446
+ !/^am_install_[A-Za-z0-9_-]{32}$/.test(value.installationId) ||
456
447
  !Number.isFinite(Date.parse(value.activatedAt)) ||
457
448
  !ACTIVATION_CREDENTIAL.test(value.usageCredential) ||
458
449
  !Number.isSafeInteger(value.dailySessionLimit) ||
@@ -465,9 +456,9 @@ export class TemporaryPluginBackend {
465
456
  return null;
466
457
  }
467
458
  }
468
- writeActivation(email, usageCredential, dailySessionLimit) {
469
- if (!isEmail(email))
470
- throw new PluginBootstrapFailure("email_invalid", "Enter a valid email address");
459
+ writeActivation(installationId, usageCredential, dailySessionLimit) {
460
+ if (!/^am_install_[A-Za-z0-9_-]{32}$/.test(installationId))
461
+ throw new PluginBootstrapFailure("activation_failed", "The installation identifier is invalid");
471
462
  if (!ACTIVATION_CREDENTIAL.test(usageCredential))
472
463
  throw new PluginBootstrapFailure("activation_failed", "The activation credential is invalid");
473
464
  if (!Number.isSafeInteger(dailySessionLimit) || dailySessionLimit <= 0 || dailySessionLimit > 10_000)
@@ -484,7 +475,13 @@ export class TemporaryPluginBackend {
484
475
  if (!directoryStat.isDirectory() || directoryStat.isSymbolicLink())
485
476
  throw new PluginBootstrapFailure("activation_path_invalid", "The plugin activation directory is unsafe");
486
477
  const temporary = `${target}.tmp-${process.pid}-${randomUUID()}`;
487
- fs.writeFileSync(temporary, `${JSON.stringify({ schemaVersion: 2, email, activatedAt: new Date().toISOString(), usageCredential, dailySessionLimit }, null, 2)}\n`, { mode: 0o600, flag: "wx" });
478
+ fs.writeFileSync(temporary, `${JSON.stringify({
479
+ schemaVersion: 3,
480
+ installationId,
481
+ activatedAt: new Date().toISOString(),
482
+ usageCredential,
483
+ dailySessionLimit,
484
+ }, null, 2)}\n`, { mode: 0o600, flag: "wx" });
488
485
  fs.renameSync(temporary, target);
489
486
  }
490
487
  async sessionUsage(action, operationId) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Status
4
4
 
5
- Accepted design on 2026-08-16 and revised on 2026-08-17. The public core implements host types, loopback email activation, live catalog and artifact retrieval, Ed25519 release verification, bounded package validation, transactional install, bundle health checks, paid-command dispatch, and SessionStart hook dispatch. The free plan grants a configurable number of agent sessions per normalized email and UTC day; durable account authentication, payment, renewal, and account management remain deferred.
5
+ Accepted design on 2026-08-16 and revised on 2026-08-17. The public core implements host types, anonymous preview activation, live catalog and artifact retrieval, Ed25519 release verification, bounded package validation, transactional install, bundle health checks, paid-command dispatch, and SessionStart hook dispatch. The free preview grants 10 device-local recalls and one device-local learning scan per local day while keeping indexing and Memory Dashboard visibility available. Account authentication, payment, renewal, and account management remain deferred.
6
6
 
7
7
  The public `agentmemory` repository and `myagentmemory` npm package remain the free, MIT-licensed core. The public bootstrap client and host contracts are also MIT-licensed. Official commercial implementations and browser assets are built and distributed separately from the private `agent-memory-plugin` workspace under their own terms. Pricing, the billing provider, device limits, offline-grace duration, and Enterprise contract terms are intentionally not decided here. The temporary beta currently uses allowlisted `*.agentmemory.paperpilot.me` service origins; changing those origins is a public-client release change.
8
8
 
@@ -10,10 +10,10 @@ The public `agentmemory` repository and `myagentmemory` npm package remain the f
10
10
 
11
11
  The public core will provide a small bootstrap and host surface for signed first-party plugins. It will not contain paid implementations, browser assets, commercial entitlement logic, or a general third-party marketplace.
12
12
 
13
- The primary user command is:
13
+ The primary product-facing command is:
14
14
 
15
15
  ```bash
16
- agent-memory plugin install
16
+ agent-memory pro install
17
17
  ```
18
18
 
19
19
  `plugin install` is an idempotent reconcile operation:
@@ -23,11 +23,11 @@ agent-memory plugin install
23
23
  | Plugin absent | Active or grace | Install the compatible signed bundle |
24
24
  | Plugin older than the selected release | Active or grace | Upgrade atomically |
25
25
  | Plugin current | Active or grace | Report that it is current |
26
- | Any | Missing | Start loopback email activation in an interactive terminal |
26
+ | Any | Missing | Request an anonymous free-preview entitlement and signed artifact grant |
27
27
  | Any | Expired | Direct the user to renewal; leave core available |
28
28
  | Incompatible bundle | Any | Leave the current version untouched and explain the required core version |
29
29
 
30
- An absent plugin cannot activate itself. The public bootstrap collects an email locally, obtains a server-issued usage credential and short-lived artifact grant, and verifies the release and artifact. The credential is persisted only after the service accepts activation. After installation, the public host reconstructs the free account-metered capability policy in core code and checks required capabilities before commands and hooks. Signed long-lived entitlements can extend this credential when authentication and payment ship.
30
+ An absent plugin cannot activate itself. The public bootstrap creates a random installation identifier, obtains a server-issued free-preview policy and short-lived artifact grant, and verifies the release and artifact. A mode-0600 activation record is persisted only after the service accepts the request. After installation, the public host reconstructs the free capability policy in core code and checks required capabilities before commands and hooks. Signed long-lived paid entitlements can extend this record when authentication and payment ship.
31
31
 
32
32
  ## Ownership boundary
33
33
 
@@ -67,6 +67,12 @@ Core memory operations must continue to work when the service is unreachable, a
67
67
  ### Bootstrap commands
68
68
 
69
69
  ```text
70
+ agent-memory pro
71
+ agent-memory pro install
72
+ agent-memory pro status
73
+ agent-memory pro upgrade
74
+ agent-memory pro manage
75
+
70
76
  agent-memory plugin
71
77
  agent-memory plugin list
72
78
  agent-memory plugin status
@@ -76,6 +82,8 @@ agent-memory plugin uninstall [--yes]
76
82
  agent-memory plugin manage [--no-browser]
77
83
  ```
78
84
 
85
+ The `pro` namespace is the user-facing surface. The `plugin` namespace remains supported for low-level administration and compatibility.
86
+
79
87
  - `plugin` with no subcommand prints a discovery summary and the next relevant command.
80
88
  - `list` reports known official plugins and whether each is installed and available. It does not download artifacts or inspect memory.
81
89
  - `status` is read-only. It reports the installed bundle, selected channel, compatibility, entitlement state, and update availability.
@@ -84,7 +92,7 @@ agent-memory plugin manage [--no-browser]
84
92
  - `uninstall` removes executable plugin material and the active receipt. It preserves core memory, plugin state, and the permission-restricted activation credential.
85
93
  - `manage` remains unavailable until authenticated account and billing management exists.
86
94
 
87
- Installed plugins contribute top-level commands such as `recall`, `learn`, `worker`, and `web`. Bootstrap command names are reserved by the core and cannot be replaced by a plugin.
95
+ Installed plugins contribute top-level commands including `recall` and `learn`; `dashboard` is a product-facing alias for the lower-level `web` command. Bootstrap command names are reserved by the core and cannot be replaced by a plugin.
88
96
 
89
97
  The current private compatibility CLI uses `plugin install` and `plugin uninstall` for skill files only. During migration, those meanings move to `install-skills --plugin-only` and `uninstall-skills --plugin-only`; the bootstrap command names above become authoritative.
90
98
 
@@ -93,13 +101,13 @@ The current private compatibility CLI uses `plugin install` and `plugin uninstal
93
101
  After a successful interactive `agent-memory init`, the core may print one informational line:
94
102
 
95
103
  ```text
96
- Optional: AgentMemory Pro adds session recall and a local Web Console.
97
- Run: agent-memory plugin install
104
+ Core remembers what you save. Pro learns from what you do.
105
+ Run: agent-memory pro install
98
106
  ```
99
107
 
100
- Top-level help includes an `Optional official plugins` section. Human-readable `status` may include the same recommendation while no official plugin is installed. Routine `context`, `read`, `write`, `search`, and scratchpad commands never show commercial prompts.
108
+ Top-level help includes a Pro section. Human-readable `status` may include the same recommendation while Pro is not installed. Routine `context`, `read`, `write`, `search`, and scratchpad commands never show commercial prompts.
101
109
 
102
- The core must not open a browser during package installation, `init`, `help`, `status`, or any normal memory operation. A browser may open only after an explicit interactive `plugin install`. `--no-browser`, non-interactive execution, and `--json` fail closed with `auth_required` when no activation record exists.
110
+ The free preview does not open a browser or request identity. Browsers remain restricted to explicit `dashboard`, future `pro manage`, and future paid upgrade/authentication flows. Non-interactive and `--json` installs use the same anonymous access request and still fail closed when the commercial service is unavailable.
103
111
 
104
112
  ### Machine-readable output
105
113
 
@@ -133,17 +141,17 @@ Every bootstrap command supports `--json` and emits one JSON document with a ver
133
141
 
134
142
  `result` is one of `not_installed`, `installed`, `upgraded`, `current`, `update_available`, `uninstalled`, `auth_required`, `renewal_required`, or `unavailable`. Failures use `ok: false` plus a stable `error.code` and redacted `error.message`. Output must never contain access tokens, download credentials, signed entitlement contents, local memory paths, or URLs containing bearer credentials.
135
143
 
136
- ## Free activation flow
144
+ ## Anonymous free-preview flow
137
145
 
138
- 1. `agent-memory plugin install` starts an HTTP server bound to `127.0.0.1` on an ephemeral port.
139
- 2. The CLI prints and opens a nonce-bearing local URL. The page accepts one email address with bounded input, an exact Host and nonce path, same-origin browser request validation, restrictive response headers, and a five-minute deadline.
140
- 3. Submission returns a completion page but does not create a local credential yet.
141
- 4. The waiting CLI sends the email plus core, installed-bundle, platform, architecture, release-channel, and consent-version fields to the private control plane. Its activation database stores none of the user's memory, session content, queries, repository paths, raw agent session identifiers, IP address, or user-agent string.
142
- 5. The service normalizes the email, stores only a hash of a random usage credential, and returns the credential, a free account-metered entitlement, and a short-lived object-bound artifact grant. Only then does the CLI atomically write a mode-0600 activation record.
146
+ 1. `agent-memory pro install` creates a random installation identifier locally when no activation record exists.
147
+ 2. The CLI sends that identifier plus core, installed-bundle, platform, architecture, and release-channel fields to the private control plane. It sends no email, memory, session content, query, repository path, raw agent session identifier, IP address, or user-agent string.
148
+ 3. The service stores the pseudonymous identifier and only the hash of a random compatibility credential, then returns a free-preview capability policy and short-lived object-bound artifact grant.
149
+ 4. The CLI validates the explicit free policy: local indexing and Memory Dashboard access, 10 device-local recalls per day, one device-local learning scan per day, and no free automatic background worker.
150
+ 5. Only then does the CLI atomically write a mode-0600 activation record.
143
151
  6. The CLI verifies the Ed25519-signed release plus package digest and limits, imports it for health checks, and atomically activates the receipt.
144
- 7. Each paid SessionStart hook reserves one opaque operation against the email's UTC-day allowance, commits after useful hook work, and releases on failure. Exhaustion skips paid hook work without affecting public-core context.
152
+ 7. Device-local quota operations reserve before work, commit after useful work, and release on abstention or failure. A zero-result recall does not consume allowance.
145
153
 
146
- Email ownership is not verified in this free flow. Authentication, payment, renewal, account management, and signed paid entitlements are not implemented yet.
154
+ Authentication, payment, renewal, account management, and signed paid entitlements are not implemented yet.
147
155
 
148
156
  ## Future authentication and purchase flow
149
157
 
@@ -163,12 +171,12 @@ An Enterprise administrator may pre-provision an organization entitlement or man
163
171
 
164
172
  The service exposes:
165
173
 
166
- - `POST /v1/plugin/access` for a free account-metered entitlement, a usage credential, and a short-lived artifact grant;
167
- - `POST /v1/plugin/sessions/reserve|commit|release` for atomic daily allowance enforcement;
174
+ - `POST /v1/plugin/access` for an anonymous free-preview policy, compatibility credential, and short-lived artifact grant;
175
+ - `POST /v1/plugin/sessions/reserve|commit|release` for migration compatibility with activation-v2 clients;
168
176
  - `GET /v1/plugin/releases` for an Ed25519-signed release selected from the private R2 catalog;
169
177
  - `GET|HEAD /v1/artifacts/download` for the exact content-addressed object authorized by the bearer grant.
170
178
 
171
- The access request contains the submitted email plus the bounded core, bundle, platform, architecture, release-channel, and consent-version fields described above. Session metering sends only a random operation ID and bearer credential; D1 associates those values with a normalized email and UTC-day counter. Application payloads contain no memory content, search query, session content, path, repository name, raw agent session identifier, qmd data, IP address, or user-agent string. The activation database stores neither IP addresses nor user-agent strings. Future authenticated service responsibilities include:
179
+ The access request contains a random installation identifier plus the bounded core, bundle, platform, architecture, and release-channel fields described above. Application payloads contain no email, memory content, search query, session content, path, repository name, raw agent session identifier, qmd data, IP address, or user-agent string. The activation database stores neither IP addresses nor user-agent strings. Future authenticated service responsibilities include:
172
180
 
173
181
  - create and poll a device authorization;
174
182
  - read the authenticated principal's effective entitlement;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagentmemory",
3
- "version": "0.4.16",
3
+ "version": "0.4.17",
4
4
  "description": "agentmemory (agent-memory) is persistent memory for coding agents (Claude Code, OpenAI Codex, Cursor, Agent) with qmd-powered semantic search across daily logs, long-term memory, and scratchpad",
5
5
  "main": "./dist/core.js",
6
6
  "types": "./dist/core.d.ts",
package/src/cli-spec.ts CHANGED
@@ -23,6 +23,10 @@ export const COMMANDS = [
23
23
  "install-hooks",
24
24
  "uninstall-hooks",
25
25
  "completion",
26
+ "pro",
27
+ "recall",
28
+ "learn",
29
+ "dashboard",
26
30
  "plugin",
27
31
  "version",
28
32
  "help",
@@ -48,9 +52,13 @@ export const COMMAND_DESCRIPTIONS: Record<(typeof COMMANDS)[number], string> = {
48
52
  "install-hooks": "install automatic SessionStart indexing and context hooks",
49
53
  "uninstall-hooks": "remove only SessionStart hooks managed by agent-memory",
50
54
  completion: "install or print Bash, Zsh, Fish, or PowerShell completion",
51
- plugin: "index, recall, learn from, and evaluate prior agent sessions",
55
+ pro: "install, inspect, or upgrade AgentMemory Pro",
56
+ recall: "recall decisions and context from prior coding sessions with Pro",
57
+ learn: "find repeated corrections worth remembering with Pro",
58
+ dashboard: "open the private local Memory Dashboard",
59
+ plugin: "discover, install, update, or remove optional official plugins",
52
60
  version: "print the installed agent-memory version",
53
- help: "show top-level, command, or nested plugin help",
61
+ help: "show this command overview",
54
62
  };
55
63
 
56
64
  export const PLUGIN_COMMAND_DESCRIPTIONS: Record<(typeof PLUGIN_COMMANDS)[number], string> = {
@@ -89,6 +97,10 @@ export const COMMAND_OPTIONS: Record<string, readonly string[]> = {
89
97
  "install-hooks": ["--yes", "--all", "--only"],
90
98
  "uninstall-hooks": ["--only"],
91
99
  completion: ["--stdout"],
100
+ pro: [],
101
+ recall: ["--scope", "--cwd", "--limit", "--context"],
102
+ learn: [],
103
+ dashboard: ["--no-browser"],
92
104
  version: [],
93
105
  help: [],
94
106
  };
package/src/cli.ts CHANGED
@@ -25,6 +25,7 @@
25
25
  import { spawn } from "node:child_process";
26
26
  import * as fs from "node:fs";
27
27
 
28
+ import { COMMAND_DESCRIPTIONS, COMMANDS } from "./cli-spec.js";
28
29
  import { type CompletionShell, detectCompletionShell, generateCompletion, installCompletion } from "./completions.js";
29
30
 
30
31
  import {
@@ -73,6 +74,7 @@ import {
73
74
  PluginBootstrapFailure,
74
75
  type PluginBootstrapResultV1,
75
76
  } from "./plugin-bootstrap.js";
77
+ import type { PluginContextSectionV1 } from "./plugin-host.js";
76
78
  import { InstalledPluginRuntimeV1 } from "./plugin-runtime.js";
77
79
 
78
80
  declare const __VERSION__: string;
@@ -186,21 +188,23 @@ function openExternalUrl(url: string): boolean {
186
188
 
187
189
  function printProOverview(installed: boolean): void {
188
190
  console.log("");
189
- console.log("AgentMemory Pro includes:");
190
- console.log(" Session Intelligence Recall decisions and context across Pi, Codex, and Claude Code sessions.");
191
- console.log(" Guided Learning Turn repeated corrections into reviewable, reversible memory.");
192
- console.log(" Local Web Console Inspect memories, activity, health, and settings in your browser.");
191
+ console.log("Core remembers what you save. Pro learns from what you do.");
193
192
  console.log("");
194
- console.log("Your session content stays on this device.");
193
+ console.log("AgentMemory Pro:");
194
+ console.log(" Recall coding history Find decisions and context across Pi, Codex, and Claude Code sessions.");
195
+ console.log(" Learn from corrections Turn repeated fixes into reviewable, reversible memory.");
196
+ console.log(" See and control learning Inspect what AgentMemory remembers and why in the Memory Dashboard.");
197
+ console.log("");
198
+ console.log("No account is required for the free preview. Your coding history stays on this device.");
195
199
  console.log("");
196
200
  if (installed) {
197
201
  console.log("Try it:");
198
202
  console.log(' agent-memory recall "what did we decide about authentication?"');
199
203
  console.log(" agent-memory learn");
200
- console.log(" agent-memory web");
204
+ console.log(" agent-memory dashboard");
201
205
  } else {
202
- console.log("Start your Pro beta:");
203
- console.log(" agent-memory plugin install");
206
+ console.log("Start your free Pro preview:");
207
+ console.log(" agent-memory pro install");
204
208
  }
205
209
  }
206
210
 
@@ -241,12 +245,10 @@ function printPluginResult(result: PluginBootstrapResultV1, json: boolean, allow
241
245
  break;
242
246
  case "not_installed":
243
247
  console.log("AgentMemory Pro is not installed.");
244
- console.log("Run: agent-memory plugin install");
248
+ console.log("Run: agent-memory pro install");
245
249
  break;
246
250
  case "auth_required":
247
- console.log(
248
- "Run this command in an interactive terminal to enter an email and activate free daily access.",
249
- );
251
+ console.log("Run agent-memory pro install to activate the free preview.");
250
252
  break;
251
253
  case "renewal_required":
252
254
  console.log("Renew AgentMemory Pro to continue using paid capabilities.");
@@ -280,10 +282,23 @@ async function cmdContext(flags: Record<string, string | boolean>) {
280
282
  ensureDirs();
281
283
  if (!noSearch && query) await ensureQmdAvailableForSync();
282
284
  const searchResults = noSearch ? "" : await searchRelevantMemories(query);
283
- const context = buildMemoryContext(searchResults);
285
+ const coreContext = buildMemoryContext(searchResults);
286
+ let pluginSections: PluginContextSectionV1[] = [];
287
+ try {
288
+ pluginSections = await new InstalledPluginRuntimeV1({ coreVersion: VERSION }).provideContext({
289
+ host: "agent-memory-cli",
290
+ cwd: process.cwd(),
291
+ query: query || undefined,
292
+ signal: new AbortController().signal,
293
+ });
294
+ } catch {
295
+ // Optional Pro context must never make public-core context unavailable.
296
+ }
297
+ const pluginContext = pluginSections.map((section) => `${section.label}\n\n${section.content}`).join("\n\n");
298
+ const context = [coreContext, pluginContext].filter(Boolean).join("\n\n");
284
299
 
285
300
  if (json) {
286
- output({ context, directory: getMemoryDir() }, true);
301
+ output({ context, directory: getMemoryDir(), ...(pluginSections.length ? { pluginSections } : {}) }, true);
287
302
  } else {
288
303
  if (context) {
289
304
  process.stdout.write(context);
@@ -811,8 +826,8 @@ async function cmdInit(flags: Record<string, string | boolean>) {
811
826
  const plugin = await createDefaultPluginBootstrap(VERSION).list();
812
827
  if (plugin.result === "not_installed") {
813
828
  console.log("");
814
- console.log("Optional: AgentMemory Pro adds session recall and a local Web Console.");
815
- console.log("Run: agent-memory plugin install");
829
+ console.log("Optional: Pro recalls coding history and learns from repeated corrections.");
830
+ console.log("Try it without an account: agent-memory pro install");
816
831
  }
817
832
  } catch {
818
833
  // Commercial discovery must never make core initialization fail.
@@ -957,8 +972,8 @@ async function cmdStatus(flags: Record<string, string | boolean>) {
957
972
  }
958
973
  if (!officialPlugin.installed) {
959
974
  console.log("");
960
- console.log("Optional official plugins: not installed");
961
- console.log(" run: agent-memory plugin install");
975
+ console.log("AgentMemory Pro: not installed");
976
+ console.log(" try without an account: agent-memory pro install");
962
977
  }
963
978
  }
964
979
  }
@@ -1001,9 +1016,10 @@ Usage:
1001
1016
  agent-memory plugin uninstall --yes
1002
1017
  agent-memory plugin manage [--no-browser]
1003
1018
 
1004
- The public core remains fully usable without AgentMemory Pro. Interactive install
1005
- opens a loopback website for email activation and a configurable free daily
1006
- agent-session allowance. Memory and session content stay on this device.`);
1019
+ The public core remains fully usable without AgentMemory Pro. Install uses a random
1020
+ installation identifier and requires no account or email. The free preview includes
1021
+ 10 recalls and one learning scan per local day; indexing and the Memory Dashboard
1022
+ remain available. Memory and session content stay on this device.`);
1007
1023
  }
1008
1024
 
1009
1025
  function pluginCommandFailure(command: string, error: unknown): PluginBootstrapResultV1 {
@@ -1028,24 +1044,24 @@ function pluginCommandFailure(command: string, error: unknown): PluginBootstrapR
1028
1044
  };
1029
1045
  }
1030
1046
 
1031
- async function cmdPlugin(flags: Record<string, string | boolean>, positional: string[]): Promise<void> {
1047
+ async function cmdPlugin(
1048
+ flags: Record<string, string | boolean>,
1049
+ positional: string[],
1050
+ ): Promise<PluginBootstrapResultV1 | null> {
1032
1051
  const json = hasFlag(flags, "json");
1033
1052
  const subcommand = positional[0] ?? "list";
1034
1053
  if (subcommand === "help" || hasFlag(flags, "help")) {
1035
1054
  printPluginUsage();
1036
- return;
1055
+ return null;
1037
1056
  }
1038
1057
  const channel = getFlag(flags, "channel") ?? "stable";
1039
1058
  if (channel !== "stable") {
1040
- printPluginResult(
1041
- pluginCommandFailure(
1042
- subcommand,
1043
- new PluginBootstrapFailure("channel_invalid", "--channel supports only 'stable'"),
1044
- ),
1045
- json,
1046
- false,
1059
+ const failure = pluginCommandFailure(
1060
+ subcommand,
1061
+ new PluginBootstrapFailure("channel_invalid", "--channel supports only 'stable'"),
1047
1062
  );
1048
- return;
1063
+ printPluginResult(failure, json, false);
1064
+ return failure;
1049
1065
  }
1050
1066
  const allowBrowser = !json && !hasFlag(flags, "no-browser") && Boolean(process.stdin.isTTY && process.stdout.isTTY);
1051
1067
  const manager = createDefaultPluginBootstrap(VERSION);
@@ -1098,6 +1114,55 @@ async function cmdPlugin(flags: Record<string, string | boolean>, positional: st
1098
1114
  result = pluginCommandFailure(subcommand, error);
1099
1115
  }
1100
1116
  printPluginResult(result, json, allowBrowser && (subcommand === "install" || subcommand === "manage"));
1117
+ return result;
1118
+ }
1119
+
1120
+ async function printFirstRunProof(): Promise<void> {
1121
+ try {
1122
+ const result = await new InstalledPluginRuntimeV1({ coreVersion: VERSION }).run("index", {
1123
+ args: [],
1124
+ flags: {},
1125
+ signal: new AbortController().signal,
1126
+ });
1127
+ if (!result?.ok || !result.data || typeof result.data !== "object") return;
1128
+ const stats = (result.data as { stats?: { discovered?: Record<string, number>; selected?: number } }).stats;
1129
+ if (!stats?.discovered) return;
1130
+ const hosts = [
1131
+ ["Claude Code", stats.discovered.claude ?? 0],
1132
+ ["Codex", stats.discovered.codex ?? 0],
1133
+ ["Pi", stats.discovered.pi ?? 0],
1134
+ ] as const;
1135
+ console.log("");
1136
+ console.log("Found local coding history:");
1137
+ for (const [label, count] of hosts) console.log(` ${label.padEnd(13)} ${count} sessions`);
1138
+ console.log("");
1139
+ console.log(`${stats.selected ?? 0} sessions available for local recall. Nothing was uploaded.`);
1140
+ console.log("");
1141
+ console.log('Try: agent-memory recall "what did we decide about authentication?"');
1142
+ console.log("Open: agent-memory dashboard");
1143
+ } catch {
1144
+ // Personalized proof is helpful but must never turn a successful install into a failure.
1145
+ }
1146
+ }
1147
+
1148
+ async function cmdPro(flags: Record<string, string | boolean>, positional: string[]): Promise<void> {
1149
+ const subcommand = positional[0];
1150
+ if (!subcommand) {
1151
+ await cmdPlugin(flags, ["list"]);
1152
+ return;
1153
+ }
1154
+ const mapped = subcommand === "upgrade" ? "update" : subcommand;
1155
+ if (!["install", "status", "update", "manage"].includes(mapped)) {
1156
+ const json = hasFlag(flags, "json");
1157
+ const message = `Unknown Pro command: ${subcommand}. Available commands: install, status, upgrade, manage.`;
1158
+ if (json) console.log(JSON.stringify({ error: message }));
1159
+ else console.error(`Error: ${message}`);
1160
+ process.exitCode = 1;
1161
+ return;
1162
+ }
1163
+ const result = await cmdPlugin(flags, [mapped]);
1164
+ if (!hasFlag(flags, "json") && mapped === "install" && ["installed", "upgraded"].includes(result?.result ?? ""))
1165
+ await printFirstRunProof();
1101
1166
  }
1102
1167
 
1103
1168
  // ---------------------------------------------------------------------------
@@ -1105,28 +1170,18 @@ async function cmdPlugin(flags: Record<string, string | boolean>, positional: st
1105
1170
  // ---------------------------------------------------------------------------
1106
1171
 
1107
1172
  function printUsage() {
1173
+ const commandWidth = Math.max(...COMMANDS.map((command) => command.length));
1174
+ const commandList = COMMANDS.map(
1175
+ (command) => ` ${command.padEnd(commandWidth)} ${COMMAND_DESCRIPTIONS[command]}`,
1176
+ ).join("\n");
1177
+
1108
1178
  console.log(`agent-memory — persistent memory for coding agents
1109
1179
 
1110
1180
  Usage:
1111
1181
  agent-memory <command> [options]
1112
1182
 
1113
1183
  Commands:
1114
- version Show binary version
1115
- install-skills Install (or --uninstall) bundled skills
1116
- uninstall-skills Uninstall bundled skills
1117
- context Build context; optionally retrieve memories with --query
1118
- write Write to memory files (default: daily; optional --source-uri)
1119
- read Read memory files
1120
- scratchpad Manage checklist items
1121
- search Search across memory files (requires qmd)
1122
- distil Generate compact MEMORY.md index from daily logs + topics
1123
- sync Re-index and embed all files (requires qmd)
1124
- init Initialize memory directory and qmd collection
1125
- status Show configuration and status (--probe for a live embeddings check)
1126
- completion Install or print shell completion
1127
- install-hooks Install managed SessionStart hooks
1128
- uninstall-hooks Remove only managed SessionStart hooks
1129
- plugin Discover, install, update, or remove optional official plugins
1184
+ ${commandList}
1130
1185
 
1131
1186
  Global flags:
1132
1187
  --dir <path> Override memory directory
@@ -1152,8 +1207,10 @@ Examples:
1152
1207
  agent-memory status --json
1153
1208
  agent-memory completion zsh
1154
1209
  agent-memory install-hooks --yes
1155
- agent-memory plugin status
1156
- agent-memory plugin install`);
1210
+ agent-memory pro status
1211
+ agent-memory pro install
1212
+ agent-memory recall "what did we decide about authentication?"
1213
+ agent-memory dashboard`);
1157
1214
  }
1158
1215
 
1159
1216
  // ---------------------------------------------------------------------------
@@ -1245,18 +1302,22 @@ async function main() {
1245
1302
  case "plugin":
1246
1303
  await cmdPlugin(flags, positional);
1247
1304
  break;
1305
+ case "pro":
1306
+ await cmdPro(flags, positional);
1307
+ break;
1248
1308
  default: {
1249
1309
  const controller = new AbortController();
1250
1310
  const abort = () => controller.abort();
1251
1311
  process.once("SIGINT", abort);
1252
1312
  try {
1253
- const result = await new InstalledPluginRuntimeV1({ coreVersion: VERSION }).run(command, {
1313
+ const pluginCommand = command === "dashboard" ? "web" : command;
1314
+ const result = await new InstalledPluginRuntimeV1({ coreVersion: VERSION }).run(pluginCommand, {
1254
1315
  args: positional,
1255
1316
  flags,
1256
1317
  signal: controller.signal,
1257
1318
  });
1258
1319
  if (!result) exitError(`Unknown command: ${command}. Run 'agent-memory help' for usage.`, json);
1259
- if (!result.ok) exitError(result.error?.message ?? `Plugin command ${command} failed`, json);
1320
+ if (!result.ok) exitError(result.error?.message ?? `Plugin command ${pluginCommand} failed`, json);
1260
1321
  output(result.data ?? { ok: true }, json);
1261
1322
  } finally {
1262
1323
  process.removeListener("SIGINT", abort);
@@ -195,8 +195,8 @@ const MISSING_ENTITLEMENT: PluginEntitlementStatusV1 = {
195
195
  };
196
196
 
197
197
  const OFFICIAL_PLUGINS = [
198
- { id: OFFICIAL_PLUGIN_IDS[0], name: "Session Intelligence" },
199
- { id: OFFICIAL_PLUGIN_IDS[1], name: "Web Console" },
198
+ { id: OFFICIAL_PLUGIN_IDS[0], name: "Coding History Recall" },
199
+ { id: OFFICIAL_PLUGIN_IDS[1], name: "Memory Dashboard" },
200
200
  ] as const;
201
201
 
202
202
  const PACKAGE_MAX_BYTES = 64 * 1024 * 1024;