All notable changes to agentmemory will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Stability + ecosystem wave. Three install-broken bugs (npm install ERESOLVE, non-OpenAI base URLs, broken Claude bridge path) closed. Six runtime bugs from active users fixed end-to-end. Three new agent integrations (Qwen Code, Antigravity, Kiro). New AGENT_ID scope for multi-agent setups. Port mapping documented.
-
npm installERESOLVE on fresh install (PR #649, closes #631).@anthropic-ai/sdkbumped from^0.39.0to^0.93.0soclaude-agent-sdk's peer is satisfied. Verified clean install with only the publisheddependenciesblock. -
Non-OpenAI base URLs silent-404 (PR #649, closes #646, #628).
buildChatUrl+buildEmbeddingUrlno longer blindly prepend/v1/. DeepSeek, SiliconFlow, Zhipu (/api/paas/v4), vLLM, LM Studio, Ollama all resolve correctly. -
CLAUDE_MEMORY_BRIDGEwrites to a path Claude Code reads (PR #649, closes #625). Slug now preserves the leading-on POSIX absolute paths and drops the spurious/memory/subdir, matching~/.claude/projects/<slug>/MEMORY.md. -
OpenAI provider reads
reasoning_contentfor thinking models (PR #648, closes #627). DeepSeek V4 / Qwen3 / GLM / Kimi returnmessage.reasoning_content. Previously onlymessage.reasoningwas checked — compress silently failed every call and tripped the circuit breaker. -
agentmemory stopreaps the worker process (PR #648, closes #640, #474). Worker pid is written to~/.agentmemory/worker.pidon boot;stopsignals both engine + worker. -
OpenCode plugin implicit-creates the session on first observation (PR #648, closes #638).
mem::observecreates the session row when one doesn't exist. No more orphan observations orSession not found for summarize. -
OpenCode plugin zero-config auto-context injection (PR #648, closes #431).
POST /session/startcontext is cached per-session; the existingexperimental.chat.system.transformhook reads from the cache. -
Viewer graph settles on 1000+ node graphs (PR #648, closes #563). Tick-decayed damping, per-node velocity cap, raf park on quiescence. Mousedown / wheel / zoom / recenter re-wake the parked loop.
-
/memories+/exportpaginate (PR #648, closes #544). New?count=trueand?limit=N&offset=Mon/memories./exportforwards?maxSessions+?offset. Stops large corpora (8K+ memories) from timing out at the iii-engine invocation boundary. -
Claude Code drops the MCP server silently (PR #650, closes #510).
plugin/.mcp.jsonenv block uses${VAR:-default}form. Unset required vars no longer fail config parse. -
Full 51-tool MCP surface by default (PR #650, closes #553).
getVisibleTools()default flipped fromcore(8) toall(51) to match what every plugin manifest advertises.AGENTMEMORY_TOOLS=corestill gives the lean set. -
Connect adapters write
${VAR:-default}env block (PR #650).agentmemory connectfor Claude Code / Cursor / Gemini CLI / Windsurf writes the same default form. -
Hermes
memory statusno longer reports the plugin as Missing (PR #643, closes #520). Hermes plugin seedsAGENTMEMORY_URLtohttp://localhost:3111at import. Works for systemd-managed agentmemory where the env file is loaded viaEnvironmentFile=and never reaches the interactive shell. -
Deleted memories cleared from BM25 + vector indices (PR #636 by @abhinav-m22, closes #632).
SearchIndex.remove()added and called from every delete path. Snapshot flushed synchronously so a SIGKILL between mutation + debounce can't resurrect deleted entries. -
PostToolUse hook reads
tool_response, falls back totool_output(PR #561 by @faraz152, closes #539). Claude Code's PostToolUse payload usestool_response. Now readstool_response ?? tool_outputso legacy integrations keep working. -
iii-sdk pinned to exact
0.11.2(PR #567, closes #555).iii-sdk@0.11.6introduced a routing regression where every/agentmemory/*route returned 404. Pin removes the caret. -
OpenAI provider sends explicit
stream: false(PR #526 by @Ptah-CT). Some OpenAI-compatible proxies default totext/event-streamwhenstreamis absent. -
Viewer search uses NFKC normalisation for CJK / fullwidth input (PR #542 by @kaushalrog).
-
Viewer splash shows actual bound viewer port (PR #560 by @Tanmay-008, closes #521).
/agentmemory/liveznow returnsviewerPort+viewerSkipped. -
Viewer tab bar height stable across tab switches (PR #325 by @hungtd119, closes #324).
-
Graph parser accepts self-closing
<entity .../>tags (PR #494 by @Rex57, closes #492). -
Plugin MCP server inherits remote/auth env (PR #386 by @LaplaceYoung, closes #375).
-
@agentmemory/mcprejects literal${VAR}placeholders. AnyAGENTMEMORY_URL/AGENTMEMORY_SECRETvalue of the form${...}is treated as unset and falls back tohttp://localhost:3111. -
Codex
stophook closes session (PR #579, closes #493).Stopwas missing from the Codex bundle; session never got marked completed. -
Claude Code
--with-hooksworks for MCP-standalone users (PR #581, closes #508).
-
AGENT_IDmulti-agent memory isolation (PR #654, closes #554). OptionalAGENT_IDenv tags every Session / RawObservation / CompressedObservation / Memory.AGENTMEMORY_AGENT_SCOPE=isolated(opt-in;shareddefault) also filters every recall path (mem::smart-search,/memories,/observations,/sessions). Per-call overrides via request body +?agentId=<role>/?agentId=*query params.?includeOrphans=truesurfaces pre-tag rows. -
Qwen Code connect adapter (PR #651, closes #647).
agentmemory connect qwenwrites the standardmcpServersblock to~/.qwen/settings.json. -
Antigravity connect adapter (PR #651, closes #614). Replacement for Gemini CLI (sunset 2026-06-18). Writes
mcp_config.jsonto the platform-specific User dir. -
Kiro connect adapter (PR #651, closes #618). Writes user-level
~/.kiro/settings/mcp.json. -
Cost-aware model selection (PR #654, closes #613). Runtime warning when
OPENROUTER_MODELmatches the premium pattern. README cost-tier table with measured workload data. Suppress viaAGENTMEMORY_SUPPRESS_COST_WARNING=1. -
Pluggable benchmark harness (PR #562). New
eval/directory with thecoding-agent-life-v1corpus (15 sessions + 15 graded queries) and three adapters (grep, OpenAI embeddings + cosine, agentmemory hybrid). LongMemEval support. Sandboxed agentmemory + iii-engine on alt ports viaeval/scripts/sandbox.sh. Dev-only — no runtime impact. -
agentmemory connect codex --with-hooksopt-in flag (PR #564, closes #509). Workaround for openai/codex#16430. -
Cross-platform CI matrix (PR #556). Ubuntu + macOS × Node 20 + 22,
paths-ignore, per-branch concurrency cancellation.
-
Port mapping table (PR #651, closes #629).
3111REST /3112streams /3113viewer /49134engine WS + env overrides + stale-process cleanup recipe. -
Pairings recipe (PR #641).
docs/recipes/pairings.mdcovers stacking agentmemory with codegraph, Understand Anything, and Graphify. -
Multi-agent README section (PR #654).
AGENT_ID+AGENTMEMORY_AGENT_SCOPEsemantics, per-endpoint behavior table. -
Supply-chain policy in SECURITY.md (PR #654, closes #540). Explains why no lockfile is committed (
dist/ships pre-built) and what monitoring exists. -
README "Config File" section + Windows path (PR #321 by @aqilaziz, closes #293).
- 108 test files, 1171 tests pass.
- Agent count: 8 → 11 (claude-code, codex, cursor, gemini-cli, qwen, antigravity, kiro, openclaw, hermes, pi, openhuman).
0.9.21 — 2026-05-19
Quality + integration wave. Headline: native OpenCode plugin with full Claude Code hook parity (#237 by @cl0ckt0wer). Ten more PRs alongside: memory_recall returning the wrong shape, env-file AGENTMEMORY_DROP_STALE_INDEX silently ignored, hook scripts crashing on Windows usernames with spaces, viewer search inputs interrupting CJK IME composition, large sessions silently failing at the LLM context limit, lessons invisible to smart-search, Hermes plugin manifest missing hooks, cli onboarding crashing in non-TTY contexts, rebuildIndex blocking boot on large corpora, 25h embed-loop bottleneck during rebuild, and the v0.9.19 iii-console installer workaround can come out now that upstream is fixed.
- OpenCode plugin with 22 auto-capture hooks (PR #237 by @cl0ckt0wer, closes #236 + #244). Complete OpenCode plugin in
plugin/opencode/matching Claude Code hook parity. Covers session lifecycle (8 hooks), messages (3), tool lifecycle (2), part tracking, permissions, task tracking, plus a two-layer enrichment pipeline (memory context on first turn, file enrichment on subsequent turns) and two slash commands (/recall,/remember). Full gap analysis inplugin/opencode/README.md.
-
memory_recallendpoint + format/token_budget forwarding (PR #516 by @serhiizghama, closes #507 + #440). MCPmemory_recallalways returned compact mode and droppedformat+token_budgetparams. Two root causes fixed: standalone shim routed through/agentmemory/smart-searchinstead of/agentmemory/search, and the local-fallback path didn't read either param. Now routes correctly, forwards both params end-to-end, defaultsformatto"full"matching the MCP schema. -
env-file
AGENTMEMORY_DROP_STALE_INDEXflag now honored (PR #461 by @honor2030, closes #456). Setting the flag in~/.agentmemory/.envwas silently ignored because the boot path readprocess.envdirectly. NewisDropStaleIndexEnabled()helper reads merged env. Combined with #455 + #469 reports, this is the unblock path for the stale-index server-crash recovery loop. -
Windows hook scripts quote plugin paths correctly (PR #487 by @honor2030, closes #477). Hook command strings referenced
${CLAUDE_PLUGIN_ROOT}/scripts/*.mjswithout quotes — Windows users with spaces in their username had every hook crash. Quotes added + regression test. -
Viewer search inputs honor IME composition (PR #517 by @jonathanzhan1975). CJK users typing in the viewer's search inputs hit mid-character interruption — every keystroke fired the
oninput=re-render handler, breaking IME composition mid-syllable. NewbindImeSafeSearchhelper defers re-render untilcompositionend. -
Chunk large sessions to fit LLM context window (PR #472 by @efenex). Sessions with >7000 observations silently failed at the LLM provider's context limit — the consolidation pipeline silently skipped the session. New chunking splits oversized sessions across multiple compress calls + restitches the narrative via a
REDUCE_SYSTEMprompt. Legacy single-call path preserved when obs count is under the chunk size. Backfill script underscripts/for users hitting the pre-fix bug. -
Surface lessons in smart-search + diagnose tally (PR #473 by @efenex). Closes the lesson round-trip with #458 (lessons auto-injected into
mem::context): lessons are now also returned alongside hybrid search results in a separatelessonsfield onsmart-search, and thediagnosehealth surface tallies per-store counts so the trust-shock pattern (save succeeds, recall empty, diagnose says 0) goes away. -
Declare all Hermes plugin hooks (PR #486 by @honor2030). The Hermes
plugin.yamlmanifest only declared 3 of the 6 implemented hooks. All 6 now declared (prefetch,sync_turn,on_session_end,on_pre_compress,on_memory_write,system_prompt_block). -
rebuildIndexnon-blocking on boot (PR #500 by @efenex). Boot path previouslyawait-edrebuildIndex(kv), so the viewer + later boot steps stalled — on large corpora this was 25h+ of blocked startup. Replaced withvoid rebuildIndex(kv).then(...).catch(...)so the rebuild runs in the background. -
Batched embed calls in
rebuildIndex(25h → 3h on large corpora) (PR #504 by @efenex). The rebuild loop made one embed call per observation, paying full HTTP RTT per item. NewvectorIndexAddBatchGuardedhelper batches embeds (default 32, configurable viaREBUILD_EMBED_BATCH_SIZE) and try/catches per-item failures. Measured 25h → 3h on a 250k-observation corpus. -
CLI skips onboarding prompts without a tty (PR #491 by @honor2030). Onboarding prompts crashed in non-interactive contexts (CI,
docker run -d, piped input). New guard short-circuits with sensible defaults when stdin/stdout aren't TTYs orCI=1.
- Drop iii-console installer
--nextworkaround (PR #546). v0.9.19 routed first-run iii-console install throughbash -s -- --nextto dodge an upstream tag-prefix bug at iii-hq/iii#1652. Upstream iii-hq/iii#1660 shipped 2026-05-19;install.iii.dev/console/main/install.shis a CDN proxy serving upstream main HEAD so the fix is live without an iii release tag. Reverted to canonical barecurl ... | sh.
- 95 test files (was 92), 1067 tests pass (was 1038) on
chore(release): v0.9.21. - Bundles 11 PRs: 1 contributor feature + 9 bug fixes across MCP / hooks / viewer / summarize / lessons / Hermes / rebuildIndex / CLI + 1 upstream-installer revert.
- New contributors landing first PRs this release: @cl0ckt0wer, @serhiizghama, @jonathanzhan1975.
0.9.20 — 2026-05-18
Hotfix: revert the Codex Stop → session-end chain shipped in v0.9.19.
- Revert Codex Stop hook session-end chain (PR #501 by @Rex57, reverts v0.9.19's #495, re-opens #493). Post-merge field-testing surfaced the underlying issue: Codex
Stopfires before the overall conversation is truly finished — multiple Stops bracket each assistant turn within one session. Chainingsession-end.mjsfrom Stop marked sessions completed too early, with later observations still arriving against anendedAt-stamped record. Restored to summarize-only Stop; the SessionEnd-shaped solution stays open as #493.
0.9.19 — 2026-05-18
Feature + hardening wave. Sessions now link to the git commits they shipped (forward + reverse lookup, REST + MCP surfaces). OpenAI provider transport collapses into one shared module with auto-detected Azure URL style (legacy /openai/deployments/<dep> and v1 /openai/v1 both supported). Graph retrieval switches from BFS to Dijkstra over the weighted edge graph. Codex Stop hook chains session-end. Plugin MCP server inherits AGENTMEMORY_URL / AGENTMEMORY_SECRET from the shell. Point fix routes the bundled iii-console installer around an upstream tag-prefix bug. 1007+ tests pass.
-
Session-to-commit linking (PR #498). New
KV.commitsnamespace keyed by full SHA holdsCommitLinkrecords (sha, shortSha, branch, repo, message, author, authoredAt, files, sessionIds).Session.commitShas[]provides the forward back-reference. REST:POST /agentmemory/session/commitupserts links (mergessessionIdson re-link, preserveslinkedAt);GET /agentmemory/commits/:shaandGET /agentmemory/commitsround-trip. MCP:memory_commit_lookupandmemory_commitstools. Post-commit hook auto-captures the link on every commit in the working directory. Closes the loop on "what session wrote this code" / "what commits did this session ship" without leaving agentmemory. -
Azure OpenAI v1 URL pattern auto-detection (PR #462, closes #371). Both the LLM and embedding providers now route through
_openai-shared.tsand auto-detect Azure URL style:OPENAI_BASE_URL=https://r.openai.azure.com/openai/deployments/<dep>→ legacy URL pattern,api-versionquery param viaOPENAI_API_VERSION(default2024-08-01-preview).OPENAI_BASE_URL=https://r.openai.azure.com(bare host, or/openai, or/openai/v1) → v1 GA pattern,/openai/v1/<route>, deployment name carried in the request body asmodel.- Net effect: Azure embeddings work for the first time (LLM-side Azure shipped in v0.9.17; embedding was still hardcoded to
/v1/embeddings+ Bearer). Closes #199 (consolidation) as superseded.
-
Graph retrieval: BFS → Dijkstra over weighted edges (PR #463, closes #328 filed by @Tanmay-008 with benchmark numbers showing the BFS edge-count semantics + O(n)
Array.shift()profile). Memory graph edges carry weights 0.1–1.0; BFS visited by edge-count regardless, so a one-hop weak edge ranked the same as a two-hop strong chain. Dijkstra overcost = 1/max(weight, 0.01)selects weight-optimal paths instead. Adjacency map built once in O(V+E) and min-heap dequeue at O(log V) replace the prior O(V·E) + O(n)Array.shift()profile.maxDepthsemantics preserved (still edge-count bound). ThestartNodepath is excluded from returned paths so the dedicatedscore=1.0fallback loop insearchByEntitiesfires as designed (regression catch from the inline review). -
Codex Stop hook chains session-end (PR #495 by @Rex57, fixes #493 also filed by @Rex57).
hooks.codex.jsonStop now runsstop.mjsfollowed bysession-end.mjs. Codex doesn't ship a separateSessionEndlifecycle event, so the session would otherwise stay open after the user terminated the Codex session. Tests assert both commands appear in the Stop chain. -
Plugin MCP entry inherits shell env via passthrough (PR #460, closes #375 filed by @anthony-spruyt).
plugin/.mcp.jsonandAGENTMEMORY_MCP_BLOCK(the templateagentmemory connect <agent>writes into~/.claude.json,~/.cursor/mcp.json, etc.) now declareenv: { AGENTMEMORY_URL: "${AGENTMEMORY_URL}", AGENTMEMORY_SECRET: "${AGENTMEMORY_SECRET}" }. The MCP host substitutes shell values at server launch. When the vars are unset, the host passes empty strings; the standalone shim'sprocess.env["AGENTMEMORY_URL"] || "http://localhost:3111"falls back to localhost. One wired entry now covers both local and remote (k8s / reverse-proxied) deployments without/doctor"duplicate server" warnings.
ensureIiiConsole()install path (src/cli.ts). The upstreaminstall.iii.dev/console/main/install.shscript's jq predicate filters releases withstartswith("v")whileiii-hq/iiitags asiii/v0.12.0. The script bails withno stable iii release foundon every fresh install. Switched the install command tocurl ... | bash -s -- --nextuntil upstream patches the script — the--nextcodepath uses a regex on-next.without the buggystartswithconstraint, so it succeeds against the same tag set. Inline comment documents the upstream bug + revert condition.
- 91 test files, 1007 tests pass on
chore(release): v0.9.19. - Bundles five PRs (#460, #462, #463, #495, #498) plus the inline iii-console installer workaround into one patch release.
0.9.18 — 2026-05-17
Hardening + DX wave. Five fixes land together: lessons now flow into the auto-inject context payload (closes a half-finished loop from earlier releases — see #381 / #457), the viewer drops data: from its img-src CSP by self-hosting its favicon, the filesystem watcher redacts PEM private-key blocks and standalone JWTs before transport, the mcp-standalone livez probe gets a dependency-injection seam that kills a flaky test, and the OpenAI timeout precedence is documented + tightened (strict integer parse, OPENAI_TIMEOUT_MS keeps its v0.9.17 meaning as an alias of the global AGENTMEMORY_LLM_TIMEOUT_MS). 1007/1007 tests pass.
-
Lessons auto-injected into
mem::contextpayload (PR #458, closes #457, surfaced in discussion #381). Lessons were generated + stored but only retrievable via an explicitmemory_lesson_recallMCP call — agents rarely thought to invoke it, so the loop was half-done.mem::contextnow readsKV.lessonsalongside slots + profile, ranks by(project-relevance × confidence)(project-scoped lessons get a 1.5× boost), filters tombstoned + cross-project entries, caps at top-10, and emits a## Lessons Learnedblock competing fairly for the token budget. Block recency tracks the most-recentlastReinforcedAt || updatedAt, so hot lessons survive when budget tightens. -
Self-hosted viewer favicon (PR #452, closes #447). The viewer's inline-SVG
data:favicon (added in #313) requireddata:inimg-src— a broader allowance than the viewer actually needed. The favicon now lives at/favicon.svgserved by the viewer withContent-Type: image/svg+xmlandCache-Control: public, max-age=3600; build script copies the asset intodist/viewer/alongsideindex.html. CSP reverts to bareimg-src 'self'.
-
OPENAI_TIMEOUT_MSis now an alias ofAGENTMEMORY_LLM_TIMEOUT_MS(PR #453, closes #446). v0.9.17 shippedOPENAI_TIMEOUT_MSas the OpenAI-scoped knob, then PR #379 introduced the globalAGENTMEMORY_LLM_TIMEOUT_MSshared across all raw-fetch providers. The OpenAI provider now resolves them in precedence order:OPENAI_TIMEOUT_MS→AGENTMEMORY_LLM_TIMEOUT_MS→60_000msdefault. v0.9.17 configs keep working unchanged; new configs should prefer the global. The provider's request also moved onto the sharedfetchWithTimeouthelper that owns AbortController +clearTimeoutcleanup for every raw-fetch path (minimax, openrouter, gemini, embedding providers). -
Strict integer parse for timeout env vars (PR #453, CodeRabbit catch).
parsePositiveIntrejects values like"30ms","1_000","60s","30abc","-30","0"via/^\d+$/(after trim) instead of lettingparseInt's lenience silently swallow trailing units / underscores / signs as a number. Malformed values fall back to the 60s default with no surprise truncation.
-
Filesystem watcher redacts PEM private-key blocks + standalone JWTs in previews (PR #450, closes #448). Continues the redaction surface opened in PR #332. PEM blocks (
-----BEGIN ... PRIVATE KEY-----through-----END ... PRIVATE KEY-----, including encrypted, RSA, EC, DSA, OpenSSH, PGP variants) get a state-machine pass that replaces the whole block with a single[REDACTED ... PRIVATE KEY]marker; standalone JWT-shaped tokens (three base64url segments separated by dots, length ≥ ~32 chars) are masked to their last 4 chars. Both run before any transport-layer write. -
mcp-standalone livez probe DI seam kills the test flake (PR #451, closes #449). The standalone shim's livez probe used a fixed
fetchagainstlocalhost:3111which made the test suite depend on no other agentmemory instance running on the host. NewsetLivezProbe()injection seam lets tests provide a deterministic probe; default behaviour for production users is unchanged.
-
91 test files (was 90), 1007 tests (was 992). New
test/context-lessons.test.ts(8 cases) covers lessons-auto-inject inclusion, empty-state no-op, project ranking, cross-project isolation, soft-delete skip, top-10 cap, confidence rendering, optionalcontextstring append. -
Bundled the four follow-up issues filed during the v0.9.17 audit wave (#446, #447, #448, #449) plus the cross-project lesson-injection gap surfaced in discussion #381 into a single patch release — no behaviour changes for existing users beyond the hardening above.
0.9.17 — 2026-05-16
OpenAI-compatible LLM provider lands the universal-adapter shape (one provider config covers OpenAI, Azure OpenAI auto-detected by hostname, DeepSeek, SiliconFlow, vLLM, LM Studio, Ollama via /v1, plus any future endpoint that mirrors POST /v1/chat/completions). Worker registration now pins a stable project_name for engine telemetry so attribution reads cleanly across hosts. Comparison section on agent-memory.dev no longer wraps awkwardly after the v0.9.16 refresh.
-
OpenAI-compatible LLM provider (PR #307, by @fatinghenji). Six providers behind one config:
OPENAI_API_KEY+OPENAI_BASE_URL+OPENAI_MODEL. Closes #185, #232 (Ollama works viaOPENAI_BASE_URL=http://localhost:11434/v1), #312, and #240 (superseded). -
Azure OpenAI auto-detection.
OpenAIProviderdetects.openai.azure.comhostnames in the configured base URL at construction time and switches the request shape automatically: drops the/v1path prefix (deployment is in the URL), usesapi-key: <KEY>header instead ofAuthorization: Bearer, appendsapi-version=<version>query param. Default api-version is2024-08-01-preview; override viaOPENAI_API_VERSION. Closes the gap with PR #219. -
OPENAI_TIMEOUT_MSenv var (PR #307). Outbound fetch timeout on the new provider, default 60s, AbortController-bounded with a clear timeout error message that points at the env var. The other raw-fetch providers (anthropic / gemini / openrouter / minimax) share the same gap tracked in #373. -
OPENAI_REASONING_EFFORTpassthrough (PR #307). Forwarded asreasoning_efforton the request body for OpenAI reasoning models (o1,o3,gpt-*-reasoning) and providers that mirror that schema (Ollama Cloud thinking models). Standard chat models reject this field with 400 — README documents the caveat. Set to"none"for thinking models that return reasoning but no content. The provider also falls back tomessage.reasoningwhenmessage.contentis empty, covering the Ollama Cloud thinking-model shape.
-
Worker
telemetry.project_namepinned to"agentmemory"(PR #426).iii-sdk'sInitOptions.telemetry.project_nameauto-detects when omitted — falls through cwd → package.json basename → hostname, which produces inconsistent identifiers per host (agentmemory,node,npm, occasionally the user's home dir basename when launched via npx). Pinning the value gives every install the same stable project identifier in the engine's metrics + traces output. Also pinslanguage: "node"andframework: "iii-sdk"for the same reason. -
OPENAI_API_KEY_FOR_LLM=falseopt-out gate (PR #307, fix pushed via maintainer edit).detectLlmProviderKind()now mirrorsdetectProvider()'s existing gate — users who setOPENAI_API_KEYonly for embeddings (via theOPENAI_BASE_URL+OPENAI_EMBEDDING_MODELflow from #186) won't see the LLM auto-activate. The README's.envtemplate now leads with an explicit shared-use callout above the LLM section pointing at the opt-out. -
Compare section on agent-memory.dev (PR #427).
AGENTMEMORY VS. THE FIELD.title →VS. THE FIELD.(the eyebrow already reads VS., so the longer version was redundant + wrapped ugly). Addedtext-wrap: balanceto.section-titleglobally so any wrapping title breaks at a balanced point.NATIVE PLUGINScell value6 (Claude/Codex/OpenClaw/Hermes/pi/OpenHuman)→6(agent names already visible in the Agents grid two sections above). Row grid rebalanced (label 1.4fr / agentmemory 1.3fr / competitors 1fr each), addedword-break: break-word+ 24px row padding so cells likeYES (APACHE-2.0)and2 (Qdrant, Neo4j)have breathing room.
- Provider factory at
src/providers/index.tsnow dispatches"openai"throughcreateBaseProvider; type union extended insrc/types.ts:132.VALID_PROVIDERSset insrc/config.tsincludes the new entry so the fallback-chain config accepts it.
0.9.16 — 2026-05-15
Two parallel waves landed back-to-back. (1) DevEx polish on top of v0.9.15's foundation: 5-port ready panel that shows REST/Viewer/Streams/Engine/iii-console in one boxed note, iii-console install probe + auto-install on first run, interactive global-install prompt that replaces the passive npx hint (so agentmemory stop actually works in new shells), onboarding wizard now wires every selected agent inline via the same agentmemory connect adapter the CLI exposes, plus a memory-share callout so users understand a single server feeds every wired agent. (2) Marketing site refresh against the v0.9.15 surface: new AS FEATURED IN bar (AlphaSignal · Agentic AI Foundation · Trendshift), six first-party agents in the featured grid (added pi + OpenHuman), MCP messaging reworded as opt-in surface so REST reads as the primary protocol.
-
5-port ready panel (PR #410). Replaces the single-line
Memory ready on :3111 · viewer on :3113 · try: agentmemory demohint with a clackp.notepanel listing all live endpoints — REST API, Viewer, Streams, Engine, iii console — each derived from the configured env vars (AGENTMEMORY_URL,III_REST_PORT,III_VIEWER_PORT,III_STREAM_PORT,III_ENGINE_URL) so a remote-bind setup reads correctly, not as hardcoded localhost. -
iii console install probe + auto-install (PR #410). New
ensureIiiConsole()checks for the iii-console binary on PATH or in~/.local/bin; if missing, prompts interactively to runcurl -fsSL https://install.iii.dev/console/main/install.sh | sh. Console is first-class — not optional. On install acceptance the ready panel includes the binary's resolved path and a runnable launch hint (<binPath> -p <port>); on decline the panel surfaces the install one-liner. -
Interactive global-install prompt (PR #410). Replaces the passive
p.log.infonpx hint with ap.confirmon first npx run that runsnpm install -g @agentmemory/agentmemory@<VERSION>inline. Suppressible viapreferences.skipGlobalInstallso we never ask twice. Closes the v0.9.15-era footgun where users typedagentmemory stopin a new shell and hitcommand not found. -
Onboarding wires selected agents inline (PR #408). After the multi-select agents step in
runOnboarding, asksRun \agentmemory connect ` for each selected agent now? [Y/n]and dispatches each through the existingrunAdapterpath used by the explicitagentmemory connectcommand. Successes + failures get bucketed in a summary block (Wired: claude-code, codex, cursor · Skipped/failed: hermes (manual install required)`). Cancellation prints the explicit per-agent commands for the user to run later. -
Memory-share callout (PR #408). Between the agents multi-select and the provider single-select the wizard now prints a verbatim note:
All selected agents share the same memory at :3111. A memory saved by Claude Code is visible to Codex + Cursor instantly.Closes the most common confusion ("does the same memory work across agents?") we were getting on the v0.9.15 install path. -
AS FEATURED IN bar on agent-memory.dev. New
FeaturedIncomponent between Hero and Stats. Three cards with real brand marks: AlphaSignal (github.com/Alpha-Signal avatar, links to the AlphaSignal Substack deep-dive), Agentic AI Foundation (self-hosted wordmark, inverted to white-on-dark for the brutalist palette), Trendshift (their official badge endpoint attrendshift.io/api/badge/repositories/25123which bakes the live rank + star count into the image). 3-column grid on desktop, 1-column stack on mobile, keyboard-accessible (:focus-visibleoutline).
-
MCP messaging reworded as opt-in surface (PR #409). The endpoints summary line in
src/index.tswas foregrounding MCP equally with REST —Endpoints: 107 REST + 51 MCP tools + 6 MCP resources + 3 MCP prompts. Users kept reading MCP as compulsory. Now:REST API: 121 endpoints at http://localhost:<PORT>/agentmemory/*(primary), plus a second lineMCP surface (opt-in via \npx @agentmemory/mcp`): 51 tools · 6 resources · 3 prompts. Eachconnect` adapter additionally prints a protocol-note line above its install summary so the user sees which surface they're wiring (native hooks vs MCP vs both). -
CLI
--helpmcp subcommand description (PR #409). WasStart standalone MCP server (no engine required). Now:Start standalone MCP shim — opt-in surface for MCP-only clients (Cursor, Gemini CLI, etc). REST always available at :3111. -
Engine version-mismatch warning copy (PR #410). The warning that fires when iii on PATH doesn't match
IIPINNED_VERSIONpreviously saidagentmemory v0.9.14+ pins v0.11.2. Now readsagentmemory v${VERSION} pins v${IIPINNED_VERSION}so the string never lies post-release. -
CommandCenter — iii console messaging (PR #415).
iii CONSOLE · OPTIONAL→iii CONSOLE · FIRST-CLASS. Section lede now mentions both UIs (viewer + console) are first-class and installed inline by the CLI on first run. Bullet counts updated: dropped stale33 functionsand49 triggers→121 HTTP endpoints(matchesgenerated-meta.json). -
Compare table refreshed (PR #415). MCP TOOLS row our column 44 → 51. New REST ENDPOINTS row (121) and NATIVE PLUGINS row (6: Claude/Codex/OpenClaw/Hermes/pi/OpenHuman).
-
Agents grid refresh (PR #415). Featured row expanded from 4 to 6 — added pi and OpenHuman. Codex CLI sub line updated to
NATIVE PLUGIN(has 6 hooks now, not MCP-only). Section titleFOUR FIRST-PARTY→SIX FIRST-PARTY. Lede mentionsagentmemory connect <agent>. -
Hero CTA (PR #415).
START IN 60 SECONDS→START IN 30 SECONDS. Cold install + engine spawn measured 8-12s on v0.9.15 via the native binary path; 60s was the v0.9.0-era Docker-first claim.
-
CLI no longer kills its own parent process (PR #410 follow-up via #411).
lsof -i :PORT -treturns every PID with an active TCP connection — including the CLI's own keep-alivefetch()fromisEngineRunning(). Now restricts to-sTCP:LISTENand filtersprocess.pidfrom the candidate set. The bug used to surface as exit code 137 with state files left stranded. -
Splash banner ASCII (PR #411). The hand-drawn block-art "agentmemory" wordmark in
src/cli/splash.tshad broken middle glyphs (_ _instead of_ __around the 'n', merged 'tm/me' segments). Replaced with verifiedfiglet agentmemorystandard-font output. All 6 rows render at exactly 70 cols, regenerable. -
README install hoisted to top (PR #411). Install section was buried at line 306 below benchmarks and comparison tables. Moved a 4-line install block right under the nav anchors at the top with the bare
agentmemorycommand leading. Quick-start kept below for the in-depth walkthrough. Adds an npx-cache caveat with three workarounds (npm install -g,npx -y @latest, manualrm -rf ~/.npm/_npxannotated as POSIX-only).
- New modules:
src/cli/connect/{index,types,claude-code,codex,cursor,gemini-cli,openclaw,hermes,pi,openhuman,json-mcp-adapter}.ts,src/cli/doctor-diagnostics.ts,src/cli/remove-plan.ts,src/cli/splash.ts,src/cli/preferences.ts,src/cli/onboarding.ts,src/logger.ts(bootLog shim) — actually shipped in v0.9.15; relisted here only to call out that v0.9.16 keeps every module backward-compatible (no signature breaks onrunOnboarding, no field removals fromPrefs). - New tests: existing CLI test suites continue at 944+ passing. mcp-standalone pre-existing failures unrelated.
- Website: new
FeaturedIncomponent (~150 LOC across.tsx+.module.css);next.config.tsaddsaaif.io,trendshift.io,raw.githubusercontent.comtoremotePatterns.
0.9.15 — 2026-05-15
DevEx overhaul. Four PRs landed simultaneously rebuilding the first-run experience to SkillKit-grade polish: splash banner + interactive agent grid + provider picker + smart-defaults preferences, agentmemory connect <agent> to automate native-plugin install for 8 agents, interactive doctor v2 with Fix/Skip/More/Quit prompts and a --all auto-fix flag, agentmemory remove for clean uninstall with destruction-plan confirmation, plus five silent-killer fixes around viewer port collisions, engine version-mismatch detection, stop --force override, adopt-on-attach state recording, and an npx-to-global-install hint.
-
Splash banner + onboarding wizard (PR #403). Terminal-width-aware ASCII (full at ≥120 cols, compact at 80–119, single-line below 80),
NO_COLOR-aware. First-run flow: multi-select 8 native-plugin agents + 8 MCP-server agents (⟁ Claude Code,◫ Cursor,◎ Codex,✦ Gemini CLI,⬡ OpenCode, etc), single-select LLM provider (Anthropic / OpenAI / Gemini / OpenRouter / MiniMax / BM25-only), seeds~/.agentmemory/.envwith the chosen provider's*_API_KEY=line commented. Subsequent runs skip the splash. -
~/.agentmemory/preferences.json(PR #403). Schema-versioned JSON with{ lastAgent, lastAgents, lastProvider, skipSplash, skipNpxHint, firstRunAt }. Atomic write via.tmp+ rename, graceful defaults on read failure. ExportsisFirstRun(),readPrefs(),writePrefs(),resetPrefs(). -
agentmemory connect <agent>command (PR #402). Automates native-plugin install forclaude-code,codex,cursor,gemini-cli,openclaw(end-to-end working) plus stubs forhermes,pi,openhuman(which print manual-install hints until deeper YAML/TS adapters land). Each adapter: detect → backup the agent's existing config to~/.agentmemory/backups/<agent>-<timestamp>.<ext>→ merge → re-read & verify → idempotent on re-run. Supports--dry-run,--force,--all. Interactive picker when run without an agent argument. -
agentmemory removecommand (PR #406). Tears down everything agentmemory installed: pidfile + state file + preferences + backups +~/.local/bin/iii(only when it matches the version we installed) + any agent connections. Asks separately for.env(holds API keys) and for the memory data dir. Requires two confirmations by default. Supports--force,--keep-data. -
agentmemory doctorv2 (PR #406). Replaces the passive reporter with an interactive fixer. Each diagnostic prints problem + cause + fix-preview, then offers Fix / Skip / More / Quit. Checks: missing.env, missing LLM key, engine version mismatch, viewer port unreachable, stale pidfile, empty API keys, iii on PATH outside~/.local/bin/iii. New flags:--all(apply every fix, for CI),--dry-run(show plan only). -
agentmemory stop --force(PR #405). Bypasses the Docker-compose heuristic refusal so engines started before v0.9.14 (which had no state file) can be torn down without a hand-rolledlsof | xargs kill -9. -
--resetflag. Wipes preferences and re-runs the onboarding wizard (PR #403). -
--verbose/AGENTMEMORY_VERBOSE=1. Restores the pre-v0.9.15 25-line[agentmemory] Xengine-boot log stream for debugging (PR #403). Default is muted to a single ready-line.
-
First-run output trimmed from 30+ lines to ~10. The
[agentmemory] Worker v0.9.xboot log stream is now buffered behind abootLogshim (src/logger.ts) and only surfaces when--verboseis passed. The default surface is the splash banner, the onboarding prompts (first run only), a single engine spinner, and a one-line ready hint:Memory ready on :3111 · viewer on http://localhost:3113 · try: agentmemory demo. -
isEngineRunning()short-circuit now adopts the engine (PR #405). When the CLI finds an existing engine on:3111, it now writes~/.agentmemory/iii.pid(resolved vialsof -i :PORT -sTCP:LISTEN -t) and~/.agentmemory/engine-state.json({kind:"native", configPath, attached:true}) if neither exists. Closes the migration gap where pre-v0.9.14 engines could not be stopped viaagentmemory stopbecause no state file was written by the older code. -
Viewer port auto-bump (PR #405). When
:3113is taken, the viewer now retries 3114 → 3115 → … up to 3122 before failing loud. Pre-fix behaviour was a silentViewer port 3113 already in use, skipping viewer.which left users staring at the previous run's stale viewer. -
Engine version-mismatch warning (PR #405). When the iii binary on PATH (or attached engine) is not the pinned
IIPINNED_VERSION(currently v0.11.2), the CLI now prints a clearly-labelledp.log.warnwith the override path (AGENTMEMORY_III_VERSION=...env var or downgrade curl one-liner). Pre-fix was silent acceptance — v0.11.6 on PATH led to undebuggable EPIPE loops. -
npx PATH hint (PR #405). After the engine is ready, runs invoked via
npxget one extra line:Tip: install globally for the bare \agentmemory` command: npm install -g @agentmemory/agentmemory. Suppressible viapreferences.skipNpxHint`.
lsof -i :PORT -twas returning client PIDs alongside the LISTEN-socket owner (already fixed in v0.9.14 via the-sTCP:LISTENflag +process.pidfilter; called out here so anyone bisecting the wave knows the LISTEN flag is what stopped the CLI from killing itself).
- New modules:
src/cli/splash.ts,src/cli/preferences.ts,src/cli/onboarding.ts,src/cli/connect/{index,types,claude-code,codex,cursor,gemini-cli,openclaw,hermes,pi,openhuman,json-mcp-adapter}.ts,src/cli/doctor-diagnostics.ts,src/cli/remove-plan.ts,src/logger.ts(bootLog shim). - New tests:
test/preferences.test.ts(7),test/cli-connect.test.ts(13),test/cli-doctor-fixes.test.ts(18),test/cli-remove.test.ts(13). 944 tests passing, 10 pre-existingmcp-standalone.test.tsfailures unrelated to this wave.
0.9.14 — 2026-05-15
CLI bootstrap rework so npx @agentmemory/agentmemory stops failing on Rancher Desktop and other Docker-shim daemons. The native iii-engine binary is now the first-class start path; Docker becomes opt-in. Also ships agentmemory stop so engines started in the background can be torn down without lsof | xargs kill. README agents grid reorders OpenHuman next to the other native-integration agents.
-
agentmemory stopcommand (PR #396). Reads~/.agentmemory/iii.pidfirst, falls back tolsof -i :PORT -sTCP:LISTEN -t, sendsSIGTERM, waits 3s, escalates toSIGKILL. iii-engine doesn't currently handleSIGTERMcleanly so the SIGKILL escalation is what actually frees the port. State file (~/.agentmemory/engine-state.json) records whether the engine was started natively or viadocker compose up -d, sostoprunsdocker compose -f <file> downfor Docker engines instead of signaling the host's Docker socket proxy by accident. -
AGENTMEMORY_USE_DOCKER=1env var. Opt-in path for users who want the bundleddocker-compose.ymlto keep handling iii-engine lifecycle. Without it, the CLI prefers the native binary in~/.local/bin/iii. Documented innpx @agentmemory/agentmemory --help.
-
startEngine()fallback order rewritten (PR #396). New tier order: (1)iiion PATH, (2)~/.local/bin/iiior other fallback paths, (3) interactive clackp.selectwith three choices — auto-install the pinned v0.11.2 binary, use Docker compose, or print manual install instructions and exit, (4) Docker compose only via explicit opt-in or the post-install failure fallback, (5) fail-loud with install instructions. CI / non-TTY environments auto-pick install. The Docker fallback was tier 2 and silently fired on every cold start; on Rancher Desktopdocker compose up -dreturns 0 even when the daemon's pull silently fails, which is what produced the "engine started but REST never responded" misdiagnoses we've been seeing this week. -
Installer logic extracted from
runUpgradeintorunIiiInstaller(). Both first-run andagentmemory upgradenow share the same pinned-v0.11.2 curl-and-tar path. The pre-v0.9.14 installer only ran onnpx @agentmemory/agentmemory upgrade, so first-time users never auto-installed. -
installInstructions()copy reordered. The curl one-liner now leads (path A), Docker is path B with theAGENTMEMORY_USE_DOCKER=1env-var hint. The historical "Why pinned" rationale moved out of the failure note (it's still in the source comment for anyone debugging the pin choice). -
README agents grid reordered (PR #397). Row 1 is now Claude Code → Codex CLI → OpenClaw → Hermes → pi → OpenHuman → Cursor → Gemini CLI. OpenHuman moved from slot 3 to slot 6 so the native-Memory-trait callout reads cleanly alongside the other native-integration agents.
-
CLI no longer kills its own parent process.
lsof -i :PORT -treturns every PID with an active TCP connection to the port, including the CLI's own keep-alivefetch()fromisEngineRunning(). Without a LISTEN filter,agentmemory stopwould SIGKILL itself — exit code 137, state files never cleaned up. Now filters to-sTCP:LISTENand dropsprocess.pidfrom the candidate set. -
agentmemory stopno longer clears the pidfile when a stale process holds the port. The HTTP probe can fail while the engine is hung, paused, or in a half-closed state. The pre-fix behaviour cleared the pidfile and printed "Nothing to stop" — the next run would silently start a second engine on a port that the first engine still owns. Now preserves the pidfile and surfaces the live PIDs withps -p+lsofhints so the operator can investigate before manual cleanup. -
Docker-started engines stop safely. The pre-fix code called
findEnginePidsByPortand signaled whatever held :3111. When the engine was started viadocker compose up -d, that's the host's Docker socket proxy (com.docker.backend,vmnetd), not the engine — killing it took down Docker Desktop networking for every other container. The new state file letsrunStopdetect Docker-managed engines and rundocker compose downinstead.
- Engine process now writes both
~/.agentmemory/iii.pidand~/.agentmemory/engine-state.jsonat spawn. State file is cleared on clean shutdown or abnormal exit; pidfile is preserved when stale PIDs hold the port so the operator can investigate.
Six PRs landed since v0.9.12 — .env.example discovery shipped (#372), CJK BM25 tokenizer landed (#344 / PR #362), benchmark/load-100k.ts load harness landed (#346 / PR #363), one-click deploy templates for fly.io / Railway / Render / Coolify added (#343 / PR #361), Gemini provider defaults moved to current GA models (#246 + #368 / PR #370), and the in-tree Python ecosystem story switched from a duplicate REST client to a one-page iii-sdk example (#342 / PR #364). Plus 14 Dependabot security advisories closed via Next.js + PostCSS bumps.
-
.env.exampleat repo root + bundled in the npm tarball (#372, closes #47, #293, partial #233). Every env var actually read bysrc/is now documented in one place, grouped by surface (LLM provider, embedding provider, auth, search tuning, behaviour flags, CLI runtime, ports, iii engine pin, Claude Code bridge, Obsidian export). Every line is commented out by default so the file ships as a config template, not a config. The npm package now lists.env.examplein itsfilesfield sonpm i -g @agentmemory/agentmemorycarries it. -
agentmemory initcommand. Copies the bundled.env.exampleto~/.agentmemory/.envif that file doesn't already exist; refuses to overwrite an existing config and prints a diff command pointing at the latest template. Wired into the CLI help block alongsidestatus/doctor/demo/upgrade/mcp/import-jsonl. -
CI sync-checker for
.env.example(scripts/check-env-example.mjs). Walks every.ts/.mts/.mjs/.jsfile undersrc/, extractsprocess.env["KEY"]/env["KEY"]/getMergedEnv()["KEY"]/getEnvVar("KEY")references, and fails CI whensrc/reads an env var the template doesn't document (or vice versa). Plugged into.github/workflows/ci.ymlafternpm test. Initial bootstrap: 60 keys in sync. -
CJK tokenizer for BM25 search (#344, PR #362). New
src/state/cjk-segmenter.tsdetects CJK input by Unicode block and routes to@node-rs/jieba(Chinese, native, no model download),tiny-segmenter(Japanese, pure JS, ~25 KB), or rule-based syllable-block split (Korean). Both segmenters declared inoptionalDependenciesso the base install stays lean; soft-fail with a one-time stderr hint when the dep is missing. Order-preserving single-pass tokenization across mixed CJK + non-CJK runs (regression test for"abc 메모리 def 项目 ghi"returns["abc","메모리","def","项目","ghi"]). -
benchmark/load-100k.tsload harness (#346, PR #363). Hand-rolled, dependency-free harness that seeds N synthetic memories against a local daemon athttp://localhost:3111and records p50 / p90 / p99 latency + throughput forPOST /agentmemory/remember,POST /agentmemory/smart-search, andGET /agentmemory/memories?latest=trueacross the matrix N ∈ {1k, 10k, 100k} × concurrency C ∈ {1, 10, 100}. Content drawn from a seedablemulberry32PRNG so re-running against the same build produces the same seed corpus. Results land inbenchmark/results/load-100k-<short-git-sha>.json. Wired asnpm run bench:load. -
One-click deploy templates for fly.io, Railway, Render, and Coolify (#343, PR #361). Each template under
deploy/<platform>/ships a multi-stage Dockerfile thatCOPY --from=iiidev/iii:0.11.2s the engine binary into anode:22-slimruntime, npm-installs@agentmemory/agentmemoryunder/opt/agentmemorywithiii-sdkpinned viapackage.jsonoverrides (avoids the caret-resolves-to-0.11.6 drift), and runs an entrypoint that rewrites the bundlediii-config.yamlto bind0.0.0.0+ use absolute/datapaths, chowns the platform-mounted volume tonode:nodeviagosu, generates a first-boot HMAC secret, and exec's the agentmemory CLI as the unprivilegednodeuser undertini(withTINI_SUBREAPER=1). Verified end-to-end on fly.io (machine iniad, 1 GB volume, healthcheck passing). -
examples/python/quickstart + observation/recall flow showingiii-sdk(Python) callingmem::remember/mem::smart-search/mem::contextdirectly overws://localhost:49134(#342, PR #364). Replaces a duplicate-transport Python REST client (initial PR #360, closed) with a single-SDK story — the sameiii-sdkinstall (pip install iii-sdk/cargo add iii-sdk/npm install iii-sdk) talks to every agentmemory function from any language.
- Gemini provider defaults bumped to current GA models (PR #370, closes #368, #246). LLM default
gemini-2.0-flash→gemini-2.5-flash(the movinggemini-flash-latestalias was rejected — release behaviour should be deterministic). Embedding defaulttext-embedding-004→gemini-embedding-001(the previous default is deprecated and shuts down 2026-01-14 perai.google.dev/gemini-api/docs/deprecations). Three implementation details ride along: (1) URL path:batchEmbedContent→:batchEmbedContents, (2) every request now sendsoutputDimensionality: 768so the returned vectors matchGeminiEmbeddingProvider.dimensions = 768and the index-restore dim guard from #248 — no reindex needed, (3) returned vectors are L2-normalized before the result-array push becausegemini-embedding-001does not normalize by default unliketext-embedding-004and without this the downstream cosine-similarity math silently collapses recall.l2Normalizewarns once on a zero-norm embedding so operators can correlate index quality dips with upstream regressions.
- 14 open Dependabot advisories closed via Next.js + PostCSS bumps (PR #348). Closed: 13 Next.js advisories (middleware/proxy bypass + SSRF on WebSocket upgrades + DoS via connection exhaustion + CSP-nonce XSS + image-opt DoS + RSC cache poisoning + beforeInteractive XSS + segment-prefetch routes) by bumping the website's Next.js to
^16.2.6. Plus the PostCSS XSS-via-unescaped-</style>advisory closed by pinning to^8.5.10viaoverridesinwebsite/package.json. Verifiednpm audit --omit=devreturns 0 andnpm run buildclean on Next 16.2.6. Dependabot now runs weekly against six update streams (npm × 5 paths + github-actions) per the new.github/dependabot.yml.
External contributors landed this release:
- @fatinghenji — pre-cleanup work on the OpenAI-compatible LLM provider (PR #240 / PR #307); the universal-adapter shape will land in the next minor once branch maintenance catches up.
- @AmmarSaleh50 — Gemini embedding migration with L2-norm + 768-dim plumbing (PR #246, folded into #370).
- @yut304 — Gemini LLM default deprecation fix (PR #368, folded into #370).
Thanks also to the issue reporters whose precise repros drove the search-quality + viewer + config-template work this cycle.
Four landed PRs since v0.9.11 — one type-correctness fix, one search-quality fix (BM25 unicode + vector-index live-write), one viewer hardening (CSP-clean fonts + load-error surface), and one integrations security hardening (bearer token over plaintext HTTP).
-
BM25 tokenizer now indexes non-ASCII (Greek, accented Latin, Hebrew, Arabic) and the vector index is actually populated at runtime (#327, closes #295).
src/state/search-index.tspreviously stripped every non-ASCII character via\w(JS\wis ASCII-only), so non-English search returned empty results across the board. Regex replaced with/[^\p{L}\p{N}\s/.\\-_]/gu— keeps Unicode letters/numbers, preserves underscore (matters formemory_recall-style identifiers), keeps existing path/separator handling. Separately,VectorIndex.add()had zero callers anywhere insrc/— the vector index was loaded from disk at startup and never updated at runtime, so hybrid search returned stale results forever. NewvectorIndexAddGuarded()helper insrc/functions/search.tswiresvectorIndex.add()intoremember.ts,observe.tssynthetic-compression branch,compress.tspost-LLM compression, and the cold-startrebuildIndex()walk — with a per-write dimension guard (symmetric to the persistence-load guard from #248), 16k-char input clipping (so an oversized memory can't 400 the embed call), and consistent stderr logging that no longer swallows embed failures.migrateVectorIndex()utility re-embeds every memory + per-session observation against a new provider when dimensions change; per-session try/catch isolation so one bad session can't abort the whole migration; structuredfailedSessions[]result with a"<sessions-list-failed>"sentinel that distinguishes a catastrophic list-failure from per-session failures. Soft-fail throughout: a downed embedder never breaks an upstream save. Live-tested end-to-end against Greek fixtures (thanks @nik1t7n for the original repro on Cyrillic content; test fixtures swapped to Greek before merge).CJK caveat preserved: this fix recovers Greek, Cyrillic, accented Latin, Hebrew, Arabic, and other space-delimited scripts. CJK languages without spaces between characters still tokenize as a single sentence-long token — separate concern, needs a segmenter (PR #224 area).
-
@agentmemory/mcpstandalone shim'sRetentionScoretype no longer declaressourcetwice (#326, closes #277).src/types.ts:835and:842both declaredsource?: "episodic" | "semantic"onRetentionScore. TypeScript silently accepts duplicate property declarations when the types are identical, so the build never errored — but the documented JSDoc on the first declaration (the #124 back-compat note explainingundefinedshould probe both scopes) was effectively shadowed by the duplicate. Removed the second declaration; grep confirmed no caller writessourcetwice on the sameRetentionScorerow, so the cleanup is a pure type-correctness fix with no runtime change. Thanks @cl0ckt0wer for the precise file:line trace. -
Viewer dashboard no longer sticks on "Loading dashboard…" when the page loads (#335, closes #323). Two narrow fixes from @hem57's Windows repro: (1) removed the
<link rel="stylesheet">tofonts.googleapis.com— the viewer's strict CSP (default-src 'none',style-src 'unsafe-inline',font-src 'self') blocks external stylesheet origins by design, so every page load logged a CSP violation for the font CSS and another for each blocked font file; system-font fallbacks were already declared on every--font-*CSS variable so dropping the external<link>is a clean swap. (2) WrappedloadDashboard()body in atry/catchthat renders the error inline ("Dashboard failed to load: ") instead of leaving the placeholder text up forever — future "stuck Loading" reports now come with concrete error messages instead of just a screenshot of the placeholder. -
Integrations (hermes / openclaw / pi) now warn when sending the bearer token over plaintext HTTP to a non-loopback host (#315, closes #275). Symmetric guard across all three plugin runtimes (Python / mjs / TypeScript): a request that would attach
Authorization: Bearer <secret>to ahttp://<non-loopback>:portURL now logs a one-time stderr warning telling the operator the token is observable on the wire. Loopback hosts (localhost,127.0.0.1,::1) andhttps://URLs are exempt. New env knobAGENTMEMORY_REQUIRE_HTTPS=1escalates the warning to a hard refusal — the plugin throws before any request is sent, so a misconfigured deployment can fail loudly instead of leaking the bearer once. Edge cases verified by 13 tests: IPv6[::1]loopback, RFC1918 LAN IPs (192.168.x.x/10.x.x.xwarn — NOT loopback), lookalike hostnames (localhost.evil.comwarns), no-secret short-circuit (guard never fires when no bearer would be sent), https-with-secret silent. Thanks @mvanhorn for the cross-runtime implementation.
@agentmemory/mcppackage version bumped from 0.9.11 → 0.9.12 to lockstep with the main package.
Three additions on top of v0.9.10: OpenAI Codex got a plugin platform and agentmemory now ships a Codex manifest + marketplace alongside the existing Claude Code one (so codex plugin marketplace add rohitg00/agentmemory installs MCP + 6 hooks + 4 skills in one step); the OpenClaw integration now actually claims the plugins.slots.memory slot via registerMemoryCapability (older builds advertised the slot via manifest kind but never declared the capability so the slot reported unavailable); and the marketing website's hero CTA row now ships a live "Star on GitHub" button.
-
Codex plugin support (#311).
plugin/.codex-plugin/plugin.jsonCodex manifest pointing at the same shared.mcp.json+skills/directory the Claude Code manifest uses, plus a Codex-shapedplugin/hooks/hooks.codex.jsonthat registers exactly the events Codex's hook engine supports (SessionStart,UserPromptSubmit,PreToolUse,PostToolUse,PreCompact,Stop) and drops the Claude-Code-only ones (SubagentStart,SubagentStop,SessionEnd,Notification,TaskCompleted,PostToolUseFailure). Verified againstcodex-rs/hooks/src/engine/discovery.rsthat Codex injectsCLAUDE_PLUGIN_ROOTinto hook subprocesses for OOTB compat with existing Claude Code plugin scripts — so the same${CLAUDE_PLUGIN_ROOT}/scripts/...references work on both hosts..codex-plugin/marketplace.jsonat the repo root publishes the plugin via the Codex marketplace API (git-subdirsource pointing at./plugin), so end users runcodex plugin marketplace add rohitg00/agentmemory && codex plugin install agentmemoryonce and get MCP + lifecycle hooks + 4 skills (/recall,/remember,/session-history,/forget). -
Star on GitHubbutton in the website hero CTA row (#316). Adds a ghost-styleGitHubStarButtoncomponent next toSTART IN 60 SECONDSandSEE IT MOVEwith inline SVG star icon,STARlabel, and a live stargazer count fetched once on mount fromapi.github.com/repos/rohitg00/agentmemory. Count is cached inlocalStoragefor 30 minutes per repo. Graceful degradation: if the API is unreachable / rate-limited / blocked, the button still renders without the count. No new dependencies.
- OpenClaw
plugins.slots.memory = "agentmemory"now reports as available, notunavailable(#310). On OpenClaw2026.4.9+, the integration declared"kind": "memory"in its manifest and wiredbefore_agent_start/agent_endhooks but never calledapi.registerMemoryCapability(...)— so OpenClaw's memory-slot machinery saw no claim on the slot even though the hooks and REST API worked end-to-end. The fix landsapi.registerMemoryCapability({ promptBuilder })at register time when the host exposes it, with thepromptBuilderaccepting the documented{ availableTools, citationsMode? }params and emitting a three-line block identifying agentmemory as the active provider. Older OpenClaw builds without the capability API still load via the existing hook-only path (typeof api.registerMemoryCapability === "function"guard). The PR does not ship aMemoryPluginRuntimeadapter because OpenClaw's currentMemoryRuntimeBackendConfigtype is exactly{ backend: "builtin" } | { backend: "qmd"; ... }— both in-process backends that don't fit an external REST shape. Verified againstopenclaw@2026.5.7'splugin-sdk/src/plugins/types.d.tsandmemory-state.d.tsdeclarations directly. (closes the bug premise originally surfaced in the closed PR #302, which had attempted the same goal but with an import path that wasn't in the package'sexportsmap and a symbol that didn't exist in any released openclaw version.)
@agentmemory/mcppackage version bumped from 0.9.10 → 0.9.11 to lockstep with the main package.- README now distinguishes Codex CLI (MCP only) from Codex CLI (full plugin) in the per-host install table and lists the marketplace install command for the latter.
Three deployment-shape fixes reported live by @flamerged (#299, #301): the v0.9.7 docker-compose persistence fix was incomplete because the distroless engine runs as UID 65532 but docker volume create initializes the named volume mountpoint as root:root mode 755; the viewer's port-detection JS hardcoded '3113' so any reverse-proxy fronting on port 80/443 returned an empty dashboard; and the mem::context budget loop short-circuited the entire selection on the first oversized block — pinning a large slot could starve all other context blocks even when smaller ones would have fit.
-
docker-compose.ymlnow chowns the named volume to UID 65532 before the engine starts. Theiiidev/iiiimage is distroless and runs as UID 65532; docker initializes named volumes asroot:root mode 755; the engine has nosh/chownto self-heal at startup, so writes to/data/state_store.dband/data/stream_storereturnedPermission denied (os error 13). The engine silently buffered in RAM, the API kept reportingsuccess: true, and state evaporated on every container restart — the exact symptom v0.9.7's working-directory fix set out to solve. The compose file now ships aniii-initone-shot service (busybox:1.36, ~4 MB, exits in <100 ms) that runschown -R 65532:65532 /data && chmod 755 /dataonce at compose-up, plus auser: "65532:65532"directive on theiii-engineservice and adepends_on.iii-init.condition: service_completed_successfullygate so the engine never starts before the volume is owner-correct. Existing deployments that already hit the bug should rundocker compose down && docker compose up -dafter upgrading — the init container will fix the volume in place on the first run. (#301, closes #301 — thanks @flamerged for the precise UID + mountpoint trace and the chown workaround that confirmed the fix shape) -
Viewer dashboard now works behind any reverse proxy on standard ports (80 / 443).
src/viewer/index.html's port-detection JS resolved the REST base URL throughparams.get('port') || window.location.port || '3113'— when the page was served on port 80 or 443,window.location.portwas the empty string and the fallback hardcoded':3113', so every browser-side/agentmemory/*fetch missed the proxied origin and went to<host>:3113(typically loopback-only on these deployments, so unreachable from outside). The viewer rendered cleanly but every panel showed the empty "first run" state — even thoughcurl <proxy-host>/agentmemory/sessions(no explicit port) returned correct data. The fix useswindow.location.originas the REST base when neither?port=norwindow.location.portis set, and constructs the WebSocket URL fromwindow.location.host(with whatever port the page was served on) so the same-origin path works for both REST and live updates. Behaviour with an explicit?port=Nor non-defaultwindow.location.portis unchanged. (#299, closes #299 — thanks @flamerged for the deployment context + the lines-927–930 trace) -
mem::contextbudget loop no longer bails the entire selection on the first oversized block. The selection loop insrc/functions/context.tsusedbreakwhenusedTokens + block.tokens > budget, so a single oversized block at the top of the sorted list — most commonly a fat pinned slot under #288's new injection path — cut off every smaller block that would have fit. Switched tocontinue, so smaller blocks downstream of an oversized one can still slip into the remaining budget. Net effect: pinned-slot priority semantic is preserved (pinned blocks still sort first viarecency: Date.now()), but the worst case no longer starves the entire context. Total tokens still bounded bytokenBudget(default 2000); only the composition under contention changes.
@agentmemory/mcppackage version bumped from 0.9.9 → 0.9.10 to lockstep with the main package.
Two field-reported regressions closed: pinned memory slots never reached SessionStart context (the renderPinnedContext and listPinnedSlots helpers shipped in v0.7 had no callers), and the MiniMax compression provider read its base URL straight off process.env, missing ~/.agentmemory/.env values that the rest of agentmemory loads through the shared merged-env path.
-
Pinned memory slots are now actually injected into SessionStart context. @wyh0626 traced (#286) that
renderPinnedContext(src/functions/slots.ts:182) andlistPinnedSlots(src/functions/slots.ts:169) — introduced in #182 — had zero callers insrc/.mem::context(the function/agentmemory/session/startinvokes and thatsession-start.mjsreads back into Claude Code) read profile / sessions / summaries / observations but never slots, so anything an agent wrote into a pinned slot viamem::slot-replace/mem::slot-append/mem::slot-reflectsat in KV and never reached the next session. Themem::slot-reflectwriter fires on the Stop hook whenAGENTMEMORY_REFLECT=trueand persists intopending_items/session_patterns/project_context— the reflect → next-session loop was open. The fix wireslistPinnedSlots→renderPinnedContextintomem::contextbehindisSlotsEnabled(), matching the existingisGraphExtractionEnabled()gate convention. Pinned slot content lands as atype: "memory"block withrecency: Date.now()so it sorts to the top of the budget-bounded selection.AGENTMEMORY_SLOTS=false(the default) keeps the existing behaviour untouched. (#288, closes #286 — thanks @wyh0626 for the precise zero-callers trace and the six-case regression suite covering global / multi-sort / unpinned-skip / empty-skip / project-shadows-global / gate-off) -
MiniMax provider now honors
MINIMAX_BASE_URLfrom~/.agentmemory/.env, with the default pointed at the current Anthropic-compatible host. @rager306 reported (#285) v0.9.8 MiniMax compression failingMiniMax API error 401: invalid api keyagainst a verified-good key. Directcurl https://api.minimax.io/anthropic/v1/messageswith the same key succeeded; the control call againsthttps://api.minimaxi.com/anthropicreturned 401. The 401 was the stale fallback host answering — the key was fine. Root cause: split-brain env source.src/config.ts(provider detection + API-key load) reads~/.agentmemory/.envthrough the mergedgetMergedEnv()loader;src/providers/minimax.tsreadMINIMAX_BASE_URLstraight offprocess.env. Deployments that kept MiniMax config in~/.agentmemory/.envonly (systemd / launchd /--env-filenot exported into the worker shell) got the key loaded but the base URL fell through to the stale default. The provider now resolvesMINIMAX_BASE_URLviagetEnvVar()(same merged loader the rest of agentmemory uses), and the default is bumped fromapi.minimaxi.comtoapi.minimax.io/anthropicper MiniMax's current Anthropic-compatible docs. (#289, closes #285 — thanks @rager306 for the precise repro and the local-patch verification)
@agentmemory/mcppackage version bumped from 0.9.8 → 0.9.9 to lockstep with the main package.
Single-line follow-up to v0.9.7's MCP shim work. v0.9.7 surfaced probe failures, added an AGENTMEMORY_FORCE_PROXY=1 escape hatch, and shipped AGENTMEMORY_DEBUG=1 — but the local-mode tools/list branch was still returning only 4 tools when an agentmemory server was unreachable, not the documented 7-tool IMPLEMENTED_TOOLS set the shim's InMemoryKV actually backs. v0.9.8 fixes that.
@agentmemory/mcplocal-modetools/listnow exposes all 7IMPLEMENTED_TOOLS, not the 4-tool intersection withESSENTIAL_TOOLS. The local-fallback branch insrc/mcp/standalone.tsfilteredgetVisibleTools()throughIMPLEMENTED_TOOLS, butgetVisibleTools()honors the shim process's ownAGENTMEMORY_TOOLSenv var (unset → "core" → 8ESSENTIAL_TOOLS). The intersection ofESSENTIAL_TOOLS(8) andIMPLEMENTED_TOOLS(7) is exactly 4 tools:memory_save,memory_recall,memory_smart_search,memory_sessions. Those four were the only ones MCP clients saw when no agentmemory server was reachable — even though the shim'sInMemoryKVimplements all seven (the four above plusmemory_export,memory_audit,memory_governance_delete). The filter source was wrong: the shim dispatches byIMPLEMENTED_TOOLS, not byESSENTIAL_TOOLS, so a server-tier env var should never have shaped the shim's local-fallback list. Switched togetAllTools().filter((t) => IMPLEMENTED_TOOLS.has(t.name)), which picks the same 7 names from the unfiltered universe regardless ofAGENTMEMORY_TOOLS. Refactored thetools/listhandler into an exportedhandleToolsList()for direct testability, and added a regression test asserting the local-fallback path returns exactly the 7 names under both unset andcoremodes. Verified live via stdio against a downed server: shim now returns 7 names (was 4). (#283, closes #234)
@agentmemory/mcppackage version bumped from 0.9.7 → 0.9.8 to lockstep with the main package.
Four follow-up fixes to v0.9.6 reported live by @jcalfee (#234) and @satabd (#278): the @agentmemory/mcp shim gained probe diagnostics and an escape hatch for clients that can reach the server via a non-default route, the Docker compose stack now persists state across docker compose down (the volume binding was unused due to a working-directory mismatch in the engine config), a cosmetic which iii stderr leak was suppressed, and the engine container's log output is now bounded so a crash/restart spam loop can no longer fill the host disk.
-
@agentmemory/mcpstandalone shim now surfaces probe failures and ships an escape hatch and a debug-trace knob. Thelivezprobe insrc/mcp/rest-proxy.tsused a 500 ms timeout and silently swallowed every failure: when the probe failed, the shim fell back to the 7-toolIMPLEMENTED_TOOLSset with no log line explaining why. The probe now writes the URL, HTTP status (or thrown reason), and the active timeout tostderron every failure; the default timeout is raised to 2000 ms;AGENTMEMORY_PROBE_TIMEOUT_MSoverrides it for slow loopbacks;AGENTMEMORY_FORCE_PROXY=1skips the probe entirely and trustsAGENTMEMORY_URLoutright (the right escape hatch when the shim can reach the server via a known route but not the host'slocalhost); andAGENTMEMORY_DEBUG=1tracestools/listend-to-end (handle.mode, response shape, returned tool count, local-fallback contents) so MCP integrations have first-class visibility into what the shim is actually returning over the wire. The shim verified end-to-end via stdio against anAGENTMEMORY_TOOLS=allserver:tools/listreturns all 51 tools. (closes #234, thanks @jcalfee for the host-vs-sandboxed-client repro and detailed log captures) -
Docker compose stack no longer loses state on
docker compose down.iii-config.docker.yamlconfigurediii-stateandiii-streamwith relativefile_path: ./data/..., which the engine resolves against its containerWORKDIR=/home/nonroot— not the/datamount where the namediii-datavolume lives. State and stream stores were written to the ephemeral container layer and discarded on every container restart, so memories, BM25 index, and stream backlog vanished. Both paths are now absolute (/data/state_store.dband/data/stream_store), routing writes through the named volume as the compose file always intended. Existing users need a one-timedocker compose down -vto clear the old empty volume layout before the upgrade. -
CLI banner no longer leaks
which: no iii in $PATHwhen iii isn't installed.whichBinary()insrc/cli.tscalledexecFileSync("which", ["iii"])with default stdio, which inherits the child'sstderrto the parent process — and GNUwhichwrites "no iii in (...)" tostderr(with exit 1) on miss. The catch swallowed the throw but the stderr line had already drained into the user's terminal between theagentmemorybanner and the "iii-engine ready" line.stdio: ["ignore", "pipe", "pipe"]now captures both streams. Pure cosmetic, no behavior change. -
Docker compose stack now caps engine container log size at 30 MB total. @satabd reported the
iiidev/iii:0.11.2engine container filling a host disk with a 129 GB<container-id>-json.logwhen the engine fell into a crash/restart spam loop (#278). The compose service now setslogging.driver: json-filewithmax-size: 10mandmax-file: 3, so unbounded engine stdout/stderr can no longer eat the host's disk. The upstream engine spam itself is filed againstiiidev/iii— this is the compose-side guardrail.
@agentmemory/mcppackage version bumped from 0.9.6 → 0.9.7 to lockstep with the main package.
0.9.6 — 2026-05-10
Three reliability fixes that close field-reported regressions in v0.9.5: search/recall returns saved memories again, the standalone MCP shim no longer caps non-Claude clients at a 7-tool subset, and the Claude Code session/subagent hooks no longer block agent startup for up to five seconds against a slow or unreachable REST server.
-
memory_smart_searchandmemory_recallsurface memories saved viamemory_saveagain. v0.9.5 indexed memories into BM25 (#258), so search ranked them correctly — but the result-enrichment step on both retrieval paths still queriedKV.observations(sessionId, obsId). Memories live inKV.memoriesunder a synthetic sessionId, so every hit was silently dropped and clients sawresults: []. BothHybridSearch.enrichResults(which powers/smart-search) andmem::search's observation map (which powers/search/memory_recall) now fall back toKV.memorieswhen the observation lookup misses, coercing theMemoryrecord into aCompressedObservationvia a new sharedmemoryToObservationhelper insrc/state/memory-utils.ts. Verified live end-to-end against an iii-engine 0.11.2 stack: pre-fix both endpoints returned[]for a saved memory; post-fix the memory surfaces withscore > 0on both. (#269, closes #265) -
@agentmemory/mcpstandalone shim now exposes the server's full tool surface to non-Claude clients. WithAGENTMEMORY_TOOLS=allon the server, OpenCode / Cursor / Gemini CLI / Cline users expected 51 tools; the shim filtered the response through a hardcoded 7-toolIMPLEMENTED_TOOLSset baked in for the local InMemoryKV fallback, so they got 4 (default) or 7 (with the env var). The shim now delegatestools/listtoGET /agentmemory/mcp/toolswhen an agentmemory server is reachable, and forwards any non-essential tool toPOST /agentmemory/mcp/callfor server-side validation. The local InMemoryKV fallback is unchanged — it still implements only the 7 essential tools, with a clearer error pointing toAGENTMEMORY_URLwhen no server is reachable. Verified live end-to-end via stdio JSON-RPC driver: pre-fixtools/listreturned 4 tools andmemory_lesson_saveraised "Unknown tool"; post-fixtools/listreturned 51 andmemory_lesson_savecreated a lesson. (#270, closes #234) -
Claude Code session/subagent hooks no longer block agent startup waiting for a slow agentmemory.
session-start.tsawaited a 5000 ms POST and discarded the response wheneverAGENTMEMORY_INJECT_CONTEXT=false(the default since 0.8.10) — pure latency.subagent-start.tshad a// fire and forgetcomment but the code awaited a 2000 ms POST. Under fan-out (Slack-bot orchestrators, multi-agent harnesses, fannedclaude -pjobs) the awaited timeouts stack and feed back into the engine; the reporter hit a positive feedback loop that OOM-killed iii-engine.session-startnow fire-and-forgets on the telemetry path and caps the inject path at 1500 ms (down from 5000 ms).subagent-startactually fire-and-forgets, capped at 800 ms. Verified live against a black-hole TCP listener (accepts, never replies): session-start (no inject) 5.05 s → 0.85 s, session-start (inject=true) 5.05 s → 1.55 s, subagent-start 2.05 s → 0.87 s. (#271, closes #221)
@agentmemory/mcppackage version bumped from 0.9.4 → 0.9.6 to lockstep with the main package, fixing a release-flow miss in v0.9.5.
0.9.5 — 2026-05-09
Bug-fix patch focused on search recall correctness and plugin compatibility. Pins iii-engine to v0.11.2 because v0.11.6 introduces a new sandbox-everything-via-iii worker add model that agentmemory hasn't been refactored for yet — pin lifts once that refactor lands. Adds a hard guard against silent vector-index corruption, fixes BM25 indexing for memories saved via memory_save, and lands four Hermes plugin fixes that make the memory provider actually usable end-to-end.
If you've been seeing memory_smart_search return empty results for memories you just saved, this release fixes that. If you've been hitting hermes memory status reporting "not available" against a healthy systemd-managed install, this release fixes that too.
-
BM25 search now indexes memories saved via
memory_save.mem::rememberwas writing toKV.memoriesbut never callinggetSearchIndex().add(), somemory_smart_searchandmemory_recallreturned empty for everything saved through that path — for every version since v0.9.0. Synthesizes aCompressedObservationfrom the saved Memory (title + content + concepts + files) and adds it to BM25 right after the durable write.rebuildIndex()now walksKV.memoriesso a fresh rebuild covers the full corpus, and a startup backfill retroactively indexes pre-existing memories on first start after upgrade — no manual reindex required. NewSearchIndex.has(id)is the idempotency gate. (#258, closes #257 — thanks @Nizar-BenHamida for the precise repro and log capture) -
Embedding providers no longer silently corrupt the vector index when an API returns wrong-dimension vectors.
cosineSimilarityreturns0on length mismatch instead of throwing, so a wrong-size vector got stored, never matched anything, and the corresponding memory became invisible without a single log line.withDimensionGuard()now wraps every embedding provider at the factory boundary insrc/providers/embedding/index.ts—embed(),embedBatch()(per-vector, indexed errors likeembedBatch[3]), andembedImage()all throw a descriptive error when the returnedFloat32Arraylength doesn't matchprovider.dimensions. The persistence-restore path got the same defense:IndexPersistence.load()now refuses to start when persisted vectors mismatch the active provider, with an actionable error spelling out the recovery paths (re-embed /AGENTMEMORY_DROP_STALE_INDEX=true/ switch back). (#248, closes #247 and #256 — thanks @AmmarSaleh50 for the issue analysis, the fix PR, and the test coverage) -
Hermes plugin:
handle_tool_callnow returns JSON strings, not raw Python dicts. Hermes stores the return value as the tool resultcontentfield in session history. Anthropic-protocol providers reject non-string content with a 400 on the next request — once triggered, every subsequent request in the affected session 400s until the session JSON is hand-cleaned. Wrapped all four return paths (memory_recall,memory_save,memory_search, unknown-tool) injson.dumps()and tightened the return-type annotationAny → stron both the abstract base and the concrete class. Matches the contract thatsrc/mcp/standalone.tsalready honors. (#255, closes #254 — thanks @KyoMio for the Anthropic-protocol-specific repro) -
Hermes plugin:
hermes memory statusnow reflects the real service state on systemd / launchd installs. When agentmemory runs as an external service whose runtime config lives in~/.agentmemory/.env, those values never reach the Hermes CLI shell. Hermes status readsos.environagainstget_config_schema()'senv_varkeys, finds them unset, and reports the plugin as "not available" — even though the service is healthy. The plugin now preloads~/.agentmemory/.envat import time usingos.environ.setdefault, bridging the agentmemory-managed and Hermes-managed config source-of-truths. Anything explicitly exported in the shell still wins. Best-effort: malformed / absent file is silently skipped. Both~/.agentmemory/.envand$XDG_CONFIG_HOME/agentmemory/.envare checked. (#253, closes #250 — thanks @OptionalCoin for the systemd repro and tracing it to env-source divergence) -
Hermes plugin: memory provider hooks accept passthrough kwargs. Hermes calls memory provider hooks with extra context kwargs (e.g.
session_id) at runtime that the existing strict signatures rejected withsync_turn() got an unexpected keyword argument 'session_id'. Hooks "succeeded" from Hermes's perspective but every conversation turn silently failed sync. Added**kwargs: Anytosync_turn,on_session_end,on_pre_compress,on_memory_write,prefetch,queue_prefetch, andshutdown. Where Hermes passessession_id, the patch prefers it over the cachedself._session_idso multi-session gateway contexts route to the right session. Same change applied to the abstractMemoryProviderfallback for the import-error path. (#252, closes #249 — thanks @OptionalCoin for the precise log analysis) -
agentmemory demonow actually seeds observations.seedDemoSessionposted to/agentmemory/observewithoutprojectandcwd, which the API requires as non-empty strings, so every observation 400'd and the demo silently reported "Seeded 0 observations across 3 sessions". Two-line fix: re-stageproject+cwdinto the observe payload alongsidesessionId. The smart-search queries the demo prints will now return real hits. (#251, closes #229 — thanks @seishonagon for the precise root-cause analysis) -
LLM compression / summarization timeouts increased. Larger sessions were hitting the 120s consolidation timeout under heavier workloads, leaving partial state. Bumped per-step ceilings to give slow providers (esp. local models) room to finish. (#213 — thanks @xuli500177)
-
pi/ OpenClaw / Hermes integration fixes. Tested round-trip fixes across the three integration plugins to keep them aligned with the latest hooks contract. (#230 — thanks @deepmroot)
-
iii-enginepinned to v0.11.2 across every install path. v0.11.6 introduces a new architecture where workers run inside sandboxed microVMs registered viaiii worker add. agentmemory still uses the olderiii-exec watch + node dist/index.mjsworker model fromiii-config.yaml, which doesn't pass the new engine's stricter trigger validation cleanly — the worker drops into an EPIPE reconnect loop and recall stops working. Pinning to v0.11.2 (the last engine that runs agentmemory's current architecture cleanly) until we refactor agentmemory to register itself viaiii worker addand run inside the new sandbox model.src/cli.tsauto-installer downloadsgithub.qkg1.top/iii-hq/iii/releases/download/iii/v0.11.2/iii-<arch>.tar.gzdirectly. Per-arch coverage: darwin arm64/x64, linux x64/arm64/armv7, win32 x64/arm64.- Docker fallback pulls
iiidev/iii:0.11.2instead of:latest. docker-compose.ymlusesimage: iiidev/iii:${AGENTMEMORY_III_VERSION:-0.11.2}so the override env var actually takes effect for compose users.- Install instructions and Windows guide updated to point at the v0.11.2 release page.
- Escape hatch:
AGENTMEMORY_III_VERSION=<version>overrides the pin for users who've moved to the sandbox model manually. - Windows ZIP path detection in
runUpgradeso the auto-installer doesn't try to pipe a.zipthroughtar -xz. (#260) - Follow-up tracked separately: refactor agentmemory to register as a sandboxed worker via
iii worker addso the pin can be lifted.
-
README documents how to extend agentmemory with
iii worker add. New "Powered by iii" section maps eachiii worker add <name>to a concrete agentmemory capability — multi-instance memory, scheduled consolidation, durable retries on embeddings, sandboxed code exec, SQL state, extra MCP host. Lists only workers actually published to workers.iii.dev with direct links. (#242) -
README iii Console section corrected. The console ships with
iiias a subcommand; there's no separate installer. Replaced the boguscurl install.iii.dev/console/main/install.shline, simplified the launch command toiii console --port 3114, and added the missing console pages to the capability table (Workers, Queues, Config, Flow). Replaced the dashboard screenshot with the Workers page so users see real agentmemory instances connected. (#243)
If you're upgrading from <0.9.5 and have an existing vector index on disk, the new dim-guard will refuse to load if your active embedding provider declares a different dimension than what's persisted. This is the intended safe default — set AGENTMEMORY_DROP_STALE_INDEX=true to discard and rebuild from live observations, or re-embed against the new provider before starting.
If you've been on iii-engine v0.11.6 and noticed search returning empty after save, install agentmemory 0.9.5 fresh (or run npx @agentmemory/agentmemory upgrade) to pull pinned engine v0.11.2. v0.11.6 brings a new sandbox-everything-via-iii worker add model that agentmemory hasn't been refactored for yet — that work is tracked as a follow-up; this release just keeps existing users unblocked.
0.9.4 — 2026-04-29
Bug-fix patch. Fixes a silent gap where the knowledge graph never auto-populated despite GRAPH_EXTRACTION_ENABLED=true, and adds a doctor check that detects when Claude Code fails to load plugin hooks.
mem::graph-extractnow auto-fires at session end. WhenGRAPH_EXTRACTION_ENABLED=true, the function was registered and the REST endpoint was live, but no internal caller invoked it — the graph KV stayed empty unless users manuallyPOSTed to/agentmemory/graph/extract.event::session::stoppednow triggers it (fire-and-forget, idempotent via existing node/edge merge keys), so enabling the flag actually populates the graph. README pipeline diagram updated to show graph extraction at the Stop/SessionEnd phase rather than implying it runs per PostToolUse. (#210)
agentmemory doctordetects Claude Code plugin-hook load state. Scans~/.claude/debug/latestfor theLoaded hooks from standard location for plugin agentmemoryline. Surfaces the silent failure mode where the plugin is enabled but Claude Code never registered the hooks — users previously got no signal, hooks just silently did nothing. Hint points at reinstall + session restart and the CC version floor (>= 2.1.x). Skips silently when~/.claude/debugis absent. (refs #212)
0.9.3 — 2026-04-24
Developer-experience patch. Every disabled feature flag is now visible in the viewer, the CLI, and REST error responses, so devs no longer hit empty tabs wondering whether the install is broken or just opt-in. Adds a doctor command that diagnoses the whole stack in one shot and a first-run hero in the viewer that points at the magical-moment demo command.
agentmemory doctorcommand. Runs 10 diagnostic checks in one shot: server reachability, health status, viewer port, LLM provider, embedding provider, four feature flag states, and whether the knowledge graph has data. Every failing check includes a concrete hint with the exact env var or command to fix it. Mirrors the shape of the new viewer feature-flag banners./agentmemory/config/flagsREST endpoint. Returns{ version, provider, embeddingProvider, flags[] }with per-flag{ key, label, enabled, default, affects, needsLlm, description, enableHow, docsHref }. Used by the viewer banner, CLI status/doctor, and anyone who wants to introspect config without parsing logs.- Viewer feature-flag banner system. Compact collapsible summary row at the top of every tab (
⚠ 3 off · ⚙ 1 note · Feature flags — click to expand). Expanded view shows per-flag card with description, exact enable command, docs link, and dismiss button. Dismissed state persists per-flag in localStorage so banners stay out of the way once acknowledged. Banners filter by the current tab'saffectslist. - Viewer first-run hero card. When
sessions.length === 0, dashboard renders an orange-accent card titled "First run → magical moment in 10 seconds" withnpx @agentmemory/agentmemory demoas the next step. Removes the dead-empty dashboard that used to greet fresh installs. - Viewer footer with preset issue report.
agentmemory viewer · v{version} · github · docs · report issue →. The feedback link opens a GitHub issue pre-filled with version, provider name, embedding provider, flag state, and user-agent — so the first message on an issue already contains the diagnostic context that used to take three back-and-forths. - Richer empty states on Actions, Memories, Lessons, Crystals tabs. Each now has a titled lead explaining what the tab is for, why it's empty, three concrete ways to populate it (MCP tool, curl, hook), and a docs link. The old one-liners ("No actions yet. Create actions via memory_action_create MCP tool") assumed too much context.
statuscommand shows flag state. New section in the output block lists provider (✓ llm/✗ noop), embedding provider (✓ embeddings/bm25-only), and each flag with a tick/cross. Parity with the viewer banner.AGENTMEMORY_URLenvironment variable honored by CLI.status,doctor, and related health checks now respectAGENTMEMORY_URL=http://host:portand extract the port from it. Previously documented but silently ignored;--port Nwas the only way to override.- Website install section promotes
demoto step 2.npx @agentmemory/agentmemory demonow appears between "start server" and "open viewer" on agent-memory.dev. The magical-moment command is on the critical path of the three-step install, not tucked into the README. - Website version auto-derived from repo package.json.
gen-meta.mjspicks upsrc/version.tsonprebuildand writeswebsite/lib/generated-meta.json. Removes the stale-version drift that showedv0.9.1on the landing page afterv0.9.2shipped.
- REST "feature not enabled" errors now return structured bodies. Graph extraction (3 endpoints) and consolidation pipeline (1 endpoint) used to return
{ error: "Knowledge graph not enabled" }. Now return{ error, flag, enableHow, docsHref }matching the viewer banner contract. Curl users get the same fix guidance as UI users. - Website install title:
THREE STEPS→THREE COMMANDS. Matches the new three-command install (npx agentmemory,agentmemory demo,open viewer).
- Viewer banner scroll blocker. Initial banner implementation rendered four full-height banner cards stacked above the dashboard, pushing all stats off-screen. Replaced with compact collapsible summary that takes ~40px of vertical space by default and only expands on click.
0.9.2 — 2026-04-22
Safety + import-pipeline patch. Kills the infinite Stop-hook recursion loop that burned Claude Pro tokens on unkeyed installs, repairs every empty viewer tab after import-jsonl, derives lessons and crystals automatically from imported sessions, and opens up OpenAI-compatible embedding endpoints.
- Stop-hook recursion loop (#187, follow-up to #149). A user with no provider key and
AGENTMEMORY_AUTO_COMPRESS=falsecould still trigger unbounded recursion: Stop hook →/summarize→provider.summarize()→ agent-sdk provider spawned a Claude Agent SDK child session that inherited the same plugin hooks, whose own Stop fired, spawning another child, etc. ~579 ghostentrypoint: sdk-tssessions could accumulate in minutes, draining the Claude Pro subscription. Fixed at five layers in defense-in-depth:detectProvider()treats empty-string keys (ANTHROPIC_API_KEY=) as unset and returns the noop provider by default. The agent-sdk fallback now requires explicitAGENTMEMORY_ALLOW_AGENT_SDK=trueopt-in with a second loud warning.- New
NoopProviderreturns empty strings for compress/summarize; callers detect.name === "noop"and short-circuit. agent-sdkprovider setsAGENTMEMORY_SDK_CHILD=1before spawningquery()and restores the previous value infinallyso later calls in the same parent process are not mis-classified.- All 12 hook scripts inline a shared
isSdkChildContext(payload)guard that checks both the env marker andpayload.entrypoint === "sdk-ts", and bail early. /summarizeshort-circuits with{ success: false, error: "no_provider" }whenprovider.name === "noop"instead of calling through. Empty provider responses are now logged and recorded as failures on the metrics store.
OPENAI_BASE_URL/OPENAI_EMBEDDING_MODEL(#186, thanks @Edison-A-N). TheOpenAIEmbeddingProvidernow accepts a base URL override and a configurable model name, mirroring theMINIMAX_BASE_URLpattern. Unlocks Azure OpenAI, vLLM, LM Studio, and other OpenAI-compatible proxies for embeddings with zero breakage — defaults are preserved.OPENAI_EMBEDDING_DIMENSIONS(#189). Follow-up:dimensionsis now derived from the model via aMODEL_DIMENSIONSlookup (3-small=1536, 3-large=3072, ada-002=1536) and falls back to 1536 for unknown models. Custom or self-hosted OpenAI-compatible models should set this env var explicitly; non-positive values are rejected at construction.- Auto-derived lessons and crystals on
import-jsonl(#188). Each imported session now produces one crystal (narrative, tool outcomes, files, lessons) and up to 20 heuristic lessons from instructional patterns (always/never/don't/prefer/avoid/caveat/note/warning). Lessons are keyed byfingerprintId("lesson", content.toLowerCase())so re-importing the same file bumpsreinforcementson existing lessons instead of duplicating rows. Crystals are keyed byfingerprintId("crystal", sessionId)and preservecreatedAton upsert. - Session preview on the sessions list (#188).
SessiongainedfirstPrompt/summaryfields; bothimport-jsonland the livemem::observepath populatefirstPromptfrom the first real user prompt they see, and the viewer renders it as a 140-char preview row under each session. - Richer session detail + crystals viz + lessons tab explainers (#188). Clicking a session now fetches its observations and renders a 4-stat grid (observations / tools / files / duration), top-10 tool bar chart, activity breakdown, and file list. Crystals cards show resolved lesson content instead of raw IDs. Lessons tab has a header explainer card for the rule + confidence + decay model.
detectProvider()default is nownoop(see Security). Users who had no API key and relied on the implicit Claude-subscription fallback must setAGENTMEMORY_ALLOW_AGENT_SDK=trueto restore old behavior — and should read the warning about Stop-hook recursion first./agentmemory/auditresponse shape (#188). Now returns{ entries, success }instead of a bare array to match the viewer's expected shape. The viewer was rendering empty despite populated data./agentmemory/replay/sessionspath (#188). Callskv.listdirectly instead ofsdk.trigger → mem::replay::sessions. Sub-50ms on 600+ sessions instead of timing out at 10s+.- Viewer WebSocket connect timeout (#188). 5-second timeout around
new WebSocket(...). If the socket is still CONNECTING after that, it is force-closed so theoncloseretry / polling-fallback chain kicks in. Previously the banner stuck onCONNECTING…forever when the iii-stream port accepted TCP but never completed the upgrade handshake. import-jsonlnow runs synthetic compression + BM25 indexing (#188). Imported observations go through the samebuildSyntheticCompression+getSearchIndex().add()path as livemem::observe. Previously the raw shape was written directly to KV and the search index never saw it — consolidation reported "fewer than 5 summaries" and semantic/procedural/memory tabs stayed empty.- Viewer strength gauge (#188). Memory tab showed
700%onstrength: 7because the scale was treated as 0–1. Now handles both 0–1 and 0–10 and clamps at 100%.
npm cion fork PRs (#187, #188). CI failed because lockfiles are gitignored at the repo level..github/workflows/ci.yml+publish.ymlnow run a two-step install:npm install --package-lock-onlyto produce a lockfile in the runner workspace, thennpm cito install deterministically from it. Gives a single resolved dependency graph across build + test + publish within one job run — important because publish uses--provenance.image-quota-cleanupfail-closed on refCount read errors (#188). WhengetImageRefCountthrew, the code fell through todeleteImagewithrefCount === 0, risking deletion of still-referenced images on transient KV errors. Fail-closed: log + return from thewithKeyedLockcallback, never reachdeleteImagewithout a confirmed zero refcount.raw.userPrompttype guard (#188).mem::observenow runtime-checkstypeof raw.userPrompt === "string"before calling.replace/.trim/.slice. Non-string truthy values from malformed hook payloads no longer crash the handler.- Viewer Actions frontier field (#188). The tab was reading
results[1].actionsbut/frontierreturns{ frontier: [...] }. Fixed the read path; preserves actions/frontier unification. - Hardcoded
maxTokens: 4096in the agent-sdk branch ofdetectProvider(#188, #190). Ignored themaxTokensvariable computed fromenv["MAX_TOKENS"]. Every other branch already used the computed value; agent-sdk now matches.
StateScopeinterface intypes.tsdocuments theKV.statescope shape (system:currentDiskSize: number);disk-size-managerusesStateScope[typeof DISK_SIZE_KEY]generics instead of ad-hoc<number>.onnxruntime-node+onnxruntime-webmoved tooptionalDependenciesalongside@xenova/transformersto make their lazy/transitive nature explicit; still externalized intsdown.config.tsbecause bundling breaks the native.nodebinding paths.FALLBACK_PROVIDERSparsing now honors the sameAGENTMEMORY_ALLOW_AGENT_SDKgate asdetectProvider, filtering outagent-sdkfrom the fallback chain unless explicitly opted in.- README provider table + env block updated: no-op is the new default, Claude-subscription fallback moved to a separate opt-in row, OpenAI env vars documented.
- Hero stat badge refreshed from 654 → 827 tests (both dark + light variants).
VERSION/ExportData.versionunion /supportedVersionsSet /test/export-import.test.ts/@agentmemory/mcpshim version all bumped in lockstep.- Test count: 827 (up from 812 in v0.9.1).
0.9.1 — 2026-04-21
Trust-the-CLI patch. Three bugs that surfaced in real testing of v0.9.0: the dashboard viewer showed zeros for half its cards, the import-jsonl command crashed on anything but a perfect response, and upgrade hard-aborted on a cargo registry that never had the crate.
- Viewer dashboard list endpoints (#172).
GET /agentmemory/semanticandGET /agentmemory/proceduralwere never registered, andGET /agentmemory/relationsreturned 405 because only the POST trigger existed. The dashboard'sPromise.allfan-out silently received null for those cards even when semantic, procedural, or relation data was present. Addedapi::semantic-list,api::procedural-list, andapi::relations-listhandlers next toapi::memoriesinsrc/triggers/api.ts, each returning the shape the viewer already parses. - CLI version drift (#173). The viewer brand badge hardcoded
v0.7.0and the README "New in" banner still saidv0.8.2. Replaced the viewer string with a__AGENTMEMORY_VERSION__placeholder substituted at render time bydocument.ts(same mechanism as the CSP nonce). Collapsedsrc/version.tsfrom a literal union of every historical release back to a singleVERSIONconstant — the import-compat contract is thesupportedVersionsSet inexport-import.ts, not the type. import-jsonlcrashed withUnexpected end of JSON input(#174). The livez probe used fetch throws as the only failure signal — any stray service on port 3111 passed silently, thenres.json()blew up when the real POST returned an empty body or HTML error. Probe now capturesprobe.status+ body snippet on non-OK responses and the exception message on network failure, so the error distinguishesunreachable (...)fromreachable but unhealthy (HTTP 503: ...). The POST reads body as text, parses only if non-empty, requiresjson.success === true, and maps 401 → "set AGENTMEMORY_SECRET" and 404 → "upgrade server to v0.8.13+".upgradeaborted oncargo install iii-engine(#174). The crate was never published — the old flow calledrequireSuccess, which exited before the Docker pull ran. Swapped to the official installer used throughout the README and demo command:curl -fsSL https://install.iii.dev/iii/main/install.sh | sh. Installer failure is optional; a warn points atiiidev/iii:latestand the releases page atiii-hq/iii.
- Three integration tests cover the new list endpoints.
VERSION/ExportData.versionunion /supportedVersions/test/export-import.test.tsall bumped in lockstep.
0.9.0 — 2026-04-18
Visibility + correctness release. Landing site, filesystem connector, MCP standalone now actually talks to the running server, health logic stops crying wolf, audit trail closes its last gap, and every memory path has a clear policy.
- Website (#164). Next.js 16 App Router landing page at
website/— Lamborghini-inspired dark canvas, live GitHub stars pill, agents marquee with real brand logos, command-center tab showcase (viewer · iii console · state · traces), 12-tile feature grid, 10-agent MCP install selector, universal MCP JSON + one-click Cursor/VS Code deeplinks. Deploys to Vercel with Root Directory =website/. - Filesystem connector — new
@agentmemory/fs-watcherpackage underintegrations/filesystem-watcher/(#163, closes #62). Nodefs.watchbased, no native deps. Emits validHookPayloadobservations for every file change and delete, with debounce, default ignore list, text-file preview, bearer auth, and env-driven config. - Security advisory drafts for v0.8.2 CVEs (#118). Six markdown drafts under
.github/security-advisories/covering viewer XSS, curl-sh RCE, default 0.0.0.0 bind, unauthenticated mesh sync, Obsidian export traversal, and incomplete secret redaction. Also documents the symlink-traversal limitation of the Obsidian export fix. - iii console documentation in the README (#157). How to launch the iii console alongside the viewer, what each page gives you for agentmemory, and the
iii-observabilityconfig that ships turned on.
- Audit policy codified (#162, closes #125).
src/functions/audit.tsgains a top-of-file policy block: every structural deletion emits arecordAuditrow, scoped deletions (governance-delete,forget) write one row per call, bulk sweeps (retention-evict,evict,auto-forget) write one batched row per invocation.mem::forgetno longer deletes silently — it writes a single audit row with target ids, session id, and per-type counts. - Standalone MCP talks to the running server (#161, closes #159).
@agentmemory/mcpnow probesGET /agentmemory/livezatAGENTMEMORY_URL(defaults tohttp://localhost:3111) on first tool call. If the server is up, every tool (sessions, smart-search, recall, save, governance-delete, export, audit) routes through REST and sees exactly what hooks and the viewer see. If the probe fails, falls back to the localInMemoryKVso pure-standalone setups keep working. BearerAGENTMEMORY_SECRETattached automatically. Handle cache invalidates on proxy failure with a 30s TTL so a later server start is picked up. Response shapes are now consistent across proxy and local branches. - Retention eviction targets the right store (#132).
mem::retention-evictnow routes deletes tomem:memoriesormem:semanticbased on the candidate'ssourcefield, probing both namespaces when the field is missing (legacy rows). Emits a single batched audit row per sweep withevictedIds,evictedEpisodic,evictedSemantic, and the threshold. Retention scores gain asourcefield persisted to the store.
- Health stops flagging
memory_criticalon tiny Node processes (#160, closes #158). Memory severity no longer escalates from heap ratio alone. Both warn and critical bands now require RSS abovememoryRssFloorBytes(default 512 MB). When heap is tight but RSS is below the floor, a non-alertingmemory_heap_tight_NN%_rssMMmbnote is attached to the snapshot — visibility without the false positive. - iii console screenshots vendored in the README so the docs don't depend on CDN signed URLs.
VERSIONunion extended to0.9.0;ExportData.version,supportedVersions, andtest/export-import.test.tsbumped in lockstep.@agentmemory/mcpdependency pinned at~0.9.0to match.- Tests: 777 passing (+ 14 skipped), up from 769.
- Session replay: new "Replay" tab in the viewer that plays any stored session as a scrubbable timeline with prompt, response, tool-call, and tool-result events. Keyboard bindings: space to play/pause, arrow keys to step, speed selector (0.5×–4×).
- JSONL transcript import via
agentmemory import-jsonl [path]CLI subcommand andPOST /agentmemory/replay/import-jsonl. Default path~/.claude/projects, or pass an explicit file/directory. Imports are recorded in the audit log. - New iii functions
mem::replay::load,mem::replay::sessions, andmem::replay::import-jsonl, each routed through the same HMAC-authed API trigger as other endpoints.
- JSONL import rejects symlinks, paths containing sensitive terms (
secret,credential,.env, etc.), and skips malformed lines without aborting the batch.
0.8.12 — 2026-04-16
- Added token-efficient
memory_recalloutput modes:format: "full"(default)format: "compact"(returns compact observation rows)format: "narrative"(title + narrative text for low-token recall)
- Added
token_budgetsupport tomemory_recall/mem::searchto trim results to a target budget and returntokens_used,tokens_budget, andtruncatedmetadata. - Added new MCP + REST tool
memory_compress_file(mem::compress-file//agentmemory/compress-file) to compress markdown files while preserving headings, URLs, and fenced code blocks.
- Updated MCP tool count to 44 and REST endpoint count to 104.
- Updated docs and plugin metadata for new tool/endpoint counts.
- Added test coverage for search formats, token budget behavior, and file compression validation.
Fix: node dist/index.mjs crashed on first import after the iii-sdk v0.11 migration (#116) merged. iii-sdk v0.11 dropped getContext(), but 32 src/functions/*.ts files still imported and called it. Added src/logger.ts (thin stderr shim with the same .info/.warn/.error signature) and mechanically replaced every ctx.logger.* call. Updated all 45 test mock blocks. Fixed search.ts registerFunction call to use the v0.11 string-ID API.
- iii-sdk v0.11 getContext crash (#116) —
SyntaxError: The requested module 'iii-sdk' does not provide an export named 'getContext'on startup. Removed allgetContextimports from 32 function files, addedsrc/logger.tsshim, updated 45 test mock blocks.
- Upgraded
iii-sdkdependency from^0.11.0-next.8to stable^0.11.0. - Aligned stream send payloads with v0.11 wire format by using
typeforstream::sendevents in observe/compress/session-activity paths. - Updated migration guidance/examples and diagnostics plugin registration snippets to v0.11 function registration and trigger request shapes.
0.8.10 — 2026-04-15
Behavior change: the PreToolUse and SessionStart hooks no longer run enrichment by default. SessionStart saves ~1-2K input tokens per session you start (the only path that was actually reaching the model, per the Claude Code hook docs). PreToolUse stops spawning a Node process and POSTing to /agentmemory/enrich on every file-touching tool call — a pure resource cleanup, not a token fix. If you were relying on either path, set AGENTMEMORY_INJECT_CONTEXT=true in ~/.agentmemory/.env and restart. Observations are still captured via PostToolUse regardless.
- Gate SessionStart context injection (#143, thanks @adrianricardo) —
src/hooks/session-start.tspreviously wrote ~1-2K chars of project context to stdout at every session start. Per the Claude Code hook docs,SessionStartstdout is explicitly injected into the model's context ("where stdout is added as context that Claude can see and act on"), so this was adding real tokens to the first turn of every new session. Now gated behindAGENTMEMORY_INJECT_CONTEXT, default off. The session still gets registered for observation tracking — only the stdout echo is skipped. - Skip the PreToolUse enrichment round-trip when disabled (#143) —
src/hooks/pre-tool-use.tswas POSTing/agentmemory/enrichon everyEdit/Write/Read/Glob/Greptool call and piping up to 4000 chars to stdout. The Claude Code docs make clear that PreToolUse stdout goes to the debug log, not the model context, so this was not burning user tokens — but it was spawning a Node process + full HTTP round-trip ~20x per user message with no effect on the conversation. Gating it makes the disabled hot path a ~15ms no-op Node startup instead of a ~100-300ms REST round-trip. This is a resource cleanup, not a token fix; leaving the gate in place protects forward in case Claude Code ever changes PreToolUse to inject stdout like SessionStart does. mem::retention-evictno longer leaks semantic memories (#124) — the eviction loop was unconditionally callingkv.delete(KV.memories, id)for every below-threshold candidate, but retention scores are computed for both episodic (KV.memories) and semantic (KV.semantic) memories. When a candidate came fromKV.semantic, the delete silently became a no-op (key wasn't inmem:memoriesto begin with) and the semantic row stayed alive forever with a sub-threshold score. Semantic memories could not be evicted by this path at all. Fix: add asource: "episodic" | "semantic"discriminator toRetentionScore, tag it at score creation, and branch the delete oncandidate.source. For pre-0.8.10 rows with nosourcefield (including semantic retention rows written by the old scorer), the loop probes both namespaces to find where thememoryIdactually lives, so upgraded stores get their stranded semantic memories evicted without needing to re-score first. The response shape now also includesevictedEpisodicandevictedSemanticcounts for observability.mem::retention-evictnow emits an audit record per sweep (#124) — retention eviction performs structural deletes (memories, retention scores, access logs) but was not callingrecordAudit(), which made evictions invisible to audit consumers. Now batched one audit row per non-zero sweep, withoperation: "delete",functionId: "mem::retention-evict",targetIdscontaining every evicted id, anddetails.evicted/evictedEpisodic/evictedSemantic/thresholdfor context. Zero-eviction sweeps intentionally do not write an audit row.
My initial diagnosis on the #143 thread pattern-matched too quickly to #138 and overclaimed that PreToolUse stdout was the smoking gun behind "Claude Pro burned in 4 messages". It wasn't — per the docs, PreToolUse stdout is debug-log only. The actual background cause is that Claude Pro's Claude Code quotas are documented as tight and Anthropic has publicly confirmed "people are hitting usage limits in Claude Code way faster than expected." agentmemory contributes ~1-2K tokens per session via SessionStart, and that contribution is worth eliminating, but this release does not and cannot make Claude Pro's base quotas roomier. Users on heavy tool-call workloads should consider Max 5x or Team tiers regardless of whether agentmemory is installed.
0.8.8's #138 fix (opt-in mem::compress via AGENTMEMORY_AUTO_COMPRESS) remains the correct fix for users with ANTHROPIC_API_KEY set — that path was a real per-observation Claude API burn and is unrelated to the Claude Code hook pipeline.
AGENTMEMORY_INJECT_CONTEXTenv var — defaultfalse. Whentrue, restores the old SessionStart stdout write and the old PreToolUse/enrichround-trip. Startup banner prints a loud warning when it's on, mirroring theAGENTMEMORY_AUTO_COMPRESSwarning from 0.8.8.isContextInjectionEnabled()helper insrc/config.ts— single source of truth for the flag. The hooks read the env var directly (they're spawned as standalone.mjsfiles by Claude Code and don't bootstrap throughsrc/index.ts), so the helper is there for the startup banner and future code paths.- 5 subprocess regression tests in
test/context-injection.test.ts— spawns the compiledpre-tool-use.mjsandsession-start.mjshooks with real stdin/stdout pipes and asserts that stdout is empty when the env var is unset, when it's explicitlyfalse, and that the disabled PreToolUse path exits under 1 second. Also asserts that the opt-in path with an unreachable backend still exits cleanly. Full suite: 724 passing (was 719 + 5 new).
- Startup banner (
src/index.ts) now printsContext injection: OFF (default, #143)on normal startup and a prominent WARNING when opt-in is enabled, so the mode is never silent. - Migration note: if you were relying on the old SessionStart project-context injection or the old PreToolUse enrichment round-trip, add to
~/.agentmemory/.env:and restart Claude Code. You'll see the startup warning in the engine logs confirming it's active.AGENTMEMORY_INJECT_CONTEXT=true
0.8.9 — 2026-04-14
Two UX fixes for the Claude Code plugin install path, both reported in #139 by @stefanfaur.
- Claude Code plugin now auto-wires the
@agentmemory/mcpstdio server (#139) — the plugin previously only shipped hooks and skills, and the README told Claude Code users to wire up the MCP server manually. A newplugin/.mcp.jsondeclares the MCP server so/plugin install agentmemory@agentmemoryauto-starts it when the plugin is enabled. No extra config step. - Skills no longer fail under Claude Code's sandbox with "Contains expansion" (#139) — the
recallandsession-historyskills used pre-execution bash with$(...)/${VAR:-default}shell expansion, which Claude Code's sandbox rejects by pattern match. All four plugin skills (recall,remember,forget,session-history) are now rewritten as pure prompts that tell Claude to use the MCP tools directly. No bash, no sandbox issues, no shell escaping — and the skills run faster because they no longer fork a curl subprocess on every invocation.
- Standalone MCP shim now implements
memory_smart_searchandmemory_governance_delete— the@agentmemory/mcpstdio server only exposed 5 tools (memory_save,memory_recall,memory_sessions,memory_export,memory_audit), so the rewritten plugin skills would have failed at runtime referencing tools the standalone didn't know about. Now ships 7 tools.memory_smart_searchfalls back to the same substring filter asmemory_recallsince the standalone shim doesn't have BM25/vector/graph without the full engine.memory_governance_deletetakesmemoryIdsas an array or comma-separated string and returns{deleted, requested, reason}. memory_saveacceptsconcepts/filesas arrays or comma-separated strings — the old standalone only accepted CSV strings, which would silently drop array inputs. NewnormalizeList()helper handles both.memory_sessionshonours alimitarg (default 20) — previously returned every session.- 8 regression tests in
test/mcp-standalone.test.tscovering array/CSV inputs formemory_save,memory_smart_searchsubstring fallback,memory_sessionslimit,memory_governance_deletehappy path + unknown-id skip + validation. Full suite: 715 passing.
- README Claude Code install snippet — now explicitly notes that
/plugin install agentmemoryregisters hooks + skills AND auto-wires the MCP server via.mcp.json, with no extra step.
0.8.8 — 2026-04-14
Behavior change: per-observation LLM compression is now opt-in. If you were relying on LLM-generated summaries (the old default), set AGENTMEMORY_AUTO_COMPRESS=true in ~/.agentmemory/.env and restart.
- Stop silently burning Claude API tokens on every tool invocation (#138, thanks @olcor1) — the old
mem::observepath firedmem::compressunconditionally on every PostToolUse hook, which called Claude via the user'sANTHROPIC_API_KEYto turn each raw observation into a structured summary. An active coding session (50-200 tool calls/hour) could run through hundreds of thousands of tokens in minutes, which is the exact opposite of what a memory tool should do. The new default path skips the LLM call and uses a zero-token synthetic compression step that derivestype,title,narrative, andfilesfrom the raw tool name, tool input, and tool output directly. Recall and BM25 search still work — you just lose the LLM-generated summaries unless you opt in.
AGENTMEMORY_AUTO_COMPRESSenv var — defaultfalse. Whentrue, restores the old per-observation LLM compression path. The engine startup banner now prints a loud warning when it's on, reminding you that it spends tokens proportional to your session tool-use frequency.src/functions/compress-synthetic.ts— the new zero-LLM compression helper.buildSyntheticCompression(raw)maps tool names toObservationType(via camelCase-aware substring matching forRead/Write/Edit/Bash/Grep/WebFetch/Task/etc.), pulls file paths out oftool_input.file_path/pattern/ etc., and truncates narratives to 400 chars so one huge tool output can't blow up the BM25 index.- Regression test
test/auto-compress.test.ts— 8 cases covering the default path (nomem::compresstrigger, synthetic observation stored in KV), explicit opt-in, tool-name-to-type mapping, file-path extraction, narrative truncation, and thepost_tool_failure→errorpath. Full suite: 707 passing.
- Startup banner (
src/index.ts:171) now prints eitherAuto-compress: OFF (default, #138)or a prominent warning when opt-in is enabled, so the mode is never silent. - Migration note: if you were running 0.8.7 or earlier with
ANTHROPIC_API_KEYset, your token usage will drop sharply on upgrade. Search quality may also drop slightly because narratives are now derived from raw tool I/O instead of Claude-generated summaries. If you want the old behavior:and restart. Existing compressed observations in# ~/.agentmemory/.env AGENTMEMORY_AUTO_COMPRESS=true
~/.agentmemory/are untouched.
0.8.7 — 2026-04-14
One-line fix for a brown-paper-bag bug reported in #136.
npx @agentmemory/agentmemoryno longer crashes with "/app/config.yamlis a directory" (#136, thanks @stefano-medapps) — the published tarball shippeddocker-compose.ymlbut notiii-config.docker.yaml, even though the compose file mounts./iii-config.docker.yaml:/app/config.yaml:ro. Docker resolves missing host-path bind sources by silently creating them as empty directories, so the iii-engine container mounted an empty dir at/app/config.yamland crashed withError: Failed to read config file '/app/config.yaml': Is a directory (os error 21). Thefilesarray inpackage.jsonnow includesiii-config.docker.yamlalongside the regulariii-config.yaml.
- New regression test in
test/consistency.test.tsparses every./<path>:<container>bind mount indocker-compose.ymland asserts the source file is shipped via thefilesarray. Catches the class of bug where a new bind mount is added to compose without a corresponding entry infiles.
0.8.6 — 2026-04-13
Finishes the npx <shim> story from #120 by moving the standalone package under the @agentmemory scope.
- Standalone MCP shim is now
@agentmemory/mcp— the 0.8.5 publish attempted to pushagentmemory-mcpas an unscoped package, but npm's name-similarity policy rejects it because of an unrelated third-party package calledagent-memory-mcp. The shim now lives under the scope we already own, sonpx -y @agentmemory/mcpworks on the live registry. All README/integration/CLI-help snippets, the OpenClaw and Hermes guides, and the Claude-Desktop/Cursor/Codex/OpenCode MCP config examples have been updated to use the scoped name. The unscopedagentmemory-mcpcommand line (in the main package'sbinfield) was never published and has been removed from the docs. - Package directory renamed
packages/agentmemory-mcp/→packages/mcp/. The.github/workflows/publish.ymlpublish step points at the new path andnpm view @agentmemory/mcpfor the propagation check. - Log prefix in
src/mcp/standalone.tsandsrc/mcp/in-memory-kv.tschanged from[agentmemory-mcp]to[@agentmemory/mcp]so stderr output matches the package users install.
- Shim version bump was missed in 0.8.5 —
packages/agentmemory-mcp/package.json(nowpackages/mcp/package.json) was still pinned at0.8.4because the release bump script only touched the 8 files in the main package. The shim now tracks the main package and depends on@agentmemory/agentmemory: ~0.8.6.
0.8.5 — 2026-04-13
Compatibility fix for stricter JSON-RPC clients, plus a spec cleanup CodeRabbit caught during review.
- MCP server works with Codex CLI and any strict JSON-RPC 2.0 client (#129) — the stdio transport was responding to JSON-RPC notifications (messages without an
idfield, e.g.notifications/initialized), which violates JSON-RPC 2.0 §4.1 and caused stricter clients like Codex CLI v0.120.0 to close the transport with "Transport closed". Notifications are now detected by the missing/nullidfield, the handler still runs for side effects, but no response is written. Handler errors on notifications are logged to stderr instead of sent back to the client. Claude Code and other clients that tolerated the spurious responses continue to work unchanged. - Request
idtype validation per JSON-RPC 2.0 §4 — the transport previously only checkedid != null, so a malformed request withid: {}orid: [1,2]could get echoed back with that non-primitive id, and valid-shape requests with bad id types fell through to the handler and produced a response carrying a bogus non-JSON-RPC id.isValidId()now enforcesstring | number | null | undefined, and bad-id requests get-32600 Invalid Requestwithid: nullbefore the handler runs. Caught by CodeRabbit on PR #131.
- 14 tests in
test/mcp-transport.test.tscovering the request path, notification path (#129), malformed input, and id-type validation (object/array/boolean). Full suite: 698 passing.
0.8.4 — 2026-04-13
Two community contributions land on top of 0.8.3 and close out the #120 npm story for real.
- Memories saved via the standalone MCP server now survive SIGKILL (#122, thanks @JasonLandbridge) —
memory_savepreviously only flushed to~/.agentmemory/standalone.jsononSIGINT/SIGTERM. If the MCP server process was killed forcefully (e.g. when an agent session ended), every memory saved during that session was lost. The save handler now persists to disk immediately after everymemory_savecall, so data survives unexpected termination. Also switched to the sharedgenerateId("mem")helper and a singleisoNowshared bycreatedAt/updatedAtso they can't drift. - OpenCode MCP config format corrected (#121, thanks @JasonLandbridge) — the README previously told OpenCode users to edit
.opencode/config.jsonwith anmcpServersobject, but OpenCode actually usesopencode.jsonwith anmcpobject,type: "local", and acommandarray. The agents table row and a new dedicated OpenCode block in the Standalone MCP section now document the correct format.
0.8.3 — 2026-04-13
Two bug fixes reported in the public issue tracker.
- Retention score now reflects real agent-side reads (#119) —
mem::retention-scorepreviously hardcodedaccessCount = 0andaccessTimestamps = []for episodic memories, and only used a single-samplelastAccessedAtfor semantic memories. Reads frommem::search,mem::smart-search,mem::context,mem::timeline,mem::file-context, and the matching MCP tools (memory_recall,memory_smart_search,memory_timeline,memory_file_history) were never recorded, so the time-frequency decay formula was a dead path. The reinforcement boost is now driven by a real per-memory access log persisted atmem:access, written by every read endpoint (fire-and-forget, so reads never block on tracker writes), with a bounded ring buffer of the last 20 access timestamps. Pre-0.8.3 semantic memories that only have the legacylastAccessedAtfield still score correctly via a backwards-compat fallback. npx agentmemory-mcp404 (#120) — the README told users to runnpx agentmemory-mcpfor MCP client setup, butagentmemory-mcpwas only abinentry inside@agentmemory/agentmemory, not a real package, sonpxreturned 404 from the npm registry. Two fixes:- Published a new sibling package
agentmemory-mcp(inpackages/agentmemory-mcp/) that is a thin shim over@agentmemory/agentmemory/dist/standalone.mjs.npx agentmemory-mcpnow works as documented. - Added a canonical
npx @agentmemory/agentmemory mcpsubcommand to the main CLI for users who already have@agentmemory/agentmemoryinstalled and don't want a second package on disk. Both commands do the same thing. - README install snippets now use
npx -y agentmemory-mcpso first-time users skip the install confirmation prompt.
- Published a new sibling package
- Concurrent access tracking is race-safe — the access log RMW is wrapped in the existing
withKeyedLockkeyed mutex, so two parallel reads of the same memory don't lose increments.recordAccessBatchusesPromise.allSettledso a slow keyed-lock acquisition on one id doesn't block the rest of the batch. mem::export/mem::importnow round-trip the access log — the newmem:accessnamespace is included in dumps and restored on import, so backup/restore cycles no longer silently zero out reinforcement signals.exportsfield inpackage.json— explicitly exposes./dist/standalone.mjsas a subpath so the shim package and external consumers have a stable contract.- CI publishes both packages on release —
.github/workflows/publish.ymlnow publishes@agentmemory/agentmemoryfirst, then theagentmemory-mcpshim frompackages/agentmemory-mcp/sonpx agentmemory-mcpworks on the live release.
0.8.2 — 2026-04-12
This release ships 6 security fixes, growth features, and a visual redesign of the README. Users on v0.8.1 should upgrade as soon as possible — the security fixes address vulnerabilities in default deployments.
Six vulnerabilities fixed, originally introduced before v0.8.1:
- [CRITICAL] Stored XSS in the real-time viewer — viewer HTML used inline
onclick=handlers while the CSP allowedscript-src 'unsafe-inline'. User-controlled tool outputs could execute JavaScript in the reader's browser. Fixed by removing all inline event handlers, adding delegateddata-actionhandling, switching to a per-response nonce-based CSP, and addingscript-src-attr 'none'. - [CRITICAL]
curl | shin CLI startup — the CLI auto-installed iii-engine viaexecSync("curl -fsSL https://install.iii.dev/iii/main/install.sh | sh"). Removed entirely. The CLI now uses an existing localiiibinary if available, or falls back to Docker Compose. Users install iii-engine manually viacargo install iii-engineor Docker. - [HIGH] Default
0.0.0.0binding —iii-config.yamlbound REST (3111) and streams (3112) to all interfaces, exposing the memory store to anyone on the local network. Now binds to127.0.0.1by default. A separateiii-config.docker.yamlhandles the Docker case with host port mapping restricted to127.0.0.1:port. - [HIGH] Unauthenticated mesh sync — mesh push/pull endpoints accepted requests without an
Authorizationheader. Mesh endpoints now requireAGENTMEMORY_SECRET, and outgoing mesh sync requests sendAuthorization: Bearer <secret>. - [MEDIUM] Path traversal in Obsidian export — the
vaultDirparameter was passed directly tomkdir/writeFile, allowing writes to any filesystem path (e.g.,/etc/cron.d). Exports are now confined toAGENTMEMORY_EXPORT_ROOT(default~/.agentmemory) viapath.resolve+startsWithcontainment check. - [MEDIUM] Incomplete secret redaction — the privacy filter missed
Bearer ...tokens, OpenAI project keys (sk-proj-*), and GitHub fine-grained service tokens (ghs_,ghu_). Added regex coverage for all three formats.
See GitHub Security Advisories for CVSS scores and affected version ranges.
agentmemory demoCLI command — seeds 3 realistic sessions (JWT auth, N+1 query fix, rate limiting) and runs smart-search queries against them. Shows semantic search finding "N+1 query fix" when you search "database performance optimization" — the kind of result keyword matching can't produce. Zero config, 30 seconds, no integration needed.benchmark/COMPARISON.md— head-to-head comparison vs mem0 (53K⭐), Letta/MemGPT (22K⭐), Khoj (34K⭐), claude-mem (46K⭐), and Hippo. 18-dimension feature matrix, honest LongMemEval vs LoCoMo caveats, token efficiency table.integrations/openclaw/— OpenClaw gateway plugin with 4 lifecycle hooks (onSessionStart,onPreLlmCall,onPostToolUse,onSessionEnd). Same pattern as the existing Hermes integration. Includes README with paste-this-prompt block,plugin.yaml, andplugin.mjs.- Token savings dashboard —
agentmemory statusnow shows cumulative token savings and dollar cost saved ($0.30/1K tokensrate). Same card added to the real-time viewer on port 3113. - Paste-this-prompt blocks — main README and both integration READMEs now open with a copy-pasteable text block users drop into their agent. The agent handles the entire setup (start server, update MCP config, verify health, open viewer).
- 60 custom SVG tags — 30 dark-bg + 30 light-bg variants under
assets/tags/andassets/tags/light/. Covers 14 section headers, 6 stat cards, 8 pill tags, and utility badges. GitHub README uses<picture>elements to auto-swap based on reader theme (dark theme → light-bg SVGs, light theme → dark-bg SVGs). - Real agent logos in the Supported Agents grid — 16 agents with clickable brand logos (Claude Code, OpenClaw, Hermes, Cursor, Gemini CLI, OpenCode, Codex CLI, Cline, Goose, Kilo Code, Aider, Claude Desktop, Windsurf, Roo Code, Claude SDK, plus "any MCP client").
- README redesigned from plain markdown headers to SVG-tagged sections matching the agentmemory brand palette (orange
#FF6B35 → #FF8F5Eaccent on dark#1A1A1Abackground). - Hero stat row replaced with 6 custom SVG stat cards showing 95.2% R@5, 92% fewer tokens, 43 MCP tools, 12 auto hooks, 0 external DBs, 654 tests passing.
- Supported Agents grid reordered: Claude Code, OpenClaw, and Hermes now lead the first row (the 3 agents with first-class integrations in
integrations/). - Viewer token savings card now shows dollar cost saved alongside raw token count.
- Default configuration files updated:
iii-config.yamlbinds to127.0.0.1, newiii-config.docker.yamlfor Docker deployments.
- Viewer cost calculation was 100x under-reporting — the formula
tokensSaved / 1000 * 0.3returns dollars but was treated as cents. Now computescostDollarsfirst, thencostCents = Math.round(costDollars * 100). 100K tokens now correctly displays$30.00instead of30ct. ObservationTypeunion missing"image"—VALID_TYPESincompress.tsincluded"image"but the TypeScript union intypes.tsdidn't, breaking exhaustive checks.- Dynamic imports inside eviction loops —
auto-forget.tsandevict.tscalledawait import("../utils/image-store.js")inside nested loops. Hoisted once at the top of each function. - OpenClaw
/agentmemory/contextpayload — plugin was sending{ tokenBudget, query, minConfidence }but the endpoint expects{ sessionId, project, budget? }. Fixed to match the server contract. - Cursor cell in README grid was missing its
<strong>Cursor</strong>label. - Codex CLI logo URL returned 404 from simple-icons CDN. Switched to GitHub org avatars for all logos for maximum reliability.
- 654 tests (up from 646 in v0.8.1), including 8 new tests covering viewer security, mesh auth, privacy redaction, and export confinement.
- All 60 custom SVGs validated with
xmllintin CI-ready fashion. - README consistency check updated to match new tool counts.
0.8.1 — 2026-04-09
- Fix viewer not found when installed via npx (#109)
0.8.0 — 2026-04-09
- Initial 0.8.x release