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.
0.9.33 — 2026-11-09
- agentmemory now pins iii 0.25.1 (engine,
iii-sdkand@iii-dev/helpers) with state 0.22.22 and http 0.22.8. The first start after the upgrade installs them (#1634, #1694). GET /agentmemory/memoriesandGET /agentmemory/relationswithoutlimitreturn 413 with a paging hint when the full list is larger than the transport limit, as/semanticand/proceduralalready did. Use?limit=NandnextCursor. The viewer and CLI already page (#1636).- Docker installs: the root and Coolify Compose files now forward
AGENTMEMORY_LLM_PROVIDER. A provider key alone does not turn on LLM features; setAGENTMEMORY_LLM_PROVIDERto the provider whose key you configured. Docker installs that set only a key ran without LLM summaries since 0.9.32 (#1700).
- State scopes above 64 MiB keep working. Whole-scope reads page through
state::list_keysinstead of one frame, and mesh export pages when givenlimitorcursor(#1636). The transport cap is 64 MiB, up from 16 MiB (#1634). GET /agentmemory/sessionsfilters bystartedAfter,startedBefore,endedAfterandendedBefore(#1527 by @yxtay).AGENTMEMORY_SUMMARY_TIMEOUT_MSsets the summary budget for large chunked sessions on slow or local LLMs (default 120 s) (#1689).memory_diagnoseandmemory_healhave afacetscategory that finds and removes facets whose target was deleted (#1698).
- Search: saved memories are no longer capped at three per search (#1696). Evicted memories leave the search indexes (#1601 by @DimitriChrysafis). Boot detects historical gaps in a partially embedded vector index (#1687 by @mvanhorn). CLIP text queries use the CLIP text tower, so text-to-image search returns matching images (#1250 by @anhtahaylove).
- Hooks: PreToolUse sends its context in the hook envelope, so the model sees it (#1693). Enrichment is scoped to the current project (#1220 by @devon3000). The Claude Code SessionEnd hook has time to finish (#1692). Captured text is redacted before it is cut to length, and compound secret key names are redacted (#1695, #1701). Cursor subagent stop type and summary fields are mapped (#1684 by @mothieras).
- Providers: placeholder keys such as
sk-...count as unset when agentmemory picks the LLM provider (#1588 by @dmazhukov). A success clears the circuit breaker failure count (#1350 by @redeye1011), and content-filter rejections no longer open the breaker (#1277 by @dKaulig). - The MCP shim waits 190 s for proxied calls instead of 15 s, past the server's 180 s limit, so long consolidate and reflect calls finish (#1691).
memory_action_createrecords the creating agent (#1697). - Consolidation keeps provenance and version heads across retries, and saved pattern memories reach the procedural tier (#1545, #1690). Reflection bounds its evidence and insight responses and keeps other projects' crystals out of a scoped reflection (#1544).
healthreports CPU relative to the machine's cores, not one core (#1286 by @DanielCarmingham).agentmemory demostops the Compose workers it started on Windows (#1688 by @Mike-Animal-Counseling). Generated Compose values keep newlines (#1708 by @zhichao-poper).- Fresh installs retry the iii engine download up to three times within two minutes on network errors, timeouts and HTTP 408, 429 and 5xx responses, and wait as long as
Retry-Afterasks (#1719). agentmemory connecthonorsCLAUDE_CONFIG_DIRfor Claude Code detection, MCP configuration and hooks (#1703 by @mothieras).
@agentmemory/pi0.1.1 and@agentmemory/fs-watcher0.2.0 (#1683). GitHub Actions bumps (#967, #1473). Config reference env count regenerated (#1705). The Windows release gate fails when its leftover-process query fails (#1711), and the CLIP tests check both towers (#1712). The release gate runs the packed package on Linux x64 and arm64, macOS arm64 and Intel, and Windows x64 and arm64 (#1716).
0.9.32 — 2026-11-04
- Breaking: an API key alone no longer turns on an outside provider. LLM summaries, compression, consolidation and reflection run only when
AGENTMEMORY_LLM_PROVIDERnamesanthropic,openai,gemini,openrouterorminimaxand that provider's key is set.AGENTMEMORY_ALLOW_AGENT_SDK=truestays the other route. Cloud embeddings run only whenEMBEDDING_PROVIDERnames the provider;EMBEDDING_PROVIDER=localstays on-device, and unset means BM25 and graph search only. If a key is present without a choice, boot,doctor,statusand the viewer name the exact line to add (#1664). OPENAI_API_KEY_FOR_LLMis removed. SetAGENTMEMORY_LLM_PROVIDERinstead (#1664).- Hooks send nothing to a remote
http://server. A non-loopbackAGENTMEMORY_URLmust use HTTPS; captures for a plain-HTTP remote server are dropped, not spooled. The secret is sent only to loopback or HTTPS addresses (#1664). - The PreCompact hook prints stored memory only with
AGENTMEMORY_INJECT_CONTEXT=true, the same gate as SessionStart (#1664). - The Claude Code plugin asks for the server URL and secret through plugin settings. The secret is kept in the system credential store. The Devin plugin no longer forwards
AGENTMEMORY_SECRETfrom the environment (#1664).
- iii installs itself on Windows. A fresh
agentmemoryon win32 downloads the pinned iii zip, checks its SHA-256 and extracts it with the systemtar.exe, falling back to PowerShellExpand-Archive(#1670). - MCP tools carry
readOnlyHintanddestructiveHintannotations, and the plugin README states what the hooks record, where it is kept and how to delete it. Privacy policy: https://agent-memory.dev/privacy (#1664). memory_lesson_saveacceptssourceIds(#1661).- agentmemory is listed in the OpenAI plugin directory for Codex (skills; pair with
agentmemory connect codex), the Hermes plugin catalog and ClawHub. For Hermes and OpenClaw, install withhermes plugins install agentmemoryoropenclaw plugins install clawhub:agentmemory; the README and the Hermes and OpenClaw guides describe both routes besideagentmemory connect. - Each published release builds a
linux/amd64andlinux/arm64image and pushes it to Docker Hub asghumarerohit/agentmemory:<version>;latestfollows the highest stable version (#1677). - The MCP stdio shim records why it exits in
mcp-crash.login the data directory (owner-only, rotated at 1 MiB) and saves its fallback store before writing to stderr (#1662, #1674).
- Worker Compose starts on native Windows. Worker commands, the worker PATH and project ownership checks with
\\?\and 8.3 paths are fixed;agentmemory stopwaits long enough for every worker (#1641). The launcher retries a slowiii --versionprobe and never waits on a hidden install prompt (#1658).doctordoes not prompt without a terminal or withCIset (#1671).statusandstopoutput no longer include iii SDK debug lines (#1672). - Boot no longer races the state worker. agentmemory waits up to 120 s for the state worker to register before boot reads, and the keyword rebuild keeps retrying, so a slow start no longer leaves vector recovery paused or the keyword index empty until restart (#1627 by @cbsincool, #1626 by @Tyxiel, #1660).
- A stale Worker Compose PID reused by an unrelated process after a reboot no longer causes a start crash loop (#1622 by @pei711).
- The Docker image keeps the optional dependencies that local embeddings need (#1651 by @mothieras).
- Slot tools are hidden and return 503 when
AGENTMEMORY_SLOTSis off (#1659). - Search: CJK queries recall core observations again (#1553 by @akushonkamen); scoped smart-search fills short pages from a deeper window (#1669 by @dmazhukov); project-filtered recall excludes unscoped memories (#1647 by @reevesc88); search responses keep the original memory type (#1646 by @reevesc88).
- An OpenAI reply cut off at
max_tokensfails over instead of being stored as the result (#1495 by @Rex57). - Orphaned index generations are reclaimed (#1256 by @inix-x), and the MCP graph stats resource reads a bounded snapshot instead of listing the whole graph (#1260 by @inix-x).
- Facet tags are removed when lessons are deleted or observations forgotten (#1642 by @xh123637). The session sweep skips rows without an id (#1645 by @dmazhukov). Hook truncation keeps surrogate pairs whole (#1598 by @dmazhukov).
- Copilot CLI subagent reports are stored with their reply. The
subagentStophook reads Copilot's camelCase fields, so a report is no longer empty and a retry is no longer stored twice. The reply is redacted before it is cut to 4000 characters (#1599 by @dmazhukov). - The Hermes project git probe no longer inherits the worker's stdin, which could hang on Windows (#1663). The Cline CLI MCP configuration uses its native settings path (#1633).
- A superseded memory gets a strictly later
updatedAt, so mesh sync carries the change to peers (#1665 by @egantz). - pi includes recalled lessons in search and can read a full lesson by ID, scoped to its project (#1605 by @YeChenglin8888).
npm run buildworks under the Windowscmd.exeshell (#1362 by @mattamundson)..env.examplenames the Agent SDK route and documentsMAX_OBS_PER_SESSIONas a hard per-session cap (#1675, from #1503 by @Rex57).- The Claude Code plugin passes its URL and secret settings to the MCP server as
CLAUDE_PLUGIN_OPTION_AGENTMEMORY_URLandCLAUDE_PLUGIN_OPTION_AGENTMEMORY_SECRET, the names the plugin directory accepts. An empty URL setting no longer hidesAGENTMEMORY_URLfrom the environment, and an empty secret setting still never sendsAGENTMEMORY_SECRETfrom the environment.
- The Claude Code plugin hooks run in exec form (
commandplusargs), so the plugin path reaches Node as one argument with no shell quoting. The plugin andconnect claude-code --with-hooksnow need Claude Code 2.1.139 or later.
- On Windows,
agentmemory stoptakes about 60 s and each start opens empty console windows for the engine and workers. Both come from iii (iii-hq/iii#2430).
0.9.31 — 2026-10-25
- The runtime moves to iii 0.25.0 and Worker Compose. Stop the existing instance with its old CLI before upgrading, then restart with the same instance, port and data directory. File state, the daemon secret and Docker data volumes are preserved. The CLI no longer uses
AGENTMEMORY_USE_DOCKER,AGENTMEMORY_III_CONFIGor customiii-config.yamlfiles; Docker deployments use the shared deployment image. Follow the upgrade guide for these installation changes. - Viewer updates use authenticated SSE on the REST port at
/agentmemory/viewer/events; port 3112 is unused.agentmemory consolenow prints migration guidance and the viewer URL. The viewer remains on port 3113 by default. Status reports the configured engine pin asservice.enginePinnedVersioninstead ofengineVersion. - Narrative recall now returns structured JSON through MCP. Read the
textfield for the narrative and the accompanying budget metadata for omitted or shortened results. See recall guidance. - Full historical vector recovery requires
AGENTMEMORY_VECTOR_BACKFILL=allon each start and processes at mostAGENTMEMORY_VECTOR_BACKFILL_MAXmissing records per start. Keyword search remains available while recovery is paused. See vector recovery before rebuilding an old index. - Re-run
agentmemory connect pi --with-mcporagentmemory connect omp --with-mcpafter upgrading to refresh their bundled paths and skills. Existing DSH hook-bridge installations migrate withagentmemory connect dsh --with-hooks --force; the connector backs up configuration and preserves unrelated entries.
- Installable Pi package and native OMP integration. Pi's
@agentmemory/pipackage contains the compiled extension and shared skills. Both connectors install project recall, capture, native memory tools and optional MCP, with bounded offline capture queues. The connector works before the separate Pi package's first npm publication. - Native DSH capture ships inside AgentMemory, with prompt, tool and assistant-reply capture, privacy filtering and offline recovery. No separate capture package is needed (#1609, including instruction-file setup by hejiawow).
- Cursor workspace resolution maps lifecycle hooks to the correct project using validated paths and local session metadata, with detached stop/session-end delivery (#1112).
- Paged exports support
collectionLimit,collectionOffsetandcollectionsthrough REST and MCP. Partial exports cannot be imported withstrategy: "replace". - Compression recovery preserves searchable captures after optional model compression fails.
agentmemory compressioninspects failures and supports scoped retries; summary repair resumes after late capture and restart.
- Saved-memory recall preserves project and agent scope, supports memory-only retrieval and retains recovery references when a token budget omits content. Graph retrieval uses bounded shared reads and keeps each observation's best score; optional reranking uses the model's actual paired-query scores.
- Vector recovery retains unfinished work across checkpoints, provider failures and restarts. Redis state mutations serialize per key within a worker, and deletion keeps graph and facet indexes consistent.
- Imports validate collection shapes and row keys before a replace operation deletes stored data. The import observation ceiling no longer changes with the ordinary capture limit.
- Hooks capture final assistant replies and distinguish separate subagent, task and notification events. Structured redaction preserves identifiers and retained custom-event content remains searchable.
- MCP keeps routine logs off stdout and reports when a write only reached its local fallback store. The viewer loads actions beyond the first page.
- JSONL import keeps real session times and no longer duplicates on re-import.
parseJsonlTexttookstartedAt/endedAtfrom the first and last line even when it was a timestampless metadata entry (last-prompt,cost-state), so the session got the import time. It now uses only entries that carry a timestamp. Observation ids are derived from the entryuuid(or session id and line position when absent) instead of a random id, so importing the same transcript again overwrites the same rows, andobservationCountcounts only rows that were new. Rows imported by earlier versions keep their random ids, so the first re-import after upgrading adds one last copy. - Session summaries cover the whole session again (#745). 0.9.30 completed a session on the first per-turn Stop and ignored every later end, so summaries and graph extraction stopped at turn 1.
mem::observenow reopens a completed session when new observations arrive, the Stop hook sendsfinal: falseso the session stays open, and an idle finalizer completes it once nothing has happened forAGENTMEMORY_FINALIZE_IDLE_MS(default 2 minutes). SessionEnd, the CLI and the OpenCode plugin sendfinal: trueand complete at once; a request without the flag behaves as before. The sweep summarizes a session before marking it abandoned (#737). - The Devin plugin captures sessions. A plugin install loaded
hooks/hooks.json, whose capitalized Claude Code matchers never match Devin's tool names and whose extra events Devin rejects, so capture never fired.plugin/hooks.jsonnow carries the six Devin hooks with lowercase matchers, and Devin loads it first. Verified on Devin CLI 3000.11.3: one session recorded session start, prompt, tool use and session end. - Summaries are incremental.
mem::summarizekeeps a watermark (coveredThrough) and summarizes only the observations captured since the last run, merging them into the stored summary with one reduce call. A session end with nothing new costs no LLM call, and the reflect, graph and skill fan-out is skipped for it.
- Publishing verifies the exact gated tarballs. The workflow checks SHA512 integrity and signed provenance against the source repository, workflow, ref and commit before accepting an existing version or completing publication. Conflicting artifacts fail instead of being skipped.
- Shared agent skills now describe the current runtime, credential discovery, native integrations and capture limits. The README and translations link to current setup, storage and upgrade guidance.
- The Devin plugin manifest adds a display name and logo, says it is for Devin CLI and Devin Desktop only, and runs
@agentmemory/mcpat the release version instead of the latest one.npm run docs:syncmoves that pin on each version bump. @agentmemory/mcppins the exact matching@agentmemory/agentmemoryrelease instead of a~range, so an installed shim never resolves a newer runtime than the one it was published with.
0.9.30 - 2026-10-06
Scale, durability and safety release. The iii engine moves from 0.11.2 to 0.22.1. The stores that grew without bound on shared daemons (graph provenance, the audit log, the vector index, the viewer stream backlog) are bounded and heal themselves at boot. Capture is durable end to end: the server accepts each observation into a persistent inbox with a restart-safe event id, and hooks keep an offline spool while the server is down. Vectors survive a force-kill through a pending log. The REST API requires auth by default. Redis becomes an opt-in state backend, and the viewer is rebuilt around one snapshot plus live stream events with a Health page backed by GET /agentmemory/status. Every publish now goes through a release gate that installs the packed tarballs and runs capture and recovery against them. Contributions from david-waltermire, a652, cbsincool, dmazhukov and Tyxiel, with earlier work by DaveCole, Srinath279, joyjit and cristianbdev carried into merged PRs.
- Auth is on by default (#1462). When
AGENTMEMORY_SECRETis not set, the server generates a secret into~/.agentmemory/secret(mode 0600) on first start. The CLI, viewer, hooks, MCP server and shim,agentmemory connectconfigs and the bundled integrations read it for loopback URLs, so they keep working with no change. Hand-written requests to:3111now needAuthorization: Bearer $(cat ~/.agentmemory/secret). An explicitAGENTMEMORY_SECRETstill wins, and mesh sync still requires an explicit one. - File import and export paths are confined (#1462).
/compress-file,/replay/import-jsonl,/graph/import-graphify, the Obsidian export and/migrateresolve symlinks and only accept paths inside the data dir,~/.agentmemoryor a directory listed inAGENTMEMORY_IMPORT_ROOT./replay/import-jsonlalso keeps its default~/.claude/projects. - Browser writes need JSON and an allowed origin (#1462).
POST,PUT,PATCHandDELETErequests with a body must sendContent-Type: application/json, and a presentOriginheader must be a loopback origin for the configured ports, the viewer's own origin, or listed inVIEWER_ALLOWED_ORIGINS. Clients that send noOrigin(CLI, hooks, MCP, curl) are unaffected. AGENTMEMORY_VECTOR_BACKFILL_MAXis now a batch size (#1467). Recovery re-embeds missing vectors in batches of this size until the backlog is empty, across restarts, instead of stopping at the cap once per boot.- iii engine 0.22.1 (#1396, #1397). Keep the
iii-prefixed builtin worker names (iii-http,iii-state,iii-queue,iii-pubsub,iii-cron) in any custom config: on 0.22.1 the bare names resolve to standalone registry workers. - Hooks skip agentmemory's own tools (#1452). PostToolUse no longer captures
memory_*MCP calls ortoolsearch,listmcpresourcesandfetchmcpresource. - Changed response shapes.
mem::forget,mem::governance-deleteandmem::governance-bulkcount only records that were really deleted. Absent ids come back innotFoundand failed deletes infailedandfailures, withsuccess: falsewhen anything failed.governance-bulkrefuses an empty filter and unsupported keys on both the dry run and the live call (#1449).GET /agentmemory/auditand thememory_auditMCP tool return{ entries, legacyFrozen, legacyFrozenBytes }; the MCP tool used to return a bare list (#1419).GET /agentmemory/memoriesreturns newest first and addsnextCursor(plussearchandfacetswhen requested) (#1433).GET /agentmemory/exportreturns 413 with the refusal body (oversized,bytes,limitBytes,stoppedAt) instead of 200 when the export is too large (#1422, #1449).POST /agentmemory/session/endfor an unknown, malformed or already completed session returns 200 withended: falseand writes nothing (#1252).memory_patterns/mem::patternsreads the 50 most recent sessions by default (limit, max 500) and stops after 5,000 observations (#1424).- Consolidation decay applies at most once per decay period, and
results.decayreports{ scanned, written }per tier (#1417).
- Scripts or tools that call the REST API by hand on
:3111: addAuthorization: Bearer $(cat ~/.agentmemory/secret), or set your ownAGENTMEMORY_SECRETand send that. - Imports or exports from folders outside
~/.agentmemoryand the data dir: list those folders inAGENTMEMORY_IMPORT_ROOT(separate several with:, or;on Windows). - A web page on another origin that writes through the viewer: add its origin to
VIEWER_ALLOWED_ORIGINS. - Nothing else is required. Stores load unchanged, and the one-time migrations below run by themselves.
- Graph provenance is compacted once in the background. Every node, edge, superseded edge and the cached snapshot is trimmed to 32 observation ids in slices, without blocking boot, search or the viewer. Progress is saved and resumes after a restart.
AGENTMEMORY_GRAPH_COMPACT_ON_BOOT=falseskips it;POST /agentmemory/graph/compactruns it by hand (#1455). - The audit log moves to monthly scopes (
mem:audit:YYYY-MM) with a one-time background migration. A legacy scope larger thanAGENTMEMORY_AUDIT_MIGRATE_MAX_BYTES(default 32 MiB) or unreadable is left frozen and reported aslegacyFrozen(#1419). - The vector index migrates to buckets (
AGENTMEMORY_VECTOR_BUCKET_SIZE, default 500) by copying vectors, with no embedding calls. BM25 is no longer persisted and is rebuilt at every boot (#1416). - State is saved every 2 s instead of 5 s, and
agentmemory stopwaits for the engine flush, so it takes a few seconds longer (#1457, #1449). - Stale sessions are marked abandoned after
AGENTMEMORY_SESSION_SWEEP_STALE_HOURS(default 24) by an hourly sweep that deletes nothing (#1453). - Viewer stream groups. Observations stop writing to per-session
mem-livegroups and the sharedviewergroup is capped atAGENTMEMORY_VIEWER_STREAM_MAX(default 500). Existing per-session groups are left in place (#1420).
- Durable capture (#1460). Hooks send a stable event id with every observation (the host tool use id when present, otherwise a hash of the event). The server writes each event to a capture inbox before storing it, keeps completed ids for
AGENTMEMORY_CAPTURE_DEDUP_HOURS, and answers a replay with the existing observation. Failed writes retry with backoff, also after a restart, and end as dead letters shown on/status, the viewer Health page andGET /agentmemory/capture, withPOST /agentmemory/capture/retryto retry them. - Offline hook spool (#1460, #1468). When the server is down, times out or returns a 5xx, hooks keep a copy of the observation in a bounded private spool under the data dir until the engine has saved it. The spool drains at boot and from the next hook that reaches the server. New:
agentmemory capture [--drain]andPOST /agentmemory/capture/drain. - Vector pending log (#1467). Every vector added to or removed from the live index is also written to a small pending log. Boot replays it after the snapshot with 0 embedding calls, and whatever is still missing is re-embedded as a durable backlog that resumes after a restart instead of stopping at a 500 cap.
/statusand the viewer show the log size and a paused backfill. - Release gate (#1463).
npm run release:gatepacks@agentmemory/agentmemoryand@agentmemory/mcp, installs both tarballs into a clean home and runs named scenarios against the installed CLI: capture through the bundled hooks, offline capture recovered from the spool, replay dedup after a force kill, dead letters that survive a restart, vectors surviving a crash, stop and start, export and import, the MCP shim, the viewer and/status. A Release gate workflow runs it on Ubuntu and macOS. - Capture cost bench (#1464).
npm run bench:capture-costsmeasures disk bytes per state scope, engine and worker memory and CPU, hook latency, provider requests, agent-visible context bytes and force-kill recovery, with separate capture and recovery budgets inbenchmark/capture-costs-budgets.jsonand a figure indocs/benchmarks/capture-costs.svg. Optional Ollama, Redis and crash-offline variants. - Codex plugin package (#1459). The Codex plugin bundles a small stdio bridge that forwards tools, resources and prompts to the configured agentmemory daemon and reports connection errors instead of falling back to a separate store. Authenticated non-loopback connections require HTTPS.
npm run plugin:pack:codexbuilds a local package with the six Codex hooks and a review package without lifecycle hooks, andnpm run plugin:verify:publishedrefuses a release whose runtime, MCP shim and iii versions do not match. - Rebuilt viewer that streams every page (#1433, #1407). One snapshot on connect (
GET /agentmemory/viewer/snapshot,GET /agentmemory/counts), then live<entity>.created/updated/deletedevents with no polling. 12 tabs in four groups with live counts, deep links, keyboard shortcuts and a mobile menu, a memories detail panel with version chain, diff and provenance, sessions with an inline timeline, and a searchable graph. Cursor pagination and facets on memories, sessions and observations,GET /graph/nodeandGET /observations/locateback it. GET /agentmemory/statusand a Health tab in the viewer (#1408). One report of what is wrong and how to fix it: providers and circuit breaker, failing functions, observations missing from the search index, index save state per leg (#1415), the state backend, graph compaction progress, capture inbox and spool, ports, the pinned engine version and every feature flag. HTML for browsers, JSON otherwise.GET /agentmemory/consolidation/statusand a "Memory layers" panel (#1407).- Opt-in Redis backend for state and streams:
AGENTMEMORY_STATE_BACKEND=file|redisandAGENTMEMORY_REDIS_URL(#1425). Use one Redis server per instance, and move data withagentmemory exportandimportwhen switching. POST /agentmemory/graph/compacttrims oversized node, edge, edge history and snapshot provenance in slices (#1454, carries #1445 by david-waltermire), andAGENTMEMORY_GRAPH_COMPACT_ON_BOOTruns it once after upgrade (#1455).- Stale session sweep:
AGENTMEMORY_SESSION_SWEEP_ENABLEDandAGENTMEMORY_SESSION_SWEEP_STALE_HOURS(#1453, carries #1411 by cristianbdev). - Capture filters for hooks:
AGENTMEMORY_CAPTURE_ALLOW,AGENTMEMORY_CAPTURE_DENY,AGENTMEMORY_CAPTURE_OUTPUT_MAX(default 8000) andAGENTMEMORY_PRE_COMPACT_BUDGET(default 1500, 0 disables) (#1452, carries #994 by joyjit). AGENTMEMORY_AUDIT_INDEX_PERSIST(off by default) re-enables index persistence audit rows for debugging (#1182 by dmazhukov).AGENTMEMORY_AUDIT_RETENTION_MONTHSandAGENTMEMORY_AUDIT_MIGRATE_MAX_BYTESfor the monthly audit log (#1419).AGENTMEMORY_STATE_SAVE_INTERVAL_MS,AGENTMEMORY_INDEX_SAVE_INTERVAL_MS,AGENTMEMORY_VECTOR_BUCKET_SIZE,AGENTMEMORY_VECTOR_BACKFILLandAGENTMEMORY_VIEWER_STREAM_MAX(#1457, #1415, #1416, #1420).agentmemory consolelaunches the iii web console through the pinned engine; the "install iii console?" prompt and theskipConsoleInstallpreference are gone (#1397).- Multi-instance installs:
--instance Ngets its own port quartet, data directory and lifecycle state, and--portderives the other ports (#892). - Procedures are extracted from finished sessions when consolidation is on and an LLM provider is configured (#1407).
memory_patternstakes an optionallimit(#1424).POST /lessonsacceptssourceIds, andmem::evolvereturns 409, 400 and 404 errors (#1433).- OpenCode 2 support in the OpenCode plugin (#1476, building on #1451 by Tyxiel). One
agentmemory-capture.tsserves both plugin APIs: OpenCode 2 loads itssetup()entry and OpenCode 1.x keeps the existing hooks. On OpenCode 2 it captures prompts, tool calls with their output, the assistant's answer, step and compaction events, injects memory on every model call, and requests a summary when a run finishes. Checked in live sessions on OpenCode 2.0.24, 1.18.34 and 1.17.10.
- Repeated identical prompts are kept (#1468). Hooks whose host sends no event id or time now include the hook timestamp in the id, so typing the same prompt twice stores it twice; retries still reuse the stored id.
- Cursor prompts are stored once (#1470). A per-session prompt ledger matches the session-end transcript back-fill against live captures, so a back-filled prompt is answered as a duplicate instead of stored a second time. Live prompts are never deduped by content.
- Concurrent spool writers cannot overwrite each other (#1468), and printed recovery commands (dead letter retry, spool drain, graph compact, the status page example) send the bearer token.
- Graph provenance is bounded. Each node and edge records only its own observation ids, capped at 32, which stops huge graph rows from crash-looping the worker during search (#1454, carries #1445 by david-waltermire).
- Search skips graph retrieval when
AGENTMEMORY_GRAPH_WEIGHT=0(#1446 by david-waltermire). - A failed graph snapshot read no longer zeroes the snapshot; the delta is aborted instead (#1384 by cbsincool).
- The graph snapshot total can no longer be lower than the nodes it returns (#1385 by cbsincool).
- Ending an unknown session no longer creates a partial row that hung the sessions listing (#1252 by a652).
- Memories and vectors written just before
agentmemory stopsurvive the restart (#1449). - Forget and governance deletes count and audit only real deletions (#1449).
- Export refuses an oversized payload before assembling it and the REST endpoint returns 413; the MCP shim surfaces the refusal (#1449, #1422).
- Session and graph read-modify-write paths take locks, closing lost updates when several agents share one daemon (#1421).
- Hooks no longer exit before their observe request is sent on a slow start (#1456).
- A fresh vector index is checkpointed within 5 s and observations keep a bounded, sanitized copy of their source for replay and export (#1448).
- Runtime config is re-seeded on every start, so
--port,--instanceand data-dir changes take effect after the first run (#1396, #1397). - The "Memory elevated" alert no longer fires on a healthy process (#1409).
- The viewer stops blinking and keeps data on a failed refresh, and dashboard numbers match the API (#1407).
- Consolidation and provider detection use the same check, and functions that need an LLM show as off instead of failed (#1433).
- Worker shutdown no longer hangs when the engine is already gone (#1396).
- Fresh installs are portable and persistent, and native and Docker removal stops the worker before the engine (#892).
OPENAI_EMBEDDING_API_KEYis honored when the embedding provider is auto-detected or chosen, and wins overOPENAI_API_KEY; blank keys count as unset (#1472).- SessionStart context reaches hosts that expect structured hook output. When the hook input names the
SessionStartevent, context is returned ashookSpecificOutput.additionalContext; hosts that send no event name still get plain text (#1472).
- Request hardening (#1462, supersedes #878 by DaveCole and #922 by Srinath279). Auth on by default, origin and content type checks on writes, and confined file paths, as described under Breaking changes. Confined files are replaced only after the new content is fully written, and a destination that is a symlink is refused.
- Scrubbing on every write (#1462). Write functions run the secret scrubber on their input, and compression, summary, crystal, graph, replay, team share, session title, commit message and image description text is scrubbed before storage. New patterns cover PEM private key blocks and credentials in URLs. Stored text is escaped before it goes into the injected context block.
- Clients resolve the API secret the same way as the server (#1462): environment first, then
~/.agentmemory/.env, then the generated secret file, and the stored secret is only sent to loopback URLs. - Supply chain (#1461). The automatic engine installer verifies the downloaded archive against a SHA-256 pinned in the CLI for each platform before extracting it, and refuses an unpinned version or platform.
npm run engine:hashesrefreshes the pins. Installer paths reach the shell as arguments, so a home directory containing shell syntax is never evaluated. The CI workflow runs with read-only permissions, and the deploy Dockerfiles check that the copied iii binary matchesIII_VERSION. GET /agentmemory/statusserves HTML with no scripts under a strict CSP and the same bearer auth as the rest of the API (#1408).- The Redis URL stays out of files and output (#1425).
mem::governance-bulkcannot widen a dry run to the whole store (#1449).- The pinned engine starts with
--no-update-checkand iii's anonymous usage telemetry off (#1396). - A profile read no longer writes a
shareaudit entry (#1433).
- Vectors are stored per key in fill-and-roll buckets, so a save rewrites a few buckets instead of the whole index and the store no longer hits V8's string limit at about 49,000 vectors (#1416).
- Index saves are throttled and each leg reports its own state, so one failing leg no longer skips the others (#1415).
- The audit log lives in monthly scopes read newest first (#1419).
- Session start context and observation lookups use small secondary indexes instead of listing every session (#1418).
mem::remembercalls the embedding provider outside the global save lock (#1423).mem::patternsis bounded to recent sessions and an observation budget (#1424).- Consolidation decay writes only rows that changed (#1417).
- The viewer stream backlog is bounded (#1420).
- Faster state saves,
MALLOC_ARENA_MAX=2for the engine on Linux, and a higher open-file limit in Docker and deploy entrypoints (#1457).
- agent-memory.dev is rebuilt around use cases and sourced proof: agent sessions showing what memory changes, a view of the 1,571 tokens the next session gets out of a month of history, live GitHub and all-time npm numbers, and new /benchmarks, /security, /privacy, /changelog and /vs comparison pages. It ships robots.txt, a sitemap, llms.txt and llms-full.txt, and link previews now point at agent-memory.dev instead of a parked domain.
npm run docs:syncandnpm run docs:checkkeep the documented counts and versions in README, the translated READMEs and AGENTS.md in step with the code.- The README documents auth by default, request rules, file path roots, the capture inbox and spool, and the pending vector log (#1460, #1462, #1467).
- The README, the config skill reference and
agentmemory --helpdocumentAGENTMEMORY_III_CONFIGand the engine bind address, including the Docker engine config (#1472). - Code and tests no longer cite issue or PR numbers (#1469).
- The
index_persistaudit gating suite is restored against bucketed persistence and monthly audit scopes (#1477), originally written by dmazhukov in #1182. - Unit tests grew from about 1,700 to more than 2,400.
- Dependabot no longer proposes
iii-sdkbumps; the engine pin and the SDK move together by hand (#1396).dotenv18.0.3 (#1430) and@types/node26.6.2 (#1401, #1400). - The deploy Dockerfiles refuse to build when
III_VERSIONandIII_SDK_VERSIONdiffer (#1396). - Thanks to MarvinFS (discussion #1358), inix-x, sbynode-ux, ErikBPF and cmondragon023, whose measurements and earlier PRs shaped the scaling work.
0.9.29 — 2026-08-16
Release wave in two parts. Recall quality: hybrid ranking reaches the primary recall path, lessons get a real index, every record learns where it came from, the knowledge graph populates keyless, and agent scoping threads through all save paths — plus connector parity for pi and Codex, a new DeepSeek Harness connector, current provider model defaults, and a viewer clarity pass. Foundation: the .env file now applies everywhere, imports become searchable, consolidation runs on session stop, twelve MCP-only agents get activated on connect, and every capture surface agrees on what "project" means. No breaking changes; read the upgrade notes for behavior changes you will notice.
~/.agentmemory/.envvalues that were silently ignored by most modules now take effect on boot. If that file has stale entries from past experiments, review it before upgrading.agentmemory connect <agent>now writes a short memory-usage guideline into the agent's native rules file (Cursor, Cline, Continue, Zed, Warp, Kiro, Gemini CLI, Qwen, OpenCode, Droid, Copilot CLI, Antigravity) so MCP-only agents actually call the memory tools. Pass--no-guidelinesto opt out.- Installs with an LLM key now run consolidation and crystallization on session stop (previously they never fired), debounced to once per 5 minutes (
AGENTMEMORY_CONSOLIDATION_COOLDOWN_MS). - Local embeddings re-download once after the
@huggingface/transformersmigration (different model cache directory). Model IDs are unchanged.
-
Two new skills (15 → 17).
memory-discipline(reference) codifies the session loop the memory model expects: recall before nontrivial work, save decisions with their reasons at the moment they settle, route corrections into lessons./lesson(invocable) distills a correction into a confidence-weighted rule viamemory_lesson_save, echoing the saved rule back for veto. -
Devin support. New
agentmemory connect devinadapter wires the MCP entry into Devin CLI's user config, and--with-hooksinstalls six native auto-capture hooks (SessionStart,UserPromptSubmit,PreToolUse,PostToolUse,Stop,SessionEnd) using Devin's lowercase tool matchers — the capitalized Claude Code matchers Devin also loads never match its tool names, so capture looked wired but never fired. A Devin plugin manifest atplugin/.devin-plugin/plugin.jsonregisters all 17 skills as/agentmemory:<skill>slash commands plus the MCP server. Hook payloads now resolve the project fromDEVIN_PROJECT_DIR, and session-start context injection answers each host in its own shape (Devin'shookSpecificOutput.additionalContext, Cursor'sadditional_context, Claude Code's raw stdout). Verified against Devin CLI 3000.1.23. -
Cursor plugin. Full Cursor Marketplace plugin (
.cursor-plugin/): 7 native auto-capture hooks (sessionStart,beforeSubmitPrompt,preToolUse,postToolUse,postToolUseFailure,stop,sessionEnd), all 17 skills, and the MCP server, withAGENTMEMORY_URL/AGENTMEMORY_SECRETdeclared as dashboard-managed plugin variables. Hook scripts accept Cursor's payload dialect (conversation_idsession fallback,workspace_rootsproject attribution) without changing Claude Code behavior, and context injection answers each host in its own output shape. Cursor's CLI print mode never dispatchesbeforeSubmitPrompt, so session end backfills user prompts from the session transcript; server-side dedup absorbs the re-post where a live hook already captured the prompt. Verified end to end against Cursor 3.13.25, GUI andcursor-agentCLI. -
Write-time provenance on every record. Each observation and memory carries an immutable origin block (channel
user/agent/tool/import/shared, detail, capturedAt) stamped at capture, save, and import, and inherited through both compression paths. The base for trust-aware retrieval and ingest screening. -
similarToadvisory hint on save.mem::rememberreports a near-miss similarity match (0.4 to 0.7) back to the caller so agents can spot near-duplicates without the write being blocked. -
AGENTMEMORY_LLM_NOTHINK=1(opt-in): asks local reasoning models to skip their hidden thinking pass during graph extraction. Extraction runs faster; relation quality can drop slightly. Default behavior unchanged; documented in.env.example. -
Keyless graph extraction.
mem::graph-extractalways runs a deterministic structural pass first: files and concepts on compressed observations become nodes, and co-occurrence within an observation becomes arelated_toedge. The graph now populates without any LLM key;GRAPH_EXTRACTION_ENABLEDplus a provider key gates only the LLM pass that layers typed relations (fixes, depends_on, causes) on top. Session end fires extraction unconditionally. -
pi extension: capture parity with the Claude Code plugin. Session registration on start (after the health check populates reachability, so it fires on the first session of a fresh process), prompt capture on submit (deduped in a 5-minute client window against auto-retry re-submissions; stored with user-channel provenance), per-tool observations from
tool_result(serverinferTypeclassifies command_run / file_edit / file_read;AGENTMEMORY_TOOL_OBSERVE=0opts out), turn capture slices raised 500/4000 → 8000/8000,memory_savescoped to the current project instead of the global bucket, session end + one cross-session consolidate run on real quit only (/new,/resume,/fork, reloads excluded; no client-side summarize call —session/endalready fans out the summary, avoiding the double-summarize the Stop hook had), status checks acceptstatus: "ok", and the status refresh no longer throws a stale-context error when the session is replaced mid-health-check. Live-verified on pi v0.84.2: prompt + turn observations landed and the session closed ascompletedon quit. Codex executes only hooks with a recordedtrusted_hashand shows its "Hooks need review" approval prompt exclusively in the interactive TUI, so acodex exec-only workflow left the freshly installed hooks silently inert.connect codex --with-hooksnow warns to launchcodexonce and choose "Trust all and continue" (and to re-approve after upgrades, since refreshed paths change the hash). Found by live-testing the documented flow end to end. -
connect piactually installs. The pi adapter was a stub that printed manual copy instructions becauseintegrations/never shipped in the npm package. The extension source now ships, andconnect picopies it into~/.pi/agent/extensions/agentmemory/, which pi auto-discovers — no settings.json edit,/reloadpicks it up live. Idempotent by content compare;--forceand stale copies refresh with a backup.integrations/piis also a proper pi package now (pi-packagekeyword,pi.extensionsmanifest, peer deps on@earendil-works/pi-coding-agent+typebox; private, local installs only —pi install ./integrations/pifrom a checkout), and the extension's type import moved off the renamed upstream package name. -
DeepSeek Harness connector.
agentmemory connect dshappends an@deepseek-ai/dsh-mcp-clientrow to the home-level$DSH_HOME/cordis.patch.yml, the machine-local patch layer every Harness profile loads.--with-hooksadds full auto-capture: the bundled Claude Code hook scripts run through Harness's first-party@deepseek-ai/dsh-hooks-claude-codebridge (SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop) via a manifest written to$DSH_HOME/agentmemory.hooks.jsonwith absolute script paths. Idempotent,--forcereplaces the rows, honorsDSH_HOME. -
Viewer clarity pass. Two-pane session explorer (list beside a sticky detail panel on wide screens), dashboard stat cards that navigate to their tabs, memory and lesson rows that expand to the full stored record with raw JSON and origin provenance, type-clustered graph layout with label collision avoidance when relations are sparse, health notes translated from machine slugs into sentences, honest zero states for consolidation and graph, and the official icon as the favicon.
-
--data-dirflag andAGENTMEMORY_DATA_DIRso iii-engine state lives outside repositories, with gated legacy./dataadoption and Docker-volume preservation (#314) -
Native hooks adapter for Droid via
~/.factory/hooks.json, reusing the bundled hook scripts (#1130) -
Native hooks adapter for Antigravity CLI (agy) via a stdin bridge that normalizes agy's hook payloads onto the bundled hook scripts, with an explicit PreToolUse allow decision (#1146, thanks @berthojoris)
-
mem::graph::import-graphifyandPOST /agentmemory/graph/import-graphify: merge graphify'sgraph.jsoninto the knowledge graph with confidence tags carried over as edge weights (#1136) -
Connector guideline activation for twelve hook-less agents, with every rules-file path verified against the agent's official documentation (#1136)
-
Honest
memory_forgetreporting plus a real lesson delete path (mem::lesson-delete,DELETE-style REST route, MCP tool) (#1132) -
AGENTMEMORY_PROJECT_NAMEoverride in the OpenCode plugin (#1125) -
Provider fetches retry 429/503 honoring
Retry-Afterunder a total-elapsed budget capped below the iii invocation timeout (#1136)
- Provider default models bumped to current generations. OpenAI
gpt-4o-mini→gpt-5.6-luna, Anthropicclaude-sonnet-4-20250514(deprecated upstream, retires 2026-06-15) →claude-sonnet-5, Geminigemini-2.5-flash→gemini-3.7-flash(current stable Flash), MiniMaxMiniMax-M2.7→MiniMax-M3, OpenRouteranthropic/claude-sonnet-4-20250514→anthropic/claude-sonnet-5. The premium-model cost warning now also matches OpenAI's Sol flagship tier, and its cheap-alternative hint leads withdeepseek/deepseek-v4-flash-0731. Explicit*_MODELenv overrides are unaffected. Embedding defaults are unchanged (text-embedding-3-small,gemini-embedding-001, local MiniLM are all current). README local-model picks refreshed to the Qwen 3 / gpt-oss / DeepSeek R1 generation. - Local embeddings migrate from
@xenova/transformersto@huggingface/transformersv4 with Node 22+ support; CI now tests Node 20, 22, 24, and 26 (#479, #1096)
-
MCP protocol version negotiation. The standalone MCP server hardcoded
protocolVersion: "2024-11-05"and ignored the client's requested version, so hosts that drop that revision disconnected with-32000(#908).initializenow echoes any supported revision (2025-11-25,2025-06-18,2025-03-26,2024-11-05) and answers with the latest supported otherwise. -
Hybrid ranking on the primary recall path.
mem::search(behindmemory_recall) now ranks through the full BM25 + vector + graph fusion when the vector index is populated; it was keyword-only while only smart-search got hybrid ranking. Fusion weights normalize per item over the streams that actually ranked it, with an explicit cross-stream agreement bonus, replacing the every-enabled-stream denominator that permanently penalized single-stream hits. Result order is deterministic (score, best rank, id). -
Indexed lesson recall. Lessons get a dedicated in-memory BM25 index built lazily from one KV list and maintained incrementally on save, delete, and decay; recall previously listed and substring-scanned the whole corpus per query. A record cache beside the index takes recall to zero KV round-trips.
-
Superseded versions leave recall. Superseded memory versions are removed from the BM25 and vector indexes; the version chain stays in KV for history, but recall no longer returns an outdated fact as if current.
mem::rememberalso finds supersession candidates through the search index (top 50) instead of walking every memory per save, with a full-scan fallback while the index is cold. -
agentIdthreads through every save path (#1159, #1160, #1197). REST/agentmemory/rememberforwardsagentIdinstead of dropping it;memoryToObservation()carries the memory'sagentIdinto the search-index shape so saved memories are visible to agent-scoped search; the MCPmemory_saveschema exposesagentIdand the standalone stdio package forwards bothagentIdandproject. -
Per-session project attribution in the OpenCode plugin (#1188). Project and cwd resolve from each session's own directory at
session.created(pruned on session end) instead of module-level state that filed every session in a multi-directory OpenCode process under whichever repo loaded the plugin first. -
Prompt dedup no longer swallows prompts (#1173). Hooks hash the payload when
tool_inputis absent, so prompt_submit, notification, and lifecycle events dedup on content instead of collapsing onto one shared key that silently dropped every prompt after the first in a TTL window. -
Stop hook no longer summarizes twice (#1203). The direct
/agentmemory/summarizePOST is gone;/session/endalready fans outevent::session::stopped, which runsmem::summarize. -
Safe Docker-mode stop (#1151). The CLI refuses to adopt or signal Docker/VM port holders (com.docker.backend, vpnkit, colima) as the native engine unless
--force; Docker-mode teardown is scoped to agentmemory's own compose services instead of an unscopeddown; the native worker is reaped before Docker teardown instead of deletingworker.pidwith the process still running. -
Viewer live stream and freshness. The stream WebSocket target resolves from
/agentmemory/livez(newstreamsPortfield) instead of viewerPort-1 arithmetic, which pointed at the wrong server whenever the viewer bound a fallback port and silently degraded live updates to polling. Tab data refetches on entry (with a freshness gate), so a memory saved by the agent appears without a hard reload. -
Hermetic tests (#1178). HOME/USERPROFILE are isolated for the whole vitest run so suites stop reading the developer's real
~/.agentmemory/.env. -
Boot hydrates
~/.agentmemory/.envintoprocess.env, closing the class of "env var in .env is ignored" bugs (#1136) -
Imported and replayed observations are indexed into BM25 and the vector index, so imports are searchable (#1072, via #1136)
-
Snapshot timer actually runs, non-positive intervals clamp to the default, and snapshot creation is serialized across timer, REST, and MCP (#1006, via #1136)
-
CJK-aware dedup with NFC normalization and an exact-match fallback for short memories (#1021, via #1136)
-
OpenRouter embeddings no longer hardcode 1536 dimensions (#1002, via #1136)
-
Viewer decodes multibyte request bodies correctly (#930, via #1136)
-
Session-stop consolidation is debounced and no longer double-fires from the client hook; eviction recovery is bounded to one consolidation pass (#1087, #1131 class, via #1136)
-
/agentmemory/sessionsno longer deadlocks on large session counts (#1100, via #1136) -
Filesystem watcher validates roots before
fs.watch, fixing Node 24/26 on Linux (#1136) -
GET /agentmemory/exportand/agentmemory/mesh/exportrefuse an over-frame response instead of shipping it: a payload past the engine 16 MiB transport frame used to drop the worker and 404 every endpoint for ~1s. They now fail that one request (413 for mesh, anoversizederror for export) with a hint to narrow the range, keeping the daemon up (#1142, #890). Full pagination of the non-session collections is a follow-up. -
Claude bridge writes
MEMORY.mdunder thememory/subdirectory Claude Code actually reads (#1134) -
Hook project-resolution tests no longer depend on the checkout directory name (#1137, #1138)
-
Project-scope parity: the OpenCode plugin, Hermes plugin, Pi extension, and JSONL replay now resolve
projectthe same way the hooks do (env override, git toplevel basename, cwd basename) instead of sending raw filesystem paths, so the same repository shares one memory bucket across agents (#903, #1135); the filesystem watcher acceptsAGENTMEMORY_PROJECT_NAMEwith the oldAGENTMEMORY_PROJECTkept as a deprecated alias; replay handles Windows-recorded paths -
OpenCode file enrichment matches the agent's lowercase tool names, which the previous capitalized set never did
-
Viewer surfaces health status from non-2xx health responses (#1046)
-
Documented REST endpoint count matches the registered routes again (130)
0.9.28 — 2026-07-19
Patch release: hardens the hook runner against malformed payloads and closes a cross-agent context leak. No breaking changes; drop-in upgrade.
- Cross-agent memory leak via
POST /agentmemory/context(#1057).mem::contextand itsapi::contexthandler filtered candidate sessions byprojectonly, so underAGENTMEMORY_AGENT_SCOPE=isolatedone profile could receive another profile's session observations and summaries whenever they shared a project path — while/searchand/smart-searchalready filtered correctly.mem::contextnow applies the same agent-scope filter asmem::search(#817): explicitagentIdpins, wildcardagentId: "*"bypasses, isolated mode falls back to envAGENT_ID, and the call fails closed if isolated mode is on with no resolvable agent id. All three callers (api::context,api::session::start,event::session::started) now forwardagentId.
- Hooks crashed with exit code 1 on a
nullJSON payload (#1047).JSON.parse("null")returnsnullwithout throwing, so the existing parse guard passed it through and the firstdata.session_idaccess threw aTypeError. Because each hook calledmain()bare, that became an unhandled rejection and the host CLI (Codex CLI, Claude Code) reported "hook exited with code 1" on every affected tool call. All 13 hook entrypoints now guardif (!data || typeof data !== "object")before dereferencing, and wrap the top-levelmain()in.catch()so any hook error fails closed (silent exit 0) instead of surfacing to the host tool loop.
- Refreshed stale stats in README and AGENTS.md (AGENTS test count 950+ → 1,428+, iii-function count 50+ → 260+) plus the README source-file, LOC, function, and KV-scope counts, and regenerated the website meta snapshot for 0.9.28. Removed the rate-limited star-history chart from the README and all 11 translations.
0.9.27 — 2026-06-07
Wave release closing several breaking regressions reported against v0.9.26, plus an agent-scope isolation security fix, an iii version-pin audit fix, and a benchmark scorecard correction. No breaking changes; drop-in upgrade.
AGENTMEMORY_AGENT_SCOPE=isolatednot enforced onmem::search/POST /agentmemory/search/memory_recall/recall_context(#817). PR #654's isolation work covered smart-search,/memories,/observations, and/sessionsbut missed the BM25-only recall path. An isolated worker booted withAGENT_ID=Bcould read agent A's memories via the standard MCPmemory_recalltool.mem::searchnow applies the same filter as smart-search (wildcardagentId: "*"bypasses, explicitagentIdpins, isolated mode falls back to envAGENT_ID).recall_contextprompt also filters its kv.list memory feed by active agent. Fail-closed: if isolated mode is on and no agent id resolves from any source, the call throws rather than dropping the filter.
/graph/queryand/graph/statstimed out with"Invocation stopped"on large existing corpora (#814, PR #816). The v0.9.25 fix from #753 paginated the response but the unboundedkv.list<GraphNode>+kv.list<GraphEdge>pair still ran on every call. At 75K+ nodes the response payload exceeded the iii heartbeat budget and the worker was declared dead before the new wall-clock timer could fire. Refactoredmem::graph-extractto maintain three side-indexes (graphNameIndex,graphEdgeKey,graphNodeDegree) so every extract path is O(1), never O(n). The hot path now reads exclusively from a precomputed top-degree snapshot updated inline on every extract. Samekv.listbottleneck was also blockingmem::graph-extracton every observation capture, so the fix immediately speeds up the observation pipeline too.- All data lost on
agentmemory stopfollowed by restart (#843).runStop()killed the iii engine first, then the worker. The worker's shutdown handler flushes BM25/vector snapshots and audit rows viaindexPersistence.save() -> kv.set() -> state::set, which all routed through an iii engine that was already dead. Stop order inverted: worker first with a bumped 5s SIGTERM grace (gives a large index a real chance to commit), engine second. The "Memories persisted to disk" message now reflects actual disk state. mem::graph-snapshot-rebuildandmem::graph-resetheartbeat-crashed on legacy >25K-node corpora (#825). Both endpoints calledkv.listup front. At 75K nodes the response payload blocks the event loop inJSON.parseand the iii heartbeat starves before any wall-clock budget timer can fire.mem::graph-snapshot-rebuildnow refuses pre-flight when no prior snapshot exists, returning{ legacyCorpus: true }with operator guidance unless an explicitforce: trueflag is set.mem::graph-resetno longer enumerates anything: it writes an empty snapshot stamped withresetAtand returns. Legacy rows stay as on-disk orphans but post-resetmem::graph-extractcalls compare each name-index hit'screatedAtagainstresetAt, so older rows are treated as not-found and a fresh node is written instead of silently reconnecting to a pre-reset orphan.- Multi-instance port collisions on one host (#750, PR #815).
--port Nonly relocated REST + viewer; streams (3112) and iii engine (49134) stayed hardcoded so a second daemon collided on those WS ports regardless of--port.loadConfig()now derives streams = REST+1 and engine = REST+46023 (so the canonical 3111 → 3112/49134 default is unchanged, and--port 3211→ 3212/49234). New--instance Nshortcut picks a 100-port block:--instance 1→ 3211/3212/3213/49234. Per-port env overrides (III_STREAM_PORT,III_ENGINE_PORT,III_ENGINE_URL) still win. - iii console install pulled latest engine instead of the pinned v0.11.2 (audit).
III_CONSOLE_INSTALL_CMDrancurl -fsSL https://install.iii.dev/iii/main/install.sh | shwith no version pin. A fresh first-run prompt could install a console build that talks a different protocol than the engine agentmemory pins. The install script reads aVERSIONenv var (engine_version="${VERSION:-}"in install.sh), so the command now passesVERSION=${IIPINNED_VERSION}. Render path is platform-aware too: Windows users get a PowerShell-friendly hint instead of a POSIX command they can't run. Mismatch error text updated from "reinstall the latest binary" to reference the pinned version explicitly.
- Corrected coding-agent-life-v1 P@5 numbers in the published scorecard (#796, PR #805). The original scorecard reported P@5 = 0.578 / 0.267, generated before PR #562 changed the P@K denominator from
topK.lengthtok. On the current formula those numbers are mathematically impossible (math ceiling at K=5 on this corpus is 0.240). Re-scored on v0.9.26: hybrid 0.240 / R@5 1.000, grep 0.227 / R@5 0.967. Reframed lift as recall + temporal not aggregate precision; aggregate P@5 saturates on a small / single-gold corpus and can't differentiate top-tier adapters. - README refresh (PR #807). Stats line bumped to 174 files / 1,390+ tests / 258 functions. Corrected hero P@5 numbers. "New in vX.Y.Z" callout block removed since that pattern went stale every release; latest release notes link points at CHANGELOG.md.
import-jsonlusers warned about Claude Code'scleanupPeriodDays. Default 30-day auto-deletion of~/.claude/projects/*.jsonldoesn't affect hook-wired installs (each turn lands in iii state while the session is live), but fresh installs on months-old Claude Code histories silently lost anything older than 30 days. README now flags this with three workarounds: cron the import, raisecleanupPeriodDays, or wire hooks.
POST /agentmemory/graph/snapshot-rebuild— pays the full enumeration cost once on corpora ≤ 25K nodes, persists a top-degree subgraph + aggregate counts, refuses with{ success: false, tooLarge: true, totalNodes, ceiling }above the safe ceiling instead of killing the worker. Strictforce: trueboolean check bypasses the legacy-corpus pre-flight refusal.POST /agentmemory/graph/reset— clean-restart escape hatch for legacy corpora. Enumeration-free: writes empty snapshot withresetAtepoch marker. Future extracts treat any pre-resetAtrow as orphan viacreatedAtcomparison.--instance NCLI flag — multi-daemon convenience. Picks a 100-port block off the 3111 base. Max N=50.GraphSnapshot.topDegrees— synchronous degree lookup keyed by nodeId so re-ranking after edge writes runs sync over numbers instead of async kv.get inside the sort comparator.GraphSnapshot.resetAt— ISO timestamp set bymem::graph-reset. Drives post-reset orphan detection in extract.GraphQueryResult.fromSnapshot+GraphQueryResult.warning— response fields the viewer can use to surface "served from cache" or "rebuild needed" banners instead of opaque 500s.
- REST endpoint count: 126 → 128.
POST /agentmemory/graph/snapshot-rebuildandPOST /agentmemory/graph/resetadded. mem::graph-statsnow reads exclusively from the snapshot. Returns{ ..., fromSnapshot, warning }envelope when snapshot is absent; never returns a 500.mem::graph-queryempty-body / nodeType-only path reads exclusively from the snapshot.startNodeId/querypaths keep the live enumeration behind a 6s budget with snapshot-backed fallback on rejection.mem::searchover-fetch triggers when agentId filtering is active (not just project/cwd). Without it, isolated-mode pages were silently underfilled when same-agent matches ranked below cross-agent ones.
mem::graph-queryBFS (startNodeId) and text-search (query) paths still callkv.listand degrade past ~25K nodes on fresh corpora (#828). The hot path stays safe (snapshot-only). A per-node adjacency index is the right next fix; deferred to the structured graph migration milestone (#309)./agentmemory:forgetskill still callsmemory_governance_deletewhich only touchesKV.memoriesand never observations (#833). Skill rewrite + newmemory_forgetMCP tool tracked separately.crypto.randomUUID()global-only on Node <19 (#715). Drop-in import fix tracked.
0.9.26 — 2026-06-03
Hotfix on top of v0.9.25. The first-run boot crashed for users without a persisted index because the load path didn't handle undefined returns from iii-state adapters.
- First boot crash:
TypeError: Cannot read properties of undefined (reading 'v')(#797). The sharded index load path (loadShardedData) checkedmanifest.value !== nullbefore forwarding toloadManifestData. Some iii-state adapters returnundefined(notnull) for a missing key, soundefined !== nullwas true andloadManifestData(undefined, ...)immediately threw onmanifest.v. Now treats bothnullandundefined(plus non-object values) as "no manifest" and falls through to the legacy load path. Self-healing: the next debounced save rebuilds a fresh manifest, so the crash was already cosmetic for ongoing operation — but it scared every fresh upgrader. Tests cover both undefined and wrong-shape manifest rows.
0.9.25 — 2026-06-03
Bug-fix wave closing every breaking regression reported against 0.9.24, plus a feature lane (graph pagination + smart-search followup diagnostic + obsidian-export hardening + sharded index persistence). Eleven issues closed. No breaking changes; drop-in upgrade.
- Cross-provider fallback always 404'd and tripped the circuit breaker (#778, PR #791).
createFallbackProvidercopied the primary provider'smodelinto every fallback config. With OpenAI primary + Gemini fallback, Gemini was called withgpt-4o-miniand 404'd on every call, tripping the circuit breaker and blocking downstream LLM ops. Each fallback now resolves its own env-driven default (OPENAI_MODEL/GEMINI_MODEL/ANTHROPIC_MODEL/MINIMAX_MODEL/OPENROUTER_MODEL). import-jsonlaborted entire batch on legacy session row missingid(#775, PR #791). Existing-session branch re-keyed onexisting.idwhich could be undefined for older rows.JSON.stringifydropped the key from thestate::setpayload, the engine returnedmissing field \key`, and the rejection aborted the whole handler. Now re-keys onparsed.sessionIdand backfillsexisting.id`.parseSummaryXmlsilently dropped summaries wrapped in markdown fences (#783, PR #791). DeepSeek / GPT / occasionally Anthropic responses wrap structured XML in```xml ... ```fences with optional conversational text. The raw payload went straight to the tag regex and returnedparse_failed. NewstripXmlWrappers()peels markdown fences + pre/postamble; final-merge parse path retries once on failure (matching chunk-level behavior).sdk.triggerVoid is not a functionon iii-sdk 0.11.2 (#758, #726, PR #773). iii-sdk 0.11.2 removedtriggerVoidin favor oftrigger({ action: TriggerAction.Void() }). Nine call sites still used the removed API; six ran without try/catch and threwTypeError, breaking image lifecycle, disk-quota cleanup, vision embeddings, and observation write paths.- pi integration recorded every observation as "No content provided" (#759, PR #772). pi sent
data.input/data.outputbutobserve.tsreadsdata.tool_input/data.tool_output. Field-name mismatch leftraw.toolInput/raw.toolOutputundefined; the compress pipeline produced empty observations. - Fresh global install refused to boot when PATH iii didn't match the runtime pin (#752, PR #774). The hard-pin enforcer told users to overwrite their global iii with v0.11.2, but the v0.11.2 release ships only
iii(notiii-init/iii-worker) on some platforms. agentmemory now installs to~/.agentmemory/bin/and auto-falls-back to it when PATH iii mismatches the pin. User's existing iii install stays untouched. mem::obsidian-exportHTTP 500[object Object]on any record missingid(#729, PR #780).sanitize(undefined.id)threw outside the per-record try and escaped the whole handler. Four-layer hardening: id filter, safe-array / safe-string / safe-timestamp normalizers, outer try/catch, fail-safe session sort.- Concurrent agent-sdk summarize chunks failed with
too_many_chunks_skipped(#781, PR #782).AGENTMEMORY_SDK_CHILDrecursion guard mutatedprocess.envglobally; concurrent chunks underPromise.allsaw the marker and returned empty. Recursion guard now scoped toAsyncLocalStorage; theprocess.envmarker stays for cross-process hook inheritance, reference-counted so overlapping calls don't race. - Viewer #graph tab blank on large graphs (#753, PR #789).
POST /agentmemory/graph/querywith{}on an 11k+ node corpus returned HTTP 500Invocation stopped.graph/querynow acceptslimit/offset, applies a default cap (500) ranked by node degree, restricts page edges to in-page endpoints, and returnstotalNodes/totalEdges/truncated. The viewer issues a bounded initial query, distinguishes server-error from empty-corpus, renders an actionable error banner with Retry.
- Sharded BM25/vector index persistence with manifest commit/rollback (#762, PR #764, contributed by @Rokurolize). Large BM25/vector snapshots used to save as monolithic strings and failed past the iii state size ceiling. Each snapshot now writes as bounded shards under a generation-scoped prefix, with a manifest published only after all shards commit. Rollback on shard-write failure, fail-closed on length mismatch, legacy snapshot load preserved for downgrade compat. 957 LOC + 25 tests covering rollback / partial-commit / fail-closed paths.
- Smart-search followup-rate diagnostic (#771, PR #786). Disambiguates retrieval bugs from reader bugs. When an agent issues a second
smart-searchwithinAGENTMEMORY_FOLLOWUP_WINDOW_SECONDS(default 30s) and the new result set has zero overlap with the prior one, counts as a directional "first results didn't satisfy" signal. OTEL counteragentmemory.smart_search.followup_within_window_total,GET /agentmemory/diagnostics/followupREST endpoint,agentmemory statussurface, viewer-source exclusion viaX-Agentmemory-Source: viewerheader.
- Dependency bumps + zero
npm auditvulnerabilities (PR #779).@anthropic-ai/sdk0.93 → 0.100.1,tsdown0.20.3 → 0.21.10 (stays on Node 20 floor),@types/node25.7 → 25.9, websitenext16.2.6 → 16.2.7 + React 19.2.7.iii-sdkstays pinned at 0.11.2. Transitive vulns closed via overrides:qs ^6.15.2,ws ^8.21.0,protobufjs ^7.5.8.npm auditroot + website: 8 → 0. - REST endpoint count: 125 → 126 (new
/agentmemory/diagnostics/followup).
- 1379 tests passing (up from 1314 in v0.9.24). 13 new test files covering the regressions + features above.
- Removed
website/package-lock.jsonfrom git tracking; root.gitignorealready forbade lockfiles.
0.9.24 — 2026-05-29
Hotfix on top of v0.9.23. Two bugs surfaced in the first hour after v0.9.23 hit npm:
agentmemory --versionsilently launched the server instead of printing the version string.-vflag was reserved by--verbose, and no--versionliteral was handled — falling through to the defaultstartcommand. Now--version(and-Vcapital, per POSIX convention) printsVERSIONand exits 0 before any side effects (engine boot, dir mkdir, env loading).- iii-engine version pin was warn-only, not enforced. When the engine on
PATHdidn't match agentmemory's pinned version (currentlyv0.11.2), the worker still booted against the mismatched engine and crashed at runtime with crypticstate::list not found(v0.13.0) or sandbox-everything traps (v0.11.6).warnIfEngineVersionMismatchrenamed toenforceEngineVersionPin— nowp.log.errors with the downgrade command andprocess.exit(1). Override escape hatch viaAGENTMEMORY_III_VERSION=<version>env unchanged (already redefinesIIPINNED_VERSIONupstream so the comparison passes for users who knowingly run against a different engine).
0.9.23 — 2026-05-28
Bug-fix + integration wave. GitHub Copilot CLI joins the supported agent matrix with plugin + hooks + MCP coverage. Three silent DX bugs fixed end-to-end: graph extraction never fired on session end, agentmemory status reported zero memories, consolidation defaulted off even with an LLM provider configured. Five additional adapters and a clearer local-LLM story for Ollama / LM Studio users. agentmemory connect now points users at npx skills add for the native-skills install path (50+ agents).
- GitHub Copilot CLI (PR #534). Full first-class support:
plugin/plugin.jsonmanifest,hooks.copilot.jsonlifecycle hooks for all 11 Copilot events with camelCase payload normalization,agentmemory connect copilot-cliMCP path, first-run onboarding default-select viaCOPILOT_CLI/COPILOT_AGENT_SESSION_IDenv detection, Windows-safecmd.exe /d /s /c npxwrapper. Standalone MCP transport now speaks LSP-styleContent-Lengthframed JSON-RPC alongside the existing newline-delimited form so Copilot's stdio init handshake works. - Five new MCP adapters (PR #677). Warp, Cline, Continue, Zed, and Droid.
createJsonMcpAdapterextended withwrapperKey(Zed usescontext_serversinstead ofmcpServers) andextraEntryFields(Droid requirestype: "stdio").ADAPTERScount: 11 → 17. /agentmemory/graph/buildendpoint (PR #698). Backfills the knowledge graph from existing compressed observations across every session in configurable batches. Wires up the viewer's "Build Graph" button that previously returned 404.- 11 README translations + language picker (PR #675). zh-CN, zh-TW, ja-JP, ko-KR, es-ES, pt-BR, fr-FR, de-DE, ru-RU, tr-TR, hi-IN.
npx skills addhint in connect output (PR #709). After a successfulagentmemory connect <agent>, the CLI now prints the matchingnpx skills add rohitg00/agentmemory -ycommand so users get the native-skills install alongside MCP wiring. TheskillsCLI covers 50+ agents including the 5 added in PR #677. README "Other agents" section gains a dedicated subsection explaining the two-step pattern (connectwrites MCP config,skills addinstalls the 8 SKILL.md files into the agent's native skill directory).
- Consolidation auto-enables when an LLM provider is configured (PR #696, closes #612).
CONSOLIDATION_ENABLEDdefaulted tofalse, so users with a working provider got compression + summarization but zero graph nodes / crystals / lessons. Now defaultstruewhenever any ofANTHROPIC_API_KEY/OPENAI_API_KEY/OPENROUTER_API_KEY/GEMINI_API_KEY/GOOGLE_API_KEY/MINIMAX_API_KEY/OPENAI_BASE_URLis set, orAGENTMEMORY_PROVIDER=agent-sdk. Explicit=false/AGENTMEMORY_PROVIDER=noopstill opt out.OPENAI_API_KEY_FOR_LLM=falsehonored (key scoped to embeddings). - Fire-and-forget telemetry hooks (PR #688, closes #573). Nine telemetry-only hooks (notification, post-tool-failure, post-tool-use, prompt-submit, stop, session-end, subagent-start, subagent-stop, task-completed) switched to unawaited
fetch(...).catch(() => {})paired withsetTimeout(() => process.exit(0), 500).unref()(1500ms for the multi-fetchstop+session-endhooks). No longer blocks Claude Code's next-prompt boundary on every assistant turn. - Observability defaults tamed (PR #686, closes #519).
iii-config.yamldefaults:sampling_ratio: 0.1,logs_console_output: false.findIiiConfig()precedence reversed soAGENTMEMORY_III_CONFIGenv > cwd >~/.agentmemory/iii-config.yaml> bundled.
- Graph extraction never fires automatically (PR #698, closes #666).
event::session::stoppedlistens onagentmemory.session.stoppedbut nothing in the codebase ever published that topic.api::session::endnow directly callssdk.triggerVoid("event::session::stopped", { sessionId })(try/catch guarded so a fan-out error doesn't fail the HTTP response). Knowledge graphs now materialize automatically when sessions end. agentmemory statusshows Memories/Observations = 0 (PR #698, closes #666). CLI fetched/agentmemory/exportfor counts but that endpoint times out (>5s) on iii-engine's file-based KV under concurrentkv.list(). Switched to/memories?count=true(count-only, constant-time) + sum ofsessions[].observationCount.- Hooks send full filesystem path as
projectinstead of repo basename (PR #687, closes #474). Native sessions, replay-import, andmemory_lesson_saveall use repo basename — the path/basename mismatch silently filtered out the bulk of relevant lessons from auto-injected context. NewresolveProject(cwd?)helper:AGENTMEMORY_PROJECT_NAMEenv >git rev-parse --show-toplevelbasename >basename(cwd). Applied to 9 hooks. - Cross-project memory leakage (PR #662). Memories created in one project leaking into recall on another. Wildcard guard pattern
(!project || !m.project || m.project === project)preserves backward-compat for legacy unscoped memories while scoping new ones strictly. - Graph parser tolerates reordered XML attributes (PR #685, closes #635). Order-dependent regex replaced with order-independent
parseAttrshelper. Self-closing trailing-/handling preserved. - Defensive null guards on
Memory.sessionIds(PR #684). Older exports + hand-edited dumps can omit this field; now treated as empty array on read. - Vector index Buffer slice metadata round-trip (PR #683, closes #587, #584).
byteOffset+byteLengthpreserved onBuffer.fromandFloat32Arrayconstruction so base64 round-trips don't corrupt vectors stored as slices. - Slots HTTP triggers return 503 not 500 (PR #682, closes #678). Feature-flag-disabled responses now use the documented 503 shape with
enableHow+docsHref..envpropagation fixed (now reads viagetEnvVar()not rawprocess.env). agentmemory doctorpoints to correct iii install URL (PR #681).- Separate
OPENAI_EMBEDDING_BASE_URL+OPENAI_EMBEDDING_API_KEY(PR #503). Lets users route embeddings and LLM calls to different OpenAI-compatible endpoints (e.g. cloud OpenAI for embeddings + local LM Studio for LLM, or vice versa). - Viewer Memories tab sorts newest first (PR #701, closes #674). Memories list rendered in KV-insertion order, hiding just-saved entries at the bottom of long lists.
loadMemories()now sorts oncreatedAtdesc (fallbackupdatedAt) before items reach state — matches thelocaleComparepattern Sessions / Metrics tabs already use.
- Local-LLM section in README (PR #697, closes #671). Dedicated "Local models (Ollama / LM Studio / vLLM)" subsection with copy-paste configs, model-pick table (qwen2.5-coder:7b, llama3.2:3b, mistral:7b-instruct, deepseek-r1:7b), and reasoning-model empty-content callout. Existing OpenAI-compatible support was buried in a one-line env comment.
- Three pipeline layers, not three primitives (PR #690). Website + README copy: the three primitives are worker / function / trigger (iii). HOOKS / RECALL / CONSOLIDATE are pipeline layers. Section anchor renamed
#primitives→#stackto match the nav label.
- Hook scripts now bundle per-entry instead of sharing chunks, so
plugin/scripts/_project-*.mjshashed artifacts no longer churn the diff on every build. AGENTS.md"Hook Scripts" section documents the two patterns (context-injecting vs telemetry-only) and the 500ms / 1500ms exit-delay rule for single vs multi-fetch hooks.- Test suite: 1271 → 1291 (+20 new tests covering project basename resolver, fire-and-forget wiring, consolidation default behavior, session-end → graph extraction, the graph-build endpoint, and the viewer memories sort).
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.com/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