From 3cd434f33fcc195b4f68f9cbb19876c901c76fca Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Sun, 7 Jun 2026 11:39:10 +0100 Subject: [PATCH 1/5] fix(mcp): correct tool-count drift and add count-consistency guard Correct stale 51-tool references to the registry truth of 53 across the standalone shim comments and the registry comment, derive the visible tool count from the registry, update README test-count stats to 1,423+, add the demo --serve README line, and add a vitest guard that fails CI if the registry count, README, or CLI help drift out of sync. --- README.md | 7 +++-- src/mcp/standalone.ts | 5 ++-- src/mcp/tools-registry.ts | 8 +++--- test/tool-count-consistency.test.ts | 43 +++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 test/tool-count-consistency.test.ts diff --git a/README.md b/README.md index 87e6b3f0d..30483919b 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ 53 MCP tools 12 auto hooks 0 external DBs - 1,390+ tests passing + 1,423+ tests passing

@@ -93,6 +93,7 @@ npm install -g @agentmemory/agentmemory # once — bare `agentmemory` o # sudo npm install -g @agentmemory/agentmemory agentmemory # start the memory server on :3111 agentmemory demo # seed sample sessions + prove recall +agentmemory demo --serve # one command: boot server, run demo, tear down (no second terminal) agentmemory connect claude-code # wire MCP into your agent (also: copilot-cli, codex, cursor, gemini-cli, ...) npx skills add rohitg00/agentmemory -y # install 8 native skills so your agent knows when to use the tools ``` @@ -1141,7 +1142,7 @@ Full registry: [workers.iii.dev](https://workers.iii.dev). Every worker there co | Prometheus / Grafana | iii OTEL + health monitor | | Custom plugin systems | `iii worker add ` | -**174 source files · ~37,800 LOC · 1,390+ tests · 258 functions · 44 KV scopes** — all on three primitives. No `agentmemory plugin install`. The plugin system is iii itself. +**174 source files · ~37,800 LOC · 1,423+ tests · 258 functions · 44 KV scopes** — all on three primitives. No `agentmemory plugin install`. The plugin system is iii itself. --- @@ -1465,7 +1466,7 @@ Full endpoint list: [`src/triggers/api.ts`](src/triggers/api.ts) ```bash npm run dev # Hot reload npm run build # Production build -npm test # 1,390+ tests +npm test # 1,423+ tests npm run test:integration # API tests (requires running services) ``` diff --git a/src/mcp/standalone.ts b/src/mcp/standalone.ts index f4683747f..dd66ecb1d 100644 --- a/src/mcp/standalone.ts +++ b/src/mcp/standalone.ts @@ -51,8 +51,9 @@ function announceMode(handle: Handle): void { `[@agentmemory/mcp] proxying to agentmemory server at ${handle.baseUrl}\n`, ); } else { + const fullToolCount = getAllTools().length; process.stderr.write( - `[@agentmemory/mcp] no server reachable at ${displayAgentmemoryUrl()}; falling back to local InMemoryKV\n`, + `[@agentmemory/mcp] no server reachable at ${displayAgentmemoryUrl()}; running reduced LOCAL FALLBACK with ${IMPLEMENTED_TOOLS.size} of ${fullToolCount} tools. Start 'npx @agentmemory/agentmemory' (and point AGENTMEMORY_URL at it) to unlock all ${fullToolCount} tools.\n`, ); } } @@ -338,7 +339,7 @@ async function handleProxyGeneric( handle: ProxyHandle, ): Promise<{ content: Array<{ type: string; text: string }> }> { // Forward to the server's full MCP surface so non-Claude clients can - // reach all 51 tools (lessons, sentinels, slots, signals, graph, …) + // reach all 53 tools (lessons, sentinels, slots, signals, graph, …) // instead of being capped at the 7 IMPLEMENTED_TOOLS set baked into // this shim. The server validates arguments per tool. const result = (await handle.call("/agentmemory/mcp/call", { diff --git a/src/mcp/tools-registry.ts b/src/mcp/tools-registry.ts index c86d899bb..c4df3499c 100644 --- a/src/mcp/tools-registry.ts +++ b/src/mcp/tools-registry.ts @@ -925,7 +925,7 @@ export const V010_SLOTS_TOOLS: McpToolDef[] = [ }, ]; -const ESSENTIAL_TOOLS = new Set([ +export const ESSENTIAL_TOOLS = new Set([ "memory_save", "memory_recall", "memory_consolidate", @@ -950,9 +950,9 @@ export function getAllTools(): McpToolDef[] { } // default switched from "core" (8 essential tools) to "all" -// (full 51-tool surface). README and plugin manifests have always -// advertised 51 tools "in proxy mode"; the old default left OpenCode / -// Claude Code users seeing 8 with no indication the other 43 existed. +// (full 53-tool surface). README and plugin manifests have always +// advertised 53 tools "in proxy mode"; the old default left OpenCode / +// Claude Code users seeing 8 with no indication the other tools existed. // Users who want the lean essentials can still set AGENTMEMORY_TOOLS=core. export function getVisibleTools(): McpToolDef[] { const mode = process.env["AGENTMEMORY_TOOLS"] || "all"; diff --git a/test/tool-count-consistency.test.ts b/test/tool-count-consistency.test.ts new file mode 100644 index 000000000..19f0e3a5e --- /dev/null +++ b/test/tool-count-consistency.test.ts @@ -0,0 +1,43 @@ +import { describe, it, expect, vi } from "vitest"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +vi.mock("../src/logger.js", () => ({ + logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() }, +})); + +import { getAllTools, ESSENTIAL_TOOLS } from "../src/mcp/tools-registry.js"; + +const ROOT = join(import.meta.dirname, ".."); +const EXPECTED_TOOL_COUNT = 53; + +function readText(relativePath: string): string { + return readFileSync(join(ROOT, relativePath), "utf-8"); +} + +describe("Tool count consistency", () => { + it("registry exposes the expected number of tools", () => { + expect(getAllTools().length).toBe(EXPECTED_TOOL_COUNT); + }); + + it("cli help derives the tool counts from the registry", () => { + const cli = readText("src/cli.ts"); + expect(cli).toContain("const ALL_TOOLS_COUNT = getAllTools().length;"); + expect(cli).toContain( + "(default: all = ${ALL_TOOLS_COUNT} tools; core = ${CORE_TOOLS_COUNT} essentials)", + ); + expect(cli).not.toMatch(/all\s*=\s*51 tools/); + }); + + it("core tool count derives from the registry", () => { + const coreCount = getAllTools().filter((t) => ESSENTIAL_TOOLS.has(t.name)).length; + expect(coreCount).toBe(ESSENTIAL_TOOLS.size); + expect(coreCount).toBeGreaterThan(0); + }); + + it("README advertises the same tool count as the registry", () => { + const readme = readText("README.md"); + expect(readme).toContain(`${EXPECTED_TOOL_COUNT} MCP tools`); + expect(readme).not.toContain("51 MCP tools"); + }); +}); From 87964c3341f07cf4765e0a58ebfc00291eff786e Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Sun, 7 Jun 2026 11:39:16 +0100 Subject: [PATCH 2/5] fix(cli): relax engine version gate and add demo --serve one-shot Convert the hard process.exit on a PATH iii version mismatch into a non-fatal warning so a mismatched iii on PATH no longer blocks first run; agentmemory continues with its own pinned engine in ~/.agentmemory/bin and honors AGENTMEMORY_III_VERSION. Add a --serve flag to the demo subcommand that boots the server, waits for health, runs the seed and query demo, and tears the server down on exit, all in one invocation. Derive the --tools help counts from the registry. --- src/cli.ts | 83 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index acac3d971..c6087d891 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -43,6 +43,10 @@ import { isFirstRun, readPrefs, resetPrefs, writePrefs } from "./cli/preferences import { runOnboarding } from "./cli/onboarding.js"; import { setBootVerbose } from "./logger.js"; import { VERSION } from "./version.js"; +import { getAllTools, ESSENTIAL_TOOLS } from "./mcp/tools-registry.js"; + +const ALL_TOOLS_COUNT = getAllTools().length; +const CORE_TOOLS_COUNT = getAllTools().filter((t) => ESSENTIAL_TOOLS.has(t.name)).length; const __dirname = dirname(fileURLToPath(import.meta.url)); const args = process.argv.slice(2); @@ -136,7 +140,9 @@ Commands: --dry-run: show what each fix would do, don't execute remove Cleanly uninstall agentmemory (pidfile, state, .env, binaries). --force: skip confirmations · --keep-data: keep memory data - demo Seed sample sessions and show recall in action + demo [--serve] Seed sample sessions and show recall in action. + --serve boots the server, runs the demo, and stops it + in one command (no second terminal). upgrade Upgrade local deps + iii runtime (best effort) stop [--force] Stop the running iii-engine started by this CLI. --force bypasses the Docker-heuristic guard and signals @@ -152,7 +158,7 @@ Options: --help, -h Show this help --verbose, -v Show engine stderr, boot log, and diagnostic info --reset Wipe ~/.agentmemory/preferences.json and re-run onboarding - --tools all|core Tool visibility (default: all = 51 tools; core = 8 essentials) + --tools all|core Tool visibility (default: all = ${ALL_TOOLS_COUNT} tools; core = ${CORE_TOOLS_COUNT} essentials) --no-engine Skip auto-starting iii-engine --port Override REST port (default: 3111). Streams (N+1), viewer (N+2), and iii engine (N+46023) auto-derive from N so a @@ -1197,15 +1203,11 @@ async function main() { if (attachedBin) { const detected = iiiBinVersion(attachedBin); if (detected && detected !== IIPINNED_VERSION) { - p.log.error( - `Attached iii-engine appears to be v${detected} (from ${attachedBin}) ` + - `but agentmemory v${VERSION} hard-pins v${IIPINNED_VERSION}. ` + - `Engine API drift causes runtime failures (e.g. state::list-not-found on v0.13.0+). ` + - `Stop the running engine (\`agentmemory stop --force\`) and re-run \`agentmemory\` ` + - `to install the pinned engine into ~/.agentmemory/bin without touching ${attachedBin}. ` + - `Or set AGENTMEMORY_III_VERSION=${detected} to override at your own risk.`, + p.log.warn( + `iii on PATH is v${detected} (from ${attachedBin}) but agentmemory v${VERSION} pins v${IIPINNED_VERSION}. ` + + `agentmemory will use its own pinned engine in ~/.agentmemory/bin and leaves ${attachedBin} untouched. ` + + `If you want agentmemory to track a different engine, set AGENTMEMORY_III_VERSION=${detected}.`, ); - process.exit(1); } } adoptRunningEngine(); @@ -2100,19 +2102,78 @@ async function runInit() { p.outro(`Edit ${target} and you're set.`); } +async function startServerForDemo(): Promise<() => Promise> { + if (await isAgentmemoryReady()) { + return async () => {}; + } + + const startedEngine = !(await isEngineRunning()); + if (startedEngine) { + const ok = await startEngine(); + if (!ok) { + p.log.error("Could not start iii-engine for the demo."); + p.note(installInstructions().join("\n"), "Setup required"); + process.exit(1); + } + if (!(await waitForEngine(15000))) { + p.log.error("iii-engine did not become ready within 15s."); + process.exit(1); + } + } + + await import("./index.js"); + if (!(await waitForAgentmemoryReady(15000))) { + p.log.error("agentmemory worker did not become ready within 15s."); + process.exit(1); + } + + return async () => { + if (!startedEngine) return; + const port = getRestPort(); + const state = readEngineState(); + if (state?.kind === "docker") { + await stopDockerEngine(state.composeFile, port).catch(() => {}); + return; + } + const pids = new Set(findEnginePidsByPort(port)); + const pidfilePid = readEnginePidfile(); + if (pidfilePid) pids.add(pidfilePid); + for (const pid of pids) { + await signalAndWait(pid, "SIGTERM", 3000).catch(() => {}); + } + clearEnginePidfile(); + clearEngineState(); + clearWorkerPidfile(); + }; +} + async function runDemo() { const port = getRestPort(); const base = `http://localhost:${port}`; p.intro("agentmemory demo"); - if (!(await isAgentmemoryReady())) { + const serve = args.includes("--serve"); + let teardown: () => Promise = async () => {}; + + if (serve) { + teardown = await startServerForDemo(); + } else if (!(await isAgentmemoryReady())) { p.log.error( `agentmemory worker not reachable on port ${port} (livez probe failed). Something may be on the port but it isn't serving /agentmemory/*.`, ); p.log.info("Start it with: npx @agentmemory/agentmemory"); + p.log.info("Or run a one-command demo with: npx @agentmemory/agentmemory demo --serve"); process.exit(1); } + try { + await runDemoBody(base); + } finally { + await teardown(); + } +} + +async function runDemoBody(base: string) { const demoProject = "/tmp/agentmemory-demo"; const sessions = buildDemoSessions(); From 7189096ed4d6f134c38a98dddcf64f46f51a3199 Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Sun, 7 Jun 2026 12:09:26 +0100 Subject: [PATCH 3/5] fix(cli): exit cleanly after demo --serve so in-process worker stops --- src/cli.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cli.ts b/src/cli.ts index c6087d891..ae5be0035 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -2171,6 +2171,10 @@ async function runDemo() { } finally { await teardown(); } + + if (serve) { + process.exit(0); + } } async function runDemoBody(base: string) { From 88fc07b2ab707e581ff4d7fd8a7ef5c1f01aa3b1 Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Sun, 7 Jun 2026 11:43:56 +0100 Subject: [PATCH 4/5] feat: agent install runbook, windows clarity, onboarding prompts Add INSTALL_FOR_AGENTS.md, a runbook a coding agent can execute end to end: global install, start server, demo --serve, connect MCP, install skills, and a save/recall verification round-trip. README Install section now leads with the agent one-liner path and a short Windows callout (WSL2 is the fast path, native setup is manual and connect is unsupported there). Onboarding gains a context-injection step that asks whether to enable AGENTMEMORY_INJECT_CONTEXT with a token-cost note, persists the choice as a never-nag prefs flag, and writes the env var when enabled. Provider selection prints a one-line rough cost hint. --- INSTALL_FOR_AGENTS.md | 88 ++++++++++++++++++++++++++++++++++++++++++ README.md | 6 +++ src/cli/onboarding.ts | 68 +++++++++++++++++++++++++++++++- src/cli/preferences.ts | 6 +++ 4 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 INSTALL_FOR_AGENTS.md diff --git a/INSTALL_FOR_AGENTS.md b/INSTALL_FOR_AGENTS.md new file mode 100644 index 000000000..6d6cf7e9f --- /dev/null +++ b/INSTALL_FOR_AGENTS.md @@ -0,0 +1,88 @@ +# Install agentmemory (agent runbook) + +You are a coding agent. Follow these steps in order to install agentmemory, wire it into yourself, and verify that persistent memory works. Run each command, check the result, then move to the next step. Stop and report if any step fails. + +## 1. Install globally + +```bash +npm install -g @agentmemory/agentmemory +``` + +If you hit `EACCES` on a system Node install (macOS/Linux), retry with `sudo npm install -g @agentmemory/agentmemory`. + +No-install alternative (skips step 1, run the server with npx in step 2): + +```bash +npx -y @agentmemory/agentmemory@latest +``` + +## 2. Start the server + +Start the memory server. It listens on port 3111. Run it in the background or in a separate terminal so the rest of the steps can talk to it. + +```bash +agentmemory +``` + +If you installed via npx in step 1, run `npx -y @agentmemory/agentmemory@latest` here instead. + +## 3. Prove it works + +```bash +agentmemory demo --serve +``` + +This boots the server, seeds sample sessions, proves recall, and tears down in one command. No second terminal needed. + +## 4. Wire MCP into the calling agent + +Detect which agent is running this runbook, then wire its MCP config: + +```bash +agentmemory connect +``` + +Supported agent names: `claude-code`, `copilot-cli`, `codex`, `cursor`, `gemini-cli`, `opencode`, `cline`, `continue`, `droid`, `hermes`, `openclaw`, `openhuman`, `pi`, `qwen`, `warp`, `zed`, `antigravity`, `kiro`. + +If you cannot tell which agent you are, default to `claude-code`. Restart the agent (or run its MCP reload command) after wiring so it picks up the server. + +## 5. Install native skills + +```bash +npx skills add rohitg00/agentmemory -y +``` + +This installs the native skills so the agent knows when to call the memory functions. + +## 6. Verify a save and recall round-trip + +First confirm the server is healthy: + +```bash +curl http://localhost:3111/agentmemory/health +``` + +Expect a JSON body with an ok status. Then run a save and recall round-trip. If MCP is wired, call the `memory_save` function followed by `memory_smart_search`. Otherwise use REST directly: + +```bash +curl -X POST http://localhost:3111/agentmemory/memory_save \ + -H "Content-Type: application/json" \ + -d '{"content":"agentmemory install verification probe","tags":["install-check"]}' + +curl -X POST http://localhost:3111/agentmemory/memory_smart_search \ + -H "Content-Type: application/json" \ + -d '{"query":"install verification probe"}' +``` + +The search response should contain the memory you just saved. + +## 7. Report success + +Report back to the user: + +- agentmemory installed and the server is running on port 3111 +- which agent was wired via `agentmemory connect` +- the save and recall round-trip returned the probe memory +- the viewer is available at http://localhost:3113 + +If any step failed, report which step, the exact command, and the error output. diff --git a/README.md b/README.md index 30483919b..c5acc3595 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,12 @@ ## Install +Fastest path if you use a coding agent: hand it this one instruction and it installs, wires, and verifies agentmemory end to end. + +> Retrieve and follow the instructions at: https://raw.githubusercontent.com/rohitg00/agentmemory/main/INSTALL_FOR_AGENTS.md + +On Windows the fast path is WSL2. Native Windows engine setup is manual (about 10 to 20 minutes) and `agentmemory connect` is currently unsupported there. See the [Windows notes](#windows) below for the step-by-step. + ```bash npm install -g @agentmemory/agentmemory # once — bare `agentmemory` on PATH # If you hit EACCES on macOS/Linux system Node installs, retry with: diff --git a/src/cli/onboarding.ts b/src/cli/onboarding.ts index 2e148a1bf..cd0f7c824 100644 --- a/src/cli/onboarding.ts +++ b/src/cli/onboarding.ts @@ -25,7 +25,8 @@ import { homedir } from "node:os"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import * as p from "@clack/prompts"; -import { writePrefs } from "./preferences.js"; +import { appendFileSync, readFileSync } from "node:fs"; +import { readPrefs, writePrefs } from "./preferences.js"; import { resolveAdapter, runAdapter } from "./connect/index.js"; import type { ConnectResult } from "./connect/types.js"; @@ -68,6 +69,14 @@ const PROVIDERS: { value: string; label: string; envKey: string | null }[] = [ { value: "skip", label: "Skip — BM25-only mode (no LLM key)", envKey: null }, ]; +const PROVIDER_COST_HINTS: Record = { + anthropic: "rough cost: a fast Haiku-class model keeps compress/consolidate at fractions of a cent per session.", + openai: "rough cost: a mini-class model keeps compress/consolidate at fractions of a cent per session.", + gemini: "rough cost: a Flash-class model keeps compress/consolidate at fractions of a cent per session.", + openrouter: "rough cost: pick a small model; spend tracks your chosen model's per-token price.", + minimax: "rough cost: scales with the MiniMax model price per token.", +}; + export function buildAgentOptions(): { value: string; label: string; hint?: string }[] { return [ ...NATIVE_AGENTS.map((a) => ({ @@ -219,8 +228,17 @@ export async function runOnboarding(): Promise { const provider = providerPicked === "skip" ? null : providerPicked; const agents = (agentsPicked as string[]) ?? []; + if (provider) { + const hint = PROVIDER_COST_HINTS[provider]; + if (hint) { + p.log.info(hint); + } + } + const envPath = await seedEnvFile(provider); + await maybePromptContextInjection(envPath); + writePrefs({ lastAgent: agents[0] ?? null, lastAgents: agents, @@ -253,6 +271,54 @@ export async function runOnboarding(): Promise { return { agents, provider }; } +function enableInjectContextInEnv(envPath: string | null): boolean { + if (!envPath || !existsSync(envPath)) return false; + try { + const current = readFileSync(envPath, "utf-8"); + if (/^\s*AGENTMEMORY_INJECT_CONTEXT\s*=\s*true\b/m.test(current)) { + return true; + } + const prefix = current.length > 0 && !current.endsWith("\n") ? "\n" : ""; + appendFileSync(envPath, `${prefix}AGENTMEMORY_INJECT_CONTEXT=true\n`, { mode: 0o600 }); + return true; + } catch { + return false; + } +} + +async function maybePromptContextInjection(envPath: string | null): Promise { + if (readPrefs().injectContextChosen) return; + + const enable = await p.confirm({ + message: "Enable automatic context injection so the agent recalls past sessions without being asked? [y/N]", + initialValue: false, + }); + + if (p.isCancel(enable)) { + p.cancel("Setup cancelled. Re-run any time with: agentmemory --reset"); + process.exit(0); + } + + p.log.info( + "Cost note: injection spends session tokens proportional to tool-call frequency. Default is off.", + ); + + writePrefs({ injectContextChosen: true }); + + if (enable === true) { + const wrote = enableInjectContextInEnv(envPath); + if (wrote) { + p.log.success("Context injection enabled (AGENTMEMORY_INJECT_CONTEXT=true)."); + } else { + p.log.warn( + "Could not update ~/.agentmemory/.env. Set AGENTMEMORY_INJECT_CONTEXT=true there to enable it.", + ); + } + } else { + p.log.info("Context injection left off. Set AGENTMEMORY_INJECT_CONTEXT=true later to enable."); + } +} + async function wireSelectedAgents(agents: string[]): Promise { p.note("Wire selected agents now?", "next step"); const confirmed = await p.confirm({ diff --git a/src/cli/preferences.ts b/src/cli/preferences.ts index ccebd1a31..63695db62 100644 --- a/src/cli/preferences.ts +++ b/src/cli/preferences.ts @@ -57,6 +57,11 @@ export interface Prefs { // never updated, so we can show "you joined agentmemory N days ago" // copy in /status later without keeping a separate file. firstRunAt: string | null; + // Set to true once the user has answered the context-injection prompt + // (either way). We never re-ask after this so the prompt stays a + // one-time choice, matching the skipGlobalInstall / skipConsoleInstall + // never-nag pattern. + injectContextChosen: boolean; } const DEFAULTS: Prefs = { @@ -69,6 +74,7 @@ const DEFAULTS: Prefs = { skipGlobalInstall: false, skipConsoleInstall: false, firstRunAt: null, + injectContextChosen: false, }; export function prefsDir(): string { From 30e64ee0b2ac26181f0e37c9a5b7a0c184e6044e Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Sun, 7 Jun 2026 12:13:07 +0100 Subject: [PATCH 5/5] docs: expand agent install runbook with prereqs, REST shapes, troubleshooting --- INSTALL_FOR_AGENTS.md | 129 +++++++++++++++++++++++++++++++++--------- 1 file changed, 102 insertions(+), 27 deletions(-) diff --git a/INSTALL_FOR_AGENTS.md b/INSTALL_FOR_AGENTS.md index 6d6cf7e9f..b7df56565 100644 --- a/INSTALL_FOR_AGENTS.md +++ b/INSTALL_FOR_AGENTS.md @@ -1,6 +1,22 @@ # Install agentmemory (agent runbook) -You are a coding agent. Follow these steps in order to install agentmemory, wire it into yourself, and verify that persistent memory works. Run each command, check the result, then move to the next step. Stop and report if any step fails. +You are a coding agent. Follow this runbook top to bottom to install agentmemory, wire it into yourself, and verify that persistent memory works. Run each command, check the result against the "Expect" note, then move on. If a step fails, jump to Troubleshooting, and if it still fails, stop and report the step, the exact command, and the error output. + +## What you are installing + +agentmemory is a local memory server for coding agents. It runs on your machine, exposes a REST API on port 3111 and an MCP server, and stores memories on disk under `~/.agentmemory`. It is built on the iii engine, which agentmemory downloads and manages for you as a pinned binary under `~/.agentmemory/bin`. You do not install iii separately. + +Default mode needs no API key and no cloud account. Out of the box it runs hybrid retrieval (BM25 keyword search plus local on-device embeddings), so a full install proves real semantic recall with zero credentials. An LLM provider key is optional and only unlocks richer summaries and auto-injection (see "Optional: richer features"). + +## Prerequisites + +- Node.js >= 20 and npm. Check with `node -v`. +- macOS or Linux for the one-command path. On Windows, use WSL2; native Windows engine setup is manual and `agentmemory connect` is not supported there. +- Ports 3111 (REST), 3112 (streams), 3113 (viewer), and 49134 (engine) free. Override the whole block with `--port ` or `--instance ` if any are taken. + +## Running non-interactively + +Several commands prompt on a TTY (for example the first-run "install globally?" question). As an agent you usually want no prompts. Either set `CI=1` in the environment for the commands below, or rely on the fact that agentmemory skips all prompts automatically when stdin/stdout are not a TTY. Prompts are also never-nag: once answered they persist and are not asked again. Re-run onboarding any time with `agentmemory --reset`. ## 1. Install globally @@ -10,31 +26,47 @@ npm install -g @agentmemory/agentmemory If you hit `EACCES` on a system Node install (macOS/Linux), retry with `sudo npm install -g @agentmemory/agentmemory`. -No-install alternative (skips step 1, run the server with npx in step 2): +No-install alternative: skip this step and run the server with `npx -y @agentmemory/agentmemory@latest` everywhere this runbook says `agentmemory`. The `@latest` and `-y` flags matter because npx caches per version and a bare `npx @agentmemory/agentmemory` can serve a stale release. + +Expect: the install completes without errors. + +## 2. Verify the install + +```bash +agentmemory --version +``` + +Expect: a version string is printed. If `command not found`, the global bin is not on `PATH`; use the `npx -y @agentmemory/agentmemory@latest` form instead. + +## 3. Start the server + +The server listens on port 3111 and auto-starts its pinned iii engine on first run (this can take a few seconds the first time while the engine binary is fetched into `~/.agentmemory/bin`). Run it in the background or in a separate terminal so the rest of the runbook can talk to it. ```bash -npx -y @agentmemory/agentmemory@latest +agentmemory & ``` -## 2. Start the server +Or in a dedicated terminal, run `agentmemory` in the foreground. To run a second isolated instance, use `agentmemory --instance 1` (relocates the whole port block to 3211/3212/3213/49234). -Start the memory server. It listens on port 3111. Run it in the background or in a separate terminal so the rest of the steps can talk to it. +Wait until it is reachable, then continue: ```bash -agentmemory +curl -fsS http://localhost:3111/agentmemory/livez ``` -If you installed via npx in step 1, run `npx -y @agentmemory/agentmemory@latest` here instead. +Expect: a `200` response. Retry for up to ~15 seconds on first run while the engine warms up. -## 3. Prove it works +## 4. Prove recall in one command ```bash agentmemory demo --serve ``` -This boots the server, seeds sample sessions, proves recall, and tears down in one command. No second terminal needed. +`--serve` boots the server, seeds three realistic sessions (JWT auth, an N+1 query fix, rate limiting), runs semantic searches against them, prints the results, and tears everything down. No second terminal needed. -## 4. Wire MCP into the calling agent +Expect: the demo finds the "N+1 query fix" memory when it searches for "database performance optimization", which keyword matching alone cannot do. Open `http://localhost:3113` while it runs to watch the memory build live. + +## 5. Wire MCP into the calling agent Detect which agent is running this runbook, then wire its MCP config: @@ -42,47 +74,90 @@ Detect which agent is running this runbook, then wire its MCP config: agentmemory connect ``` -Supported agent names: `claude-code`, `copilot-cli`, `codex`, `cursor`, `gemini-cli`, `opencode`, `cline`, `continue`, `droid`, `hermes`, `openclaw`, `openhuman`, `pi`, `qwen`, `warp`, `zed`, `antigravity`, `kiro`. +`connect` merges agentmemory into that agent's MCP config and preserves any existing servers. Supported agent names: + +`claude-code`, `copilot-cli`, `codex`, `cursor`, `gemini-cli`, `opencode`, `cline`, `continue`, `droid`, `hermes`, `openclaw`, `openhuman`, `pi`, `qwen`, `warp`, `zed`, `antigravity`, `kiro`. -If you cannot tell which agent you are, default to `claude-code`. Restart the agent (or run its MCP reload command) after wiring so it picks up the server. +If you cannot tell which agent you are, default to `claude-code`. After wiring, restart the agent or run its MCP reload command (for example `/mcp` in Claude Code) so it picks up the server. -## 5. Install native skills +Expect: the agent now lists agentmemory's tools. With the server running you should see the full set of 53 tools (for example `memory_save`, `memory_smart_search`, `memory_sessions`). If you see only 7 tools, the MCP shim could not reach a server, see Troubleshooting. + +## 6. Install native skills ```bash npx skills add rohitg00/agentmemory -y ``` -This installs the native skills so the agent knows when to call the memory functions. +This installs the native skills so the agent knows when to call the memory tools, not just that they exist. `connect` makes the tools available; skills teach the agent when to use them. + +Expect: the skills are installed for the detected agent. -## 6. Verify a save and recall round-trip +## 7. Verify a save and recall round-trip -First confirm the server is healthy: +Confirm health first: ```bash -curl http://localhost:3111/agentmemory/health +curl -fsS http://localhost:3111/agentmemory/health ``` -Expect a JSON body with an ok status. Then run a save and recall round-trip. If MCP is wired, call the `memory_save` function followed by `memory_smart_search`. Otherwise use REST directly: +Expect: a JSON body with an ok status. + +Now write a memory and read it back. If MCP is wired, call the `memory_save` tool followed by `memory_smart_search`. Otherwise use REST directly (note: these are the REST paths, which differ from the MCP tool names): ```bash -curl -X POST http://localhost:3111/agentmemory/memory_save \ +curl -X POST http://localhost:3111/agentmemory/remember \ -H "Content-Type: application/json" \ - -d '{"content":"agentmemory install verification probe","tags":["install-check"]}' + -d '{"content":"agentmemory install verification probe","concepts":["install-check"]}' -curl -X POST http://localhost:3111/agentmemory/memory_smart_search \ +curl -X POST http://localhost:3111/agentmemory/smart-search \ -H "Content-Type: application/json" \ - -d '{"query":"install verification probe"}' + -d '{"query":"install verification probe","limit":5}' ``` -The search response should contain the memory you just saved. +Expect: the first call returns `201`, the second returns `200` with results that include the probe memory you just saved. + +If `AGENTMEMORY_SECRET` is set in the environment, the REST API requires it. Add `-H "Authorization: Bearer $AGENTMEMORY_SECRET"` to both calls. By default no secret is set and localhost is open. + +## Optional: richer features + +These are off by default because they spend tokens. Enable them only if the user wants them. Put configuration in `~/.agentmemory/.env` (no `export` prefix), then restart the server. + +- `AGENTMEMORY_INJECT_CONTEXT=true` makes the SessionStart and PreToolUse hooks inject past memory into the agent's context automatically. Cost: spends session tokens proportional to tool-call frequency. +- `AGENTMEMORY_AUTO_COMPRESS=true` sends each observation to your LLM provider for a richer summary. Cost: spends API tokens proportional to tool-use frequency. Requires a provider key. +- Provider key: set one of `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, and similar, in the same file. Without a key, agentmemory stays in zero-LLM mode and still indexes and recalls via BM25 plus local embeddings. + +## Tool surface + +The MCP server exposes 53 tools by default (`--tools all`). Use `--tools core` (or `AGENTMEMORY_TOOLS=core`) for a lean 8-tool set on hosts with tight tool limits. The 8 core tools cover save, recall, smart search, sessions, export, audit, and governance delete. + +## Lifecycle commands + +- `agentmemory status` shows server and engine state. +- `agentmemory doctor` runs diagnostics and reports what is misconfigured. +- `agentmemory stop` stops the engine this CLI started (`stop --force` bypasses the Docker guard). +- `agentmemory upgrade` upgrades agentmemory and the iii runtime, best effort. +- `agentmemory --reset` wipes onboarding preferences and re-runs the wizard. +- `agentmemory import-jsonl ` imports prior Claude Code session logs as memories. + +## Troubleshooting + +- `command not found: agentmemory`: the global bin is not on `PATH`. Use `npx -y @agentmemory/agentmemory@latest`. +- `EACCES` during global install: retry with `sudo`, or use the npx form. +- Stale npx version: run `npx -y @agentmemory/agentmemory@latest`, or clear the cache with `rm -rf ~/.npm/_npx` (macOS/Linux). +- Port already in use: another instance or process holds 3111. Stop it, or relocate with `agentmemory --instance 1`. +- Server starts but `livez` never returns 200: re-run with `agentmemory --verbose` to see engine stderr. +- Engine version warning on start: harmless. agentmemory uses its own pinned engine in `~/.agentmemory/bin` regardless of any `iii` on `PATH`. Set `AGENTMEMORY_III_VERSION` only to override deliberately. +- Only 7 tools visible in the agent: the MCP shim is in local fallback because it could not reach a server. Start `npx @agentmemory/agentmemory` and ensure `AGENTMEMORY_URL` points at it (default `http://localhost:3111`), then reload MCP. +- Windows: use WSL2 for the path above. Native Windows runs the server but `connect` and the automated engine install are not supported. -## 7. Report success +## Report success Report back to the user: -- agentmemory installed and the server is running on port 3111 -- which agent was wired via `agentmemory connect` +- agentmemory installed, version, and the server running on port 3111 +- which agent was wired via `agentmemory connect`, and the tool count the agent now sees - the save and recall round-trip returned the probe memory -- the viewer is available at http://localhost:3113 +- the viewer is available at `http://localhost:3113` +- whether any optional features were enabled If any step failed, report which step, the exact command, and the error output.