@agentmemory/agentmemory 0.9.3 → 0.9.5
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 +116 -53
- package/dist/cli.mjs +163 -23
- package/dist/cli.mjs.map +1 -1
- package/dist/docker-compose.yml +10 -1
- package/dist/hooks/session-end.mjs +4 -4
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/stop.mjs +1 -1
- package/dist/hooks/stop.mjs.map +1 -1
- package/dist/image-refs-DRse_ePx.mjs +3 -0
- package/dist/{image-store-DGvZMMrI.mjs → image-store-DnuCI2RB.mjs} +1 -1
- package/dist/index.mjs +338 -103
- package/dist/index.mjs.map +1 -1
- package/dist/{src-3Snd7D3T.mjs → src-xYHSzz5S.mjs} +264 -41
- package/dist/src-xYHSzz5S.mjs.map +1 -0
- package/dist/{standalone-BG9uPsDK.mjs → standalone-BvKacAId.mjs} +2 -2
- package/dist/{standalone-BG9uPsDK.mjs.map → standalone-BvKacAId.mjs.map} +1 -1
- package/dist/standalone.mjs +9 -2
- package/dist/standalone.mjs.map +1 -1
- package/dist/{tools-registry-m8Ofn9vV.mjs → tools-registry-BWM0vWeA.mjs} +16 -4
- package/dist/tools-registry-BWM0vWeA.mjs.map +1 -0
- package/docker-compose.yml +10 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/scripts/session-end.mjs +4 -4
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +1 -1
- package/plugin/scripts/stop.mjs.map +1 -1
- package/dist/image-refs-CESf9ndJ.mjs +0 -3
- package/dist/src-3Snd7D3T.mjs.map +0 -1
- package/dist/tools-registry-m8Ofn9vV.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
<strong>
|
|
7
|
-
|
|
6
|
+
<strong>
|
|
7
|
+
Your coding agent remembers everything. No more re-explaining.
|
|
8
|
+
Built on <a href="https://github.com/iii-hq/iii">iii engine</a>
|
|
9
|
+
</strong></br>
|
|
10
|
+
Persistent memory for Claude Code, Cursor, Gemini CLI, Codex CLI, pi, OpenCode, and any MCP client.
|
|
8
11
|
</p>
|
|
9
12
|
|
|
10
13
|
<p align="center">
|
|
11
|
-
<a href="https://gist.github.com/rohitg00/2067ab416f7bbe447c1977edaaa681e2"><img src="https://img.shields.io/badge/Viral%20GitHub%20Gist-
|
|
14
|
+
<a href="https://gist.github.com/rohitg00/2067ab416f7bbe447c1977edaaa681e2"><img src="https://img.shields.io/badge/Viral%20GitHub%20Gist-1050%20stars%20%2F%20150%20forks-FF6B35?style=for-the-badge&logo=github&logoColor=white&labelColor=1a1a1a" alt="Design doc: 1050 stars / 150 forks on the gist" /></a>
|
|
12
15
|
</p>
|
|
13
16
|
|
|
14
17
|
<p align="center">
|
|
@@ -43,7 +46,8 @@
|
|
|
43
46
|
<a href="#how-it-works">How It Works</a> •
|
|
44
47
|
<a href="#mcp-server">MCP</a> •
|
|
45
48
|
<a href="#real-time-viewer">Viewer</a> •
|
|
46
|
-
<a href="#iii-console
|
|
49
|
+
<a href="#iii-console">iii Console</a> •
|
|
50
|
+
<a href="#powered-by-iii">Powered by iii</a> •
|
|
47
51
|
<a href="#configuration">Config</a> •
|
|
48
52
|
<a href="#api">API</a>
|
|
49
53
|
</p>
|
|
@@ -341,7 +345,7 @@ Install agentmemory: run `npx @agentmemory/agentmemory` in a separate terminal t
|
|
|
341
345
|
<summary><b>OpenClaw (paste this prompt)</b></summary>
|
|
342
346
|
|
|
343
347
|
```
|
|
344
|
-
Install agentmemory for OpenClaw. Run `npx @agentmemory/agentmemory` in a separate terminal to start the memory server on localhost:3111. Then add this to my OpenClaw MCP config so agentmemory is available with all
|
|
348
|
+
Install agentmemory for OpenClaw. Run `npx @agentmemory/agentmemory` in a separate terminal to start the memory server on localhost:3111. Then add this to my OpenClaw MCP config so agentmemory is available with all 43 memory tools:
|
|
345
349
|
|
|
346
350
|
{
|
|
347
351
|
"mcpServers": {
|
|
@@ -352,7 +356,7 @@ Install agentmemory for OpenClaw. Run `npx @agentmemory/agentmemory` in a separa
|
|
|
352
356
|
}
|
|
353
357
|
}
|
|
354
358
|
|
|
355
|
-
Restart OpenClaw. Verify with `curl http://localhost:3111/agentmemory/health`. Open http://localhost:3113 for the real-time viewer. For deeper
|
|
359
|
+
Restart OpenClaw. Verify with `curl http://localhost:3111/agentmemory/health`. Open http://localhost:3113 for the real-time viewer. For deeper memory-slot integration, copy `integrations/openclaw` to `~/.openclaw/extensions/agentmemory` and enable `plugins.slots.memory = "agentmemory"` in `~/.openclaw/openclaw.json`.
|
|
356
360
|
```
|
|
357
361
|
|
|
358
362
|
Full guide: [`integrations/openclaw/`](integrations/openclaw/)
|
|
@@ -363,14 +367,17 @@ Full guide: [`integrations/openclaw/`](integrations/openclaw/)
|
|
|
363
367
|
<summary><b>Hermes Agent (paste this prompt)</b></summary>
|
|
364
368
|
|
|
365
369
|
```
|
|
366
|
-
Install agentmemory for Hermes. Run `npx @agentmemory/agentmemory` in a separate terminal to start the memory server on localhost:3111. Then add this to ~/.hermes/config.yaml so Hermes can use agentmemory as an MCP server with all
|
|
370
|
+
Install agentmemory for Hermes. Run `npx @agentmemory/agentmemory` in a separate terminal to start the memory server on localhost:3111. Then add this to ~/.hermes/config.yaml so Hermes can use agentmemory as an MCP server with all 43 memory tools:
|
|
367
371
|
|
|
368
372
|
mcp_servers:
|
|
369
373
|
agentmemory:
|
|
370
374
|
command: npx
|
|
371
375
|
args: ["-y", "@agentmemory/mcp"]
|
|
372
376
|
|
|
373
|
-
|
|
377
|
+
memory:
|
|
378
|
+
provider: agentmemory
|
|
379
|
+
|
|
380
|
+
Verify with `curl http://localhost:3111/agentmemory/health`. Open http://localhost:3113 for the real-time viewer. For deeper 6-hook memory provider integration (pre-LLM context injection, turn capture, MEMORY.md mirroring, system prompt block), copy integrations/hermes from the agentmemory repo to ~/.hermes/plugins/agentmemory.
|
|
374
381
|
```
|
|
375
382
|
|
|
376
383
|
Full guide: [`integrations/hermes/`](integrations/hermes/)
|
|
@@ -386,11 +393,12 @@ Then add the MCP config for your agent:
|
|
|
386
393
|
| Agent | Setup |
|
|
387
394
|
|---|---|
|
|
388
395
|
| **Cursor** | Add to `~/.cursor/mcp.json`: `{"mcpServers": {"agentmemory": {"command": "npx", "args": ["-y", "@agentmemory/mcp"]}}}` |
|
|
389
|
-
| **OpenClaw** | Add to MCP config: `{"mcpServers": {"agentmemory": {"command": "npx", "args": ["-y", "@agentmemory/mcp"]}}}` or use the [
|
|
390
|
-
| **Gemini CLI** | `gemini mcp add agentmemory
|
|
391
|
-
| **Codex CLI** |
|
|
396
|
+
| **OpenClaw** | Add to MCP config: `{"mcpServers": {"agentmemory": {"command": "npx", "args": ["-y", "@agentmemory/mcp"]}}}` or use the [memory plugin](integrations/openclaw/) |
|
|
397
|
+
| **Gemini CLI** | `gemini mcp add agentmemory npx -y @agentmemory/mcp --scope user` |
|
|
398
|
+
| **Codex CLI** | `codex mcp add agentmemory -- npx -y @agentmemory/mcp` or add `[mcp_servers.agentmemory]` to `.codex/config.toml` |
|
|
399
|
+
| **pi** | Copy [`integrations/pi`](integrations/pi/) to `~/.pi/agent/extensions/agentmemory` and restart pi |
|
|
392
400
|
| **OpenCode** | Add to `opencode.json`: `{"mcp": {"agentmemory": {"type": "local", "command": ["npx", "-y", "@agentmemory/mcp"], "enabled": true}}}` |
|
|
393
|
-
| **Hermes Agent** | Add to `~/.hermes/config.yaml` or use the [memory provider plugin](integrations/hermes/) |
|
|
401
|
+
| **Hermes Agent** | Add to `~/.hermes/config.yaml` with `memory.provider: agentmemory` or use the [memory provider plugin](integrations/hermes/) |
|
|
394
402
|
| **Cline / Goose / Kilo Code** | Add MCP server in settings |
|
|
395
403
|
| **Claude Desktop** | Add to `claude_desktop_config.json`: `{"mcpServers": {"agentmemory": {"command": "npx", "args": ["-y", "@agentmemory/mcp"]}}}` |
|
|
396
404
|
| **Aider** | REST API: `curl -X POST http://localhost:3111/agentmemory/smart-search -d '{"query": "auth"}'` |
|
|
@@ -405,12 +413,15 @@ npm install && npm run build && npm start
|
|
|
405
413
|
|
|
406
414
|
This starts agentmemory with a local `iii-engine` if `iii` is already installed, or falls back to Docker Compose if Docker is available. REST, streams, and the viewer bind to `127.0.0.1` by default.
|
|
407
415
|
|
|
408
|
-
Install `iii-engine` manually
|
|
416
|
+
Install `iii-engine` manually. **agentmemory currently pins `iii-engine` to `v0.11.2`** — `v0.11.6` introduces a new sandbox-everything-via-`iii worker add` model that agentmemory hasn't been refactored for yet. Pin lifts once the refactor lands. Override with `AGENTMEMORY_III_VERSION=<version>` if you've migrated to the sandbox model manually.
|
|
409
417
|
|
|
410
|
-
- **macOS /
|
|
411
|
-
- **
|
|
418
|
+
- **macOS arm64:** `mkdir -p ~/.local/bin && curl -fsSL https://github.com/iii-hq/iii/releases/download/iii/v0.11.2/iii-aarch64-apple-darwin.tar.gz | tar -xz -C ~/.local/bin && chmod +x ~/.local/bin/iii`
|
|
419
|
+
- **macOS x64:** swap `aarch64-apple-darwin` for `x86_64-apple-darwin`
|
|
420
|
+
- **Linux x64:** swap for `x86_64-unknown-linux-gnu`
|
|
421
|
+
- **Linux arm64:** swap for `aarch64-unknown-linux-gnu`
|
|
422
|
+
- **Windows:** download `iii-x86_64-pc-windows-msvc.zip` from [iii-hq/iii releases v0.11.2](https://github.com/iii-hq/iii/releases/tag/iii%2Fv0.11.2), extract `iii.exe`, add to PATH
|
|
412
423
|
|
|
413
|
-
Or use Docker (the bundled `docker-compose.yml` pulls `iiidev/iii:
|
|
424
|
+
Or use Docker (the bundled `docker-compose.yml` pulls `iiidev/iii:0.11.2`). Full docs: [iii.dev/docs](https://iii.dev/docs).
|
|
414
425
|
|
|
415
426
|
### Windows
|
|
416
427
|
|
|
@@ -419,7 +430,9 @@ agentmemory runs on Windows 10/11, but the Node.js package alone isn't enough
|
|
|
419
430
|
**Option A — Prebuilt Windows binary (recommended):**
|
|
420
431
|
|
|
421
432
|
```powershell
|
|
422
|
-
# 1. Open https://github.com/iii-hq/iii/releases/
|
|
433
|
+
# 1. Open https://github.com/iii-hq/iii/releases/tag/iii%2Fv0.11.2 in your browser
|
|
434
|
+
# (we pin to v0.11.2 until agentmemory refactors for the new sandbox
|
|
435
|
+
# model that engine v0.11.6+ requires)
|
|
423
436
|
# 2. Download iii-x86_64-pc-windows-msvc.zip
|
|
424
437
|
# (or iii-aarch64-pc-windows-msvc.zip if you're on an ARM machine)
|
|
425
438
|
# 3. Extract iii.exe somewhere on PATH, or place it at:
|
|
@@ -427,6 +440,7 @@ agentmemory runs on Windows 10/11, but the Node.js package alone isn't enough
|
|
|
427
440
|
# (agentmemory checks that location automatically)
|
|
428
441
|
# 4. Verify:
|
|
429
442
|
iii --version
|
|
443
|
+
# Should print: 0.11.2
|
|
430
444
|
|
|
431
445
|
# 5. Then run agentmemory as usual:
|
|
432
446
|
npx -y @agentmemory/agentmemory
|
|
@@ -506,7 +520,12 @@ PostToolUse hook fires
|
|
|
506
520
|
-> Store raw observation
|
|
507
521
|
-> LLM compress -> structured facts + concepts + narrative
|
|
508
522
|
-> Vector embedding (6 providers + local)
|
|
509
|
-
-> Index in BM25 + vector
|
|
523
|
+
-> Index in BM25 + vector
|
|
524
|
+
|
|
525
|
+
Stop / SessionEnd hook fires
|
|
526
|
+
-> Summarize session
|
|
527
|
+
-> Knowledge graph extraction (if GRAPH_EXTRACTION_ENABLED=true)
|
|
528
|
+
-> Slot reflection (if SLOT_REFLECT_ENABLED=true)
|
|
510
529
|
|
|
511
530
|
SessionStart hook fires
|
|
512
531
|
-> Load project profile (top concepts, files, patterns)
|
|
@@ -719,41 +738,57 @@ open http://localhost:3113
|
|
|
719
738
|
|
|
720
739
|
The viewer server binds to `127.0.0.1` by default. The REST-served `/agentmemory/viewer` endpoint follows the normal `AGENTMEMORY_SECRET` bearer-token rules. CSP headers use a per-response script nonce and disable inline handler attributes (`script-src-attr 'none'`).
|
|
721
740
|
|
|
722
|
-
|
|
741
|
+
---
|
|
742
|
+
|
|
743
|
+
<h2 id="iii-console"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/section-viewer.svg"><img src="assets/tags/section-viewer.svg" alt="iii Console" height="32" /></picture></h2>
|
|
744
|
+
|
|
745
|
+
The viewer at `:3113` shows what your agent **remembered**. The [iii console](https://iii.dev/docs/console) shows what your agent **did** — every memory op as an OpenTelemetry trace, every KV entry editable, every function invocable, every stream tappable. Two windows on the same memory: one product-shaped, one engine-shaped.
|
|
746
|
+
|
|
747
|
+
Watch a `memory_smart_search` fire and see the BM25 scan → embedding lookup → RRF fusion → reranker as a waterfall. Edit a stuck consolidation timer in the KV browser. Replay a `PostToolUse` hook with a tweaked payload. Pin the WebSocket stream and watch observations land live.
|
|
723
748
|
|
|
724
|
-
agentmemory
|
|
749
|
+
agentmemory ships this for free because every function, trigger, state scope, and stream is an iii primitive — nothing custom, nothing to instrument.
|
|
725
750
|
|
|
726
751
|
<p align="center">
|
|
727
|
-
<img src="assets/iii-console/
|
|
752
|
+
<img src="assets/iii-console/workers.png" alt="iii console Workers page — connected workers including agentmemory instances with live function counts and runtime metadata" width="720" />
|
|
728
753
|
<br/>
|
|
729
|
-
<em>
|
|
754
|
+
<em>Workers page: every connected worker — including agentmemory itself — with PID, function count, runtime, and last-seen.</em>
|
|
730
755
|
</p>
|
|
731
756
|
|
|
732
|
-
**
|
|
757
|
+
**Already installed.** The console ships with `iii` — no separate installer.
|
|
758
|
+
|
|
759
|
+
**Launch alongside agentmemory:**
|
|
733
760
|
|
|
734
761
|
```bash
|
|
735
|
-
|
|
762
|
+
# agentmemory viewer holds port 3113, so run the console on 3114.
|
|
763
|
+
# Engine REST (3111), WebSocket (3112), and bridge (49134) defaults match agentmemory.
|
|
764
|
+
iii console --port 3114
|
|
736
765
|
```
|
|
737
766
|
|
|
738
|
-
|
|
767
|
+
Then open `http://localhost:3114`. Add `--enable-flow` for the experimental architecture-graph page.
|
|
768
|
+
|
|
769
|
+
Override engine endpoints only if you've moved them:
|
|
739
770
|
|
|
740
771
|
```bash
|
|
741
|
-
|
|
742
|
-
|
|
772
|
+
iii console --port 3114 \
|
|
773
|
+
--engine-port 3111 \
|
|
774
|
+
--ws-port 3112 \
|
|
775
|
+
--bridge-port 49134
|
|
743
776
|
```
|
|
744
777
|
|
|
745
|
-
Then open `http://localhost:3114`.
|
|
746
|
-
|
|
747
778
|
**What you can do from the console:**
|
|
748
779
|
|
|
749
780
|
| Page | Use it to |
|
|
750
781
|
|------|-----------|
|
|
751
|
-
| **
|
|
752
|
-
| **
|
|
753
|
-
| **
|
|
754
|
-
| **
|
|
782
|
+
| **Workers** | See every connected worker and its live metrics — including the agentmemory worker itself. |
|
|
783
|
+
| **Functions** | Invoke any of agentmemory's functions directly with a JSON payload — handy for testing `memory.recall`, `memory.consolidate`, `graph.query` without wiring a client. |
|
|
784
|
+
| **Triggers** | Replay HTTP, cron, event, and state triggers — fire the consolidation cron manually, retry an HTTP route, emit a state change. |
|
|
785
|
+
| **States** | KV browser with full CRUD — sessions, memory slots, lifecycle timers, embeddings index — edit values in place. |
|
|
786
|
+
| **Streams** | Live WebSocket monitor for memory writes, hook events, and observation updates as they flow through iii streams. |
|
|
787
|
+
| **Queues** | Durable queue topics + dead-letter management. Replay or drop failed embedding / compression jobs. |
|
|
755
788
|
| **Traces** | OpenTelemetry waterfall / flame / service-breakdown views. Filter by `trace_id` to see exactly which functions, DB calls, and embedding requests a single `memory.search` produced. |
|
|
756
|
-
| **Logs** | Structured OTEL logs correlated to trace/span IDs. |
|
|
789
|
+
| **Logs** | Structured OTEL logs filtered and correlated to trace/span IDs. |
|
|
790
|
+
| **Config** | Runtime configuration — see exactly which workers, providers, and ports your engine is running with. |
|
|
791
|
+
| **Flow** | (Optional, `--enable-flow`) Interactive architecture graph of every worker, trigger, and stream. |
|
|
757
792
|
|
|
758
793
|
<p align="center">
|
|
759
794
|
<img src="assets/iii-console/traces-waterfall.png" alt="iii console trace waterfall view showing per-span duration" width="720" />
|
|
@@ -771,6 +806,53 @@ If you want to export to Jaeger/Honeycomb/Grafana Tempo instead, change `exporte
|
|
|
771
806
|
|
|
772
807
|
---
|
|
773
808
|
|
|
809
|
+
<h2 id="powered-by-iii"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/section-architecture.svg"><img src="assets/tags/section-architecture.svg" alt="Powered by iii" height="32" /></picture></h2>
|
|
810
|
+
|
|
811
|
+
agentmemory is **already a running [iii](https://iii.dev) instance**. Functions, triggers, KV state, streams, OTEL traces — all of it is iii primitives. You didn't install Postgres, Redis, Express, pm2, or Prometheus, because iii replaces them.
|
|
812
|
+
|
|
813
|
+
That means one more command extends agentmemory with an entire new capability.
|
|
814
|
+
|
|
815
|
+
### Extend agentmemory with one command
|
|
816
|
+
|
|
817
|
+
```bash
|
|
818
|
+
iii worker add iii-pubsub # fan memory writes out to every connected instance
|
|
819
|
+
iii worker add iii-cron # scheduled consolidation, decay sweeps, snapshot rotation
|
|
820
|
+
iii worker add iii-queue # durable retries for embedding + compression jobs
|
|
821
|
+
iii worker add iii-observability # OTEL traces on every memory op (default on)
|
|
822
|
+
iii worker add iii-sandbox # run recalled code inside an isolated microVM
|
|
823
|
+
iii worker add iii-database # swap in a SQL-backed state adapter
|
|
824
|
+
iii worker add mcp # generic MCP host alongside the agentmemory MCP
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
Each `iii worker add` registers new functions and triggers into the same engine agentmemory is already running on. The viewer and console pick them up immediately — no reload, no new integration, no new container.
|
|
828
|
+
|
|
829
|
+
| `iii worker add` | What you get on top of agentmemory |
|
|
830
|
+
|---|---|
|
|
831
|
+
| [`iii-pubsub`](https://workers.iii.dev/workers/iii-pubsub) | Multi-instance memory: every `remember` fans out, every `search` reads the union |
|
|
832
|
+
| [`iii-cron`](https://workers.iii.dev/workers/iii-cron) | Scheduled lifecycle — nightly consolidation, weekly snapshots, decay on a fixed clock |
|
|
833
|
+
| [`iii-queue`](https://workers.iii.dev/workers/iii-queue) | Durable retries: failed embedding + compression jobs survive restart, no lost observations |
|
|
834
|
+
| [`iii-observability`](https://workers.iii.dev/workers/iii-observability) | OTEL traces, metrics, logs on every function — wired in `iii-config.yaml` from day one |
|
|
835
|
+
| [`iii-sandbox`](https://workers.iii.dev/workers/iii-sandbox) | Code that came out of `memory_recall` runs inside a throwaway VM, not your shell |
|
|
836
|
+
| [`iii-database`](https://workers.iii.dev/workers/iii-database) | SQL-backed state adapter when you outgrow the in-memory KV defaults |
|
|
837
|
+
| [`mcp`](https://workers.iii.dev/workers/mcp) | Stand up extra MCP servers next to agentmemory's, share the same engine |
|
|
838
|
+
|
|
839
|
+
Full registry: [workers.iii.dev](https://workers.iii.dev). Every worker there composes through the same primitives agentmemory uses — and the agentmemory you already have is one of them.
|
|
840
|
+
|
|
841
|
+
### What iii replaces
|
|
842
|
+
|
|
843
|
+
| Traditional stack | agentmemory uses |
|
|
844
|
+
|---|---|
|
|
845
|
+
| Express.js / Fastify | iii HTTP Triggers |
|
|
846
|
+
| SQLite / Postgres + pgvector | iii KV State + in-memory vector index |
|
|
847
|
+
| SSE / Socket.io | iii Streams (WebSocket) |
|
|
848
|
+
| pm2 / systemd | iii engine worker supervision |
|
|
849
|
+
| Prometheus / Grafana | iii OTEL + health monitor |
|
|
850
|
+
| Custom plugin systems | `iii worker add <name>` |
|
|
851
|
+
|
|
852
|
+
**118 source files · ~21,800 LOC · 800 tests · 123 functions · 34 KV scopes** — all on three primitives. No `agentmemory plugin install`. The plugin system is iii itself.
|
|
853
|
+
|
|
854
|
+
---
|
|
855
|
+
|
|
774
856
|
<h2 id="configuration"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/section-config.svg"><img src="assets/tags/section-config.svg" alt="Configuration" height="32" /></picture></h2>
|
|
775
857
|
|
|
776
858
|
### LLM Providers
|
|
@@ -907,25 +989,6 @@ Full endpoint list: [`src/triggers/api.ts`](src/triggers/api.ts)
|
|
|
907
989
|
|
|
908
990
|
---
|
|
909
991
|
|
|
910
|
-
<h2 id="architecture"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/section-architecture.svg"><img src="assets/tags/section-architecture.svg" alt="Architecture" height="32" /></picture></h2>
|
|
911
|
-
|
|
912
|
-
Built on [iii-engine](https://iii.dev)'s three primitives — no Express, no Postgres, no Redis.
|
|
913
|
-
|
|
914
|
-
**118 source files · ~21,800 LOC · 800 tests · 123 functions · 34 KV scopes**
|
|
915
|
-
|
|
916
|
-
<details>
|
|
917
|
-
<summary>What iii-engine replaces</summary>
|
|
918
|
-
|
|
919
|
-
| Traditional stack | agentmemory uses |
|
|
920
|
-
|---|---|
|
|
921
|
-
| Express.js / Fastify | iii HTTP Triggers |
|
|
922
|
-
| SQLite / Postgres + pgvector | iii KV State + in-memory vector index |
|
|
923
|
-
| SSE / Socket.io | iii Streams (WebSocket) |
|
|
924
|
-
| pm2 / systemd | iii-engine worker management |
|
|
925
|
-
| Prometheus / Grafana | iii OTEL + health monitor |
|
|
926
|
-
|
|
927
|
-
</details>
|
|
928
|
-
|
|
929
992
|
<h2 id="development"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/section-development.svg"><img src="assets/tags/section-development.svg" alt="Development" height="32" /></picture></h2>
|
|
930
993
|
|
|
931
994
|
```bash
|
package/dist/cli.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, readlinkSync, statSync } from "node:fs";
|
|
4
4
|
import { delimiter, dirname, join } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { platform } from "node:os";
|
|
6
|
+
import { homedir, platform } from "node:os";
|
|
7
7
|
import * as p from "@clack/prompts";
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
9
|
|
|
@@ -81,6 +81,24 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
81
81
|
const args = process.argv.slice(2);
|
|
82
82
|
const IS_WINDOWS = platform() === "win32";
|
|
83
83
|
const IS_VERBOSE = args.includes("--verbose") || args.includes("-v");
|
|
84
|
+
const IIPINNED_VERSION = process.env["AGENTMEMORY_III_VERSION"] || "0.11.2";
|
|
85
|
+
function iiiReleaseAsset() {
|
|
86
|
+
const p = platform();
|
|
87
|
+
const a = process.arch;
|
|
88
|
+
if (p === "darwin" && a === "arm64") return "iii-aarch64-apple-darwin.tar.gz";
|
|
89
|
+
if (p === "darwin" && a === "x64") return "iii-x86_64-apple-darwin.tar.gz";
|
|
90
|
+
if (p === "linux" && a === "x64") return "iii-x86_64-unknown-linux-gnu.tar.gz";
|
|
91
|
+
if (p === "linux" && a === "arm64") return "iii-aarch64-unknown-linux-gnu.tar.gz";
|
|
92
|
+
if (p === "linux" && a === "arm") return "iii-armv7-unknown-linux-gnueabihf.tar.gz";
|
|
93
|
+
if (p === "win32" && a === "x64") return "iii-x86_64-pc-windows-msvc.zip";
|
|
94
|
+
if (p === "win32" && a === "arm64") return "iii-aarch64-pc-windows-msvc.zip";
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
function iiiReleaseUrl() {
|
|
98
|
+
const asset = iiiReleaseAsset();
|
|
99
|
+
if (!asset) return null;
|
|
100
|
+
return `https://github.com/iii-hq/iii/releases/download/iii/v${IIPINNED_VERSION}/${asset}`;
|
|
101
|
+
}
|
|
84
102
|
function vlog(msg) {
|
|
85
103
|
if (IS_VERBOSE) p.log.info(`[verbose] ${msg}`);
|
|
86
104
|
}
|
|
@@ -98,6 +116,8 @@ Commands:
|
|
|
98
116
|
upgrade Upgrade local deps + iii runtime (best effort)
|
|
99
117
|
mcp Start standalone MCP server (no engine required)
|
|
100
118
|
import-jsonl [p] Import Claude Code JSONL transcripts (default: ~/.claude/projects)
|
|
119
|
+
--max-files <N> | --max-files=<N>: override scan cap (default 200, max 1000;
|
|
120
|
+
out-of-range is rejected; for trees >1000 files, batch by subdirectory)
|
|
101
121
|
|
|
102
122
|
Options:
|
|
103
123
|
--help, -h Show this help
|
|
@@ -286,12 +306,13 @@ async function waitForEngine(timeoutMs) {
|
|
|
286
306
|
return false;
|
|
287
307
|
}
|
|
288
308
|
function installInstructions() {
|
|
309
|
+
const releaseUrl = iiiReleaseUrl();
|
|
289
310
|
if (IS_WINDOWS) return [
|
|
290
|
-
|
|
311
|
+
`agentmemory requires the \`iii-engine\` runtime, pinned to v${IIPINNED_VERSION}. Pick one:`,
|
|
291
312
|
"",
|
|
292
313
|
" A) Download the prebuilt Windows binary:",
|
|
293
|
-
|
|
294
|
-
|
|
314
|
+
` 1. Open https://github.com/iii-hq/iii/releases/tag/iii%2Fv${IIPINNED_VERSION}`,
|
|
315
|
+
` 2. Download iii-x86_64-pc-windows-msvc.zip`,
|
|
295
316
|
" (or iii-aarch64-pc-windows-msvc.zip on ARM)",
|
|
296
317
|
" 3. Extract iii.exe and either add its folder to PATH",
|
|
297
318
|
" or move it to %USERPROFILE%\\.local\\bin\\iii.exe",
|
|
@@ -299,24 +320,31 @@ function installInstructions() {
|
|
|
299
320
|
"",
|
|
300
321
|
" B) Docker Desktop:",
|
|
301
322
|
" 1. Install Docker Desktop for Windows",
|
|
302
|
-
|
|
303
|
-
" 3.
|
|
323
|
+
` 2. docker pull iiidev/iii:${IIPINNED_VERSION}`,
|
|
324
|
+
" 3. Start Docker Desktop (engine must be running)",
|
|
325
|
+
" 4. Re-run: npx @agentmemory/agentmemory",
|
|
304
326
|
"",
|
|
305
327
|
"Or skip the engine entirely for standalone MCP:",
|
|
306
328
|
" npx @agentmemory/agentmemory mcp"
|
|
307
329
|
];
|
|
330
|
+
const linuxInstall = releaseUrl ? ` A) mkdir -p ~/.local/bin && curl -fsSL "${releaseUrl}" | tar -xz -C ~/.local/bin && chmod +x ~/.local/bin/iii` : ` A) Manual download from https://github.com/iii-hq/iii/releases/tag/iii%2Fv${IIPINNED_VERSION}`;
|
|
308
331
|
return [
|
|
309
|
-
|
|
332
|
+
`agentmemory requires the \`iii-engine\` runtime, pinned to v${IIPINNED_VERSION}. Pick one:`,
|
|
310
333
|
"",
|
|
311
|
-
|
|
312
|
-
|
|
334
|
+
linuxInstall,
|
|
335
|
+
` (installs iii v${IIPINNED_VERSION} into ~/.local/bin/iii)`,
|
|
313
336
|
"",
|
|
314
|
-
|
|
337
|
+
` B) Docker: \`docker pull iiidev/iii:${IIPINNED_VERSION}\``,
|
|
315
338
|
"",
|
|
316
339
|
"Or skip the engine entirely for standalone MCP:",
|
|
317
340
|
" npx @agentmemory/agentmemory mcp",
|
|
318
341
|
"",
|
|
319
|
-
"Docs: https://iii.dev/docs"
|
|
342
|
+
"Docs: https://iii.dev/docs",
|
|
343
|
+
`Why pinned: iii v0.11.6 introduces the new sandbox-everything model`,
|
|
344
|
+
`(\`iii worker add\` registration). agentmemory still uses the older`,
|
|
345
|
+
`iii-exec config-file worker model and needs a refactor before it`,
|
|
346
|
+
`runs cleanly under the new engine. Override with`,
|
|
347
|
+
`AGENTMEMORY_III_VERSION=<version> when you've migrated manually.`
|
|
320
348
|
];
|
|
321
349
|
}
|
|
322
350
|
function portInUseDiagnostic(port) {
|
|
@@ -326,12 +354,12 @@ async function main() {
|
|
|
326
354
|
p.intro("agentmemory");
|
|
327
355
|
if (skipEngine) {
|
|
328
356
|
p.log.info("Skipping engine check (--no-engine)");
|
|
329
|
-
await import("./src-
|
|
357
|
+
await import("./src-xYHSzz5S.mjs");
|
|
330
358
|
return;
|
|
331
359
|
}
|
|
332
360
|
if (await isEngineRunning()) {
|
|
333
361
|
p.log.success("iii-engine is running");
|
|
334
|
-
await import("./src-
|
|
362
|
+
await import("./src-xYHSzz5S.mjs");
|
|
335
363
|
return;
|
|
336
364
|
}
|
|
337
365
|
if (!await startEngine()) {
|
|
@@ -375,7 +403,7 @@ async function main() {
|
|
|
375
403
|
process.exit(1);
|
|
376
404
|
}
|
|
377
405
|
s.stop("iii-engine is ready");
|
|
378
|
-
await import("./src-
|
|
406
|
+
await import("./src-xYHSzz5S.mjs");
|
|
379
407
|
}
|
|
380
408
|
async function apiFetch(base, path, timeoutMs = 5e3) {
|
|
381
409
|
try {
|
|
@@ -453,6 +481,42 @@ async function runStatus() {
|
|
|
453
481
|
function formatChecks(checks) {
|
|
454
482
|
return checks.map((c) => `${c.ok ? "✓" : "✗"} ${c.name}${c.hint ? `\n ${c.hint}` : ""}`).join("\n");
|
|
455
483
|
}
|
|
484
|
+
function findLatestDebugLog(debugDir) {
|
|
485
|
+
const latestLink = join(debugDir, "latest");
|
|
486
|
+
try {
|
|
487
|
+
if (existsSync(latestLink)) {
|
|
488
|
+
const target = readlinkSync(latestLink);
|
|
489
|
+
const resolved = target.startsWith("/") ? target : join(debugDir, target);
|
|
490
|
+
if (existsSync(resolved)) return resolved;
|
|
491
|
+
}
|
|
492
|
+
} catch {}
|
|
493
|
+
try {
|
|
494
|
+
const newest = readdirSync(debugDir).filter((f) => f.endsWith(".txt")).map((f) => ({
|
|
495
|
+
f,
|
|
496
|
+
m: statSync(join(debugDir, f)).mtimeMs
|
|
497
|
+
})).sort((a, b) => b.m - a.m)[0];
|
|
498
|
+
if (newest) return join(debugDir, newest.f);
|
|
499
|
+
} catch {}
|
|
500
|
+
}
|
|
501
|
+
function checkClaudeCodeHooks() {
|
|
502
|
+
const debugDir = join(homedir(), ".claude", "debug");
|
|
503
|
+
if (!existsSync(debugDir)) return { state: "no-cc-dir" };
|
|
504
|
+
const logPath = findLatestDebugLog(debugDir);
|
|
505
|
+
if (!logPath) return { state: "no-debug-log" };
|
|
506
|
+
let content;
|
|
507
|
+
try {
|
|
508
|
+
content = readFileSync(logPath, "utf8");
|
|
509
|
+
} catch {
|
|
510
|
+
return { state: "no-debug-log" };
|
|
511
|
+
}
|
|
512
|
+
const match = content.match(/Loaded hooks from standard location for plugin agentmemory:\s*(\S+)/);
|
|
513
|
+
if (match) return {
|
|
514
|
+
state: "loaded",
|
|
515
|
+
manifestPath: match[1]
|
|
516
|
+
};
|
|
517
|
+
if (content.includes("Loading hooks from plugin: agentmemory")) return { state: "loaded" };
|
|
518
|
+
return { state: "not-loaded" };
|
|
519
|
+
}
|
|
456
520
|
async function runDoctor() {
|
|
457
521
|
p.intro("agentmemory doctor");
|
|
458
522
|
const base = getBaseUrl();
|
|
@@ -499,6 +563,28 @@ async function runDoctor() {
|
|
|
499
563
|
ok: f.enabled,
|
|
500
564
|
hint: f.enabled ? void 0 : f.enableHow
|
|
501
565
|
});
|
|
566
|
+
const cc = checkClaudeCodeHooks();
|
|
567
|
+
const ccCheck = (() => {
|
|
568
|
+
switch (cc.state) {
|
|
569
|
+
case "loaded": return {
|
|
570
|
+
ok: true,
|
|
571
|
+
hint: cc.manifestPath ? `manifest: ${cc.manifestPath}` : void 0
|
|
572
|
+
};
|
|
573
|
+
case "not-loaded": return {
|
|
574
|
+
ok: false,
|
|
575
|
+
hint: "Plugin enabled but hooks not loaded by Claude Code. Try: /plugin uninstall agentmemory@agentmemory && /plugin install agentmemory@agentmemory, then restart the session. CC must be >= 2.1.x for plugin-hook auto-load."
|
|
576
|
+
};
|
|
577
|
+
case "no-debug-log": return {
|
|
578
|
+
ok: false,
|
|
579
|
+
hint: "Cannot verify — no Claude Code debug log found. Run once with `claude --debug -p \"x\"`, then re-run doctor."
|
|
580
|
+
};
|
|
581
|
+
case "no-cc-dir": return;
|
|
582
|
+
}
|
|
583
|
+
})();
|
|
584
|
+
if (ccCheck) checks.push({
|
|
585
|
+
name: "Claude Code plugin hooks registered",
|
|
586
|
+
...ccCheck
|
|
587
|
+
});
|
|
502
588
|
checks.push({
|
|
503
589
|
name: "Knowledge graph populated",
|
|
504
590
|
ok: graphHas,
|
|
@@ -600,6 +686,8 @@ async function seedDemoSession(base, project, session) {
|
|
|
600
686
|
const payload = {
|
|
601
687
|
hookType: "post_tool_use",
|
|
602
688
|
sessionId: session.id,
|
|
689
|
+
project,
|
|
690
|
+
cwd: project,
|
|
603
691
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
604
692
|
data: {
|
|
605
693
|
tool_name: obs.toolName,
|
|
@@ -744,14 +832,26 @@ async function runUpgrade() {
|
|
|
744
832
|
return process.exit(0);
|
|
745
833
|
}
|
|
746
834
|
if (upgradeEngine === true) {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
835
|
+
const releaseUrl = iiiReleaseUrl();
|
|
836
|
+
const asset = iiiReleaseAsset();
|
|
837
|
+
const isZipAsset = asset?.endsWith(".zip") === true;
|
|
838
|
+
if (!releaseUrl) p.log.warn(`iii-engine binary not available for ${platform()}/${process.arch}. Use Docker (\`docker pull iiidev/iii:${IIPINNED_VERSION}\`) or download manually from https://github.com/iii-hq/iii/releases/tag/iii%2Fv${IIPINNED_VERSION}.`);
|
|
839
|
+
else if (IS_WINDOWS || isZipAsset) p.log.info(`Skipping auto-install on ${platform()} — the ${asset} asset isn't tar-compatible. Install manually:\n 1. Download ${releaseUrl}\n 2. Extract iii.exe and place it on PATH (e.g. %USERPROFILE%\\.local\\bin)\nOr use Docker: docker pull iiidev/iii:${IIPINNED_VERSION}`);
|
|
840
|
+
else {
|
|
841
|
+
const binDir = join(homedir(), ".local", "bin");
|
|
842
|
+
if (!runCommand(shBin, ["-c", [
|
|
843
|
+
`mkdir -p "${binDir}"`,
|
|
844
|
+
`curl -fsSL "${releaseUrl}" | tar -xz -C "${binDir}"`,
|
|
845
|
+
`chmod +x "${binDir}/iii"`
|
|
846
|
+
].join(" && ")], {
|
|
847
|
+
label: `Installing iii-engine v${IIPINNED_VERSION} (pinned)`,
|
|
848
|
+
optional: true
|
|
849
|
+
})) p.log.warn(`iii-engine installer failed. Fallbacks: Docker (\`docker pull iiidev/iii:${IIPINNED_VERSION}\`) or download manually from https://github.com/iii-hq/iii/releases/tag/iii%2Fv${IIPINNED_VERSION}.`);
|
|
850
|
+
}
|
|
751
851
|
} else p.log.info("Skipped iii-engine installer.");
|
|
752
852
|
} else p.log.warn("curl or sh not found. Skipping iii-engine installer.");
|
|
753
|
-
if (dockerBin) runCommand(dockerBin, ["pull",
|
|
754
|
-
label:
|
|
853
|
+
if (dockerBin) runCommand(dockerBin, ["pull", `iiidev/iii:${IIPINNED_VERSION}`], {
|
|
854
|
+
label: `Pulling iii Docker image v${IIPINNED_VERSION} (pinned)`,
|
|
755
855
|
optional: true
|
|
756
856
|
});
|
|
757
857
|
else p.log.info("Docker not found. Skipping Docker image refresh.");
|
|
@@ -765,10 +865,38 @@ async function runUpgrade() {
|
|
|
765
865
|
].join("\n"), "agentmemory upgrade");
|
|
766
866
|
}
|
|
767
867
|
async function runMcp() {
|
|
768
|
-
await import("./standalone-
|
|
868
|
+
await import("./standalone-BvKacAId.mjs");
|
|
769
869
|
}
|
|
770
870
|
async function runImportJsonl() {
|
|
771
|
-
const
|
|
871
|
+
const VALUE_FLAGS = new Set(["--port", "--tools"]);
|
|
872
|
+
let maxFiles;
|
|
873
|
+
const tail = args.slice(1);
|
|
874
|
+
const positional = [];
|
|
875
|
+
for (let i = 0; i < tail.length; i++) {
|
|
876
|
+
const a = tail[i];
|
|
877
|
+
if (a === "--max-files") {
|
|
878
|
+
const raw = tail[i + 1];
|
|
879
|
+
const parsed = raw !== void 0 ? parseInt(raw, 10) : NaN;
|
|
880
|
+
if (Number.isInteger(parsed) && parsed > 0) maxFiles = parsed;
|
|
881
|
+
else if (raw !== void 0) p.log.warn(`Ignoring --max-files ${raw}: expected a positive integer.`);
|
|
882
|
+
i++;
|
|
883
|
+
continue;
|
|
884
|
+
}
|
|
885
|
+
if (a.startsWith("--max-files=")) {
|
|
886
|
+
const raw = a.slice(12);
|
|
887
|
+
const parsed = parseInt(raw, 10);
|
|
888
|
+
if (Number.isInteger(parsed) && parsed > 0) maxFiles = parsed;
|
|
889
|
+
else p.log.warn(`Ignoring --max-files=${raw}: expected a positive integer.`);
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
if (VALUE_FLAGS.has(a)) {
|
|
893
|
+
i++;
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
if (a.startsWith("-")) continue;
|
|
897
|
+
positional.push(a);
|
|
898
|
+
}
|
|
899
|
+
const pathArg = positional[0];
|
|
772
900
|
const port = getRestPort();
|
|
773
901
|
const base = `http://localhost:${port}`;
|
|
774
902
|
let probeOk = false;
|
|
@@ -790,6 +918,7 @@ async function runImportJsonl() {
|
|
|
790
918
|
}
|
|
791
919
|
const body = {};
|
|
792
920
|
if (pathArg) body["path"] = pathArg;
|
|
921
|
+
if (maxFiles !== void 0) body["maxFiles"] = maxFiles;
|
|
793
922
|
const headers = { "content-type": "application/json" };
|
|
794
923
|
const secret = process.env["AGENTMEMORY_SECRET"];
|
|
795
924
|
if (secret) headers["authorization"] = `Bearer ${secret}`;
|
|
@@ -821,6 +950,17 @@ async function runImportJsonl() {
|
|
|
821
950
|
process.exit(1);
|
|
822
951
|
}
|
|
823
952
|
spinner.stop(`imported ${json.imported ?? 0} file(s), ${json.observations ?? 0} observation(s) across ${json.sessionIds?.length || 0} session(s)`);
|
|
953
|
+
if (json.truncated) {
|
|
954
|
+
const cap = json.maxFiles ?? 200;
|
|
955
|
+
const upper = json.maxFilesUpperBound ?? 1e3;
|
|
956
|
+
const discovered = json.discovered ?? 0;
|
|
957
|
+
const baseMsg = `Hit the ${cap}-file scan cap; ${discovered - (json.imported ?? 0)} of ${json.traversalCapped ? `${discovered}+ (traversal halted at safety cap)` : String(discovered)} discovered file(s) were skipped.`;
|
|
958
|
+
if (discovered > upper || json.traversalCapped) p.log.warn(`${baseMsg} Tree exceeds the server's --max-files limit of ${upper}; batch by subdirectory (run import-jsonl once per project under ~/.claude/projects).`);
|
|
959
|
+
else {
|
|
960
|
+
const suggested = Math.min(Math.max((discovered || cap) + 100, cap * 2), upper);
|
|
961
|
+
p.log.warn(`${baseMsg} Re-run with --max-files=${suggested} (max ${upper}) or batch by subdirectory.`);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
824
964
|
if (json.sessionIds && json.sessionIds.length > 0) p.log.info(`View at ${getViewerUrl()} → Replay tab`);
|
|
825
965
|
} catch (err) {
|
|
826
966
|
spinner.stop("failed");
|