38 Commits

Author SHA1 Message Date
Rohit Ghumare f72c7a54fc fix: plugin auto-wires MCP + sandbox-safe skills (#139) (#141)
* fix: Claude Code plugin auto-wires MCP + sandbox-safe skills (#139)

Two fixes reported in #139:

1. The Claude Code plugin (rohitg00/agentmemory) only shipped hooks
   and skills; it did not auto-register any MCP server. Users had to
   configure the @agentmemory/mcp stdio server separately, which the
   README didn't make clear. Add plugin/.mcp.json so
   /plugin install agentmemory@agentmemory wires up the MCP server
   automatically when the plugin is enabled.

2. The `recall` and `session-history` skills used inline bash
   pre-execution blocks (`!$(curl -s ... ${VAR:-default})`) with
   shell expansion, which Claude Code's sandbox rejects by pattern
   match with "Contains expansion" — no way to bypass except for
   Claude to reconstruct the curl call manually, as the reporter
   had to work around.

   Rewrite all four plugin skills (recall / remember / forget /
   session-history) as pure prompts that tell Claude to use the MCP
   tools directly: memory_smart_search, memory_save, memory_sessions,
   memory_governance_delete. No bash, no sandbox issues, no shell
   escaping. Skills also run faster — no curl subprocess fork on
   every invocation.

Also tighten the README Claude Code install snippet to note that
the plugin now registers hooks + skills AND auto-wires the MCP
server in one step.

Bumps to 0.8.9. 707 tests still pass (no behavioral changes to
server code; only plugin assets).

* review: implement the MCP tools the new skills call (#139)

CodeRabbit flagged that the rewritten plugin skills reference
memory_smart_search and memory_governance_delete, but the
standalone MCP shim (@agentmemory/mcp) only exposed 5 tools:
memory_save, memory_recall, memory_sessions, memory_export,
memory_audit. At runtime the skills would have thrown
"Unknown tool" the first time they ran.

Add the missing handlers to src/mcp/standalone.ts:

- memory_smart_search — aliases memory_recall, falling back to
  substring search over the in-memory KV store. The standalone
  shim has no engine behind it, so BM25/vector/graph aren't
  available, but the substring match is good enough for plugin
  usage on small personal memory stores.
- memory_governance_delete — deletes memories by id. Accepts
  memoryIds as an array or a comma-separated string, returns
  {deleted, requested, reason}. Throws on missing/empty input,
  silently skips unknown ids.

Also normalize memory_save concepts/files: they now accept both
arrays (what the new skills send) and CSV strings (what the old
skills and legacy clients send). New normalizeList() helper
centralizes the logic.

Fix memory_sessions to honour a limit arg (default 20) — it was
previously returning every session in the store.

Update the forget skill wording per CodeRabbit's nit: make it
explicit that memory_governance_delete only takes memoryIds, and
that deleting a whole session means collecting all memory IDs
from that session via search first.

Adds 8 regression tests to test/mcp-standalone.test.ts covering:
- memory_save with array concepts/files
- memory_save with CSV concepts/files (legacy path)
- memory_smart_search substring fallback
- memory_sessions limit
- memory_governance_delete array path
- memory_governance_delete CSV path
- memory_governance_delete missing/empty validation
- memory_governance_delete unknown-id skip

Full suite: 715 passing (was 707 + 8 new).

* review: reject empty search query + fix skill troubleshooting paths (#139)

CodeRabbit round 2:

1. src/mcp/standalone.ts memory_smart_search accepted '' as a
   query and used .includes('') which matches every memory. In
   the forget flow this would surface unrelated memory IDs for
   deletion. Now throws 'query is required' on missing/empty/
   whitespace-only input. Also broadens the search corpus from
   just title+content to include files, concepts, sessionIds,
   and id — so users can /forget by file path, concept name, or
   session ID, as the skill docs already promise.

2. All four skill files (recall, remember, forget, session-history)
   said 'check the agentmemory engine is running on localhost:3111'
   when tools are missing. Wrong troubleshooting path: the stdio
   MCP shim spawned by Claude Code via .mcp.json has no REST API,
   no port, no localhost. The correct checks are /plugin list,
   /mcp, and restarting Claude Code after install. Updated all
   four skills.

Adds 2 new regression tests to test/mcp-standalone.test.ts:
- memory_smart_search rejects empty/whitespace/missing query
- memory_smart_search finds memories by file, concept, or id

Full suite: 717 passing.

* review: tighten content/limit validation in standalone MCP (#139)

CodeRabbit round 3:

1. memory_save cast args.content as string and called .trim(),
   which throws a runtime TypeError if content is a number, object,
   null, etc. Replace the cast with a proper typeof guard that
   returns the clean 'content is required' error for any non-string
   input.

2. memory_smart_search trimmed rawQuery for emptiness but then
   lowercased the *untrimmed* value, so a query like '  bcrypt  '
   would fail substring matches with trailing whitespace. Trim
   first, then lowercase.

3. (args.limit as number) || 10 is fragile — it treats 0 and NaN
   the same, silently accepts negative/Infinity values, and has no
   upper bound so a malicious or buggy caller could request a
   million memories in one slice(). Add parseLimit() helper that:
   - rejects non-number/non-string types (booleans, objects, arrays)
   - rejects NaN, Infinity, and non-positive values
   - clamps to MAX_LIMIT=100 via Math.min
   - Math.floor()s to force integer
   - falls back to a per-call default (10 for search, 20 for
     sessions, 50 for audit)

   Applied to all three limit sites: memory_smart_search,
   memory_sessions, memory_audit.

Adds 2 regression tests:
- memory_save rejects 42 / {} / [] / null / undefined / true without
  crashing on .trim()
- parseLimit falls back on bogus values and clamps 99999 -> 100

Full suite: 719 passing (was 717 + 2 new).
2026-04-14 17:03:58 +01:00
Rohit Ghumare 281e10ca8c fix: stop burning Claude tokens on every PostToolUse hook (#138) (#140)
* fix: stop burning Claude tokens on every PostToolUse hook (#138)

mem::observe was firing mem::compress unconditionally on every
PostToolUse hook, which called Claude via the user's ANTHROPIC_API_KEY
to compress each raw observation into a structured summary. On an
active coding session (50-200 tool calls/hour) this silently burned
hundreds of thousands of Claude API tokens within minutes. Reported
by @olcor1 on a fresh Docker install — his token allocation was gone
in 20 minutes.

Make per-observation LLM compression opt-in.

- New env var AGENTMEMORY_AUTO_COMPRESS, default `false`. When false,
  observe.ts builds a zero-LLM synthetic CompressedObservation from
  raw tool I/O (title from toolName, narrative from truncated
  input/output, files extracted from file_path/pattern/etc., type
  inferred from camelCase-normalized tool name) and stores + indexes
  it. Recall and BM25 search still work.
- New src/functions/compress-synthetic.ts with buildSyntheticCompression().
- src/functions/observe.ts gates the compress trigger on the flag and
  writes the synthetic observation + stream events when disabled.
- Startup banner now logs "Auto-compress: OFF (default, #138)" or a
  loud warning when opt-in is on, so the mode is never silent.
- Regression test: test/auto-compress.test.ts covers the default path
  (no mem::compress fired), explicit opt-in, tool-name-to-type
  mapping, file-path extraction, narrative truncation, and the
  post_tool_failure→error mapping.

Bumps to 0.8.8 (main package + shim). 707 tests pass.

**Migration**: users who were relying on LLM-generated summaries set
AGENTMEMORY_AUTO_COMPRESS=true in ~/.agentmemory/.env and restart.
Existing compressed observations on disk are untouched.

* review: address CodeRabbit findings on #140

- compress-synthetic.ts:92 — use the fallback toolName for inferType
  so both title and type derive from the same resolved value
- test/auto-compress.test.ts — vi.resetModules() in beforeEach to
  prevent cached observe.js from seeing stale env var state between
  the default, opt-in, and explicit-off test cases
2026-04-14 15:42:17 +01:00
Rohit Ghumare b864a7d268 fix: ship iii-config.docker.yaml in the npm tarball (#136) (#137)
docker-compose.yml mounts `./iii-config.docker.yaml:/app/config.yaml:ro`
but the `files` array in package.json only shipped `iii-config.yaml`.
Docker resolves missing bind sources by silently creating them as empty
directories, so `npx @agentmemory/agentmemory` mounted an empty dir at
/app/config.yaml and iii-engine crashed with:

  Error: Failed to read config file '/app/config.yaml':
  Is a directory (os error 21)

Fix: add iii-config.docker.yaml to package.json `files`.

Also adds a regression test in test/consistency.test.ts that parses
every `./<path>:<container>` bind mount in docker-compose.yml and
asserts the source file is shipped via the `files` array, so this
class of bug can't reach a release again.

Bumps main package + shim to 0.8.7 and adds CHANGELOG [0.8.7].
2026-04-14 09:58:19 +01:00
Rohit Ghumare 416fa15af4 chore: release 0.8.6 — scope the MCP shim as @agentmemory/mcp (#134)
0.8.5's publish workflow got blocked on the unscoped `agentmemory-mcp`
name by npm's name-similarity policy (there's an unrelated third-party
package called `agent-memory-mcp`). Publishing the shim under the
`@agentmemory` scope we already own sidesteps the conflict.

Changes:
- Rename packages/agentmemory-mcp → packages/mcp
- Package name: agentmemory-mcp → @agentmemory/mcp (0.8.4 → 0.8.6)
- Keep bin name `agentmemory-mcp` so `npm i -g @agentmemory/mcp`
  still installs a binary at `agentmemory-mcp` for muscle memory
- Log prefix [agentmemory-mcp] → [@agentmemory/mcp] in standalone.ts
  and in-memory-kv.ts
- README / integrations/openclaw / integrations/hermes / src/cli.ts
  all point at `npx -y @agentmemory/mcp`
- .github/workflows/publish.yml working-directory and npm view queries
  target packages/mcp and @agentmemory/mcp
- Shim dependency on @agentmemory/agentmemory bumped to ~0.8.6
- Main package 0.8.5 → 0.8.6 across the 8 version files
- CHANGELOG [0.8.6] entry documenting the scope move
2026-04-14 00:31:10 +01:00
Rohit Ghumare 3935aecdae chore: bump version to 0.8.5 + add CHANGELOG (#133) 2026-04-13 20:03:04 +01:00
Rohit Ghumare 461ef827fa mcp: validate request id type per JSON-RPC 2.0 §4
CodeRabbit flagged that processLine only checked `id != null` in the
invalid-shape path, which meant (a) malformed messages with non-primitive
ids could be echoed back with that id, and (b) valid-shape requests with
id: {} / [] / true would fall through to the handler and be responded to
with the bogus id as the response id — both spec violations.

Add isValidId() (string | number | null | undefined), extract rawId once
as unknown, and:
- In the invalid-shape path, only echo if rawId is string or number.
- After shape validation, reject bad-id requests with -32600 / id: null
  before invoking the handler.

Adds 5 test cases covering id: object, array, boolean, plus the malformed
+ non-primitive-id drop path and a positive string-id case.
2026-04-13 19:24:37 +01:00
Rohit Ghumare 745ad87095 fix(mcp): never respond to JSON-RPC notifications (#129)
Codex CLI v0.120.0 fails to start the standalone MCP server with
"MCP startup failed: Transport closed". Other MCP clients (Claude
Desktop, Cursor, OpenClaw) work fine with the same binary. Reported
in #129 by @GuillaumeOuint.

Root cause: src/mcp/transport.ts unconditionally writes a JSON-RPC
response for every incoming message, including notifications. Per
JSON-RPC 2.0 §4.1 a notification is "a Request object without an id
member" and "the Server MUST NOT reply to a Notification". Strict
clients close the transport when they receive an unsolicited
response — exactly the symptom Guillaume reported.

The trigger sequence on Codex CLI:

  1. Codex sends initialize (request, has id) → server responds ✓
  2. Codex sends notifications/initialized (notification, no id)
  3. Our handler in standalone.ts returns {}
  4. Transport writes {"jsonrpc":"2.0","result":{}} to stdout
     (no id field because request.id was undefined)
  5. Codex parses an unsolicited response → closes transport
  6. Guillaume sees "Transport closed"

This worked accidentally for lenient clients (Claude Desktop,
Cursor, etc.) which silently ignored the spurious responses.

Fix:

- transport.ts: detect notifications via missing/null id field,
  run the handler for side effects, then drop the response. Errors
  inside notification handlers are logged to stderr (not silently
  swallowed) so production debugging still works
- transport.ts: malformed messages that have no id are also dropped
  silently (consistent with notification semantics) instead of being
  responded to with id: null
- transport.ts: extracted processLine() so the line-handling logic
  is testable independently of process.stdin/stdout
- new test/mcp-transport.test.ts with 9 tests covering: request
  responses (success + error), notification suppression (no id +
  null id + handler-throws), malformed input (parse error, invalid
  request shape with id, invalid request shape without id, empty
  lines)

Tests: 693/693 (684 baseline + 9 new). Build clean.
2026-04-13 18:13:53 +01:00
Rohit Ghumare 95e089a37c chore: release 0.8.4
Two community contributions on top of 0.8.3 land as a patch release so
they reach users immediately and so `npx agentmemory-mcp` ships to the
npm registry for the first time (closing out #120 on the live release).

- #122 (Jason Landbridge): memory_save persists to disk immediately
  after every call, not just on SIGINT/SIGTERM, so memories survive
  SIGKILL from agent sessions ending forcefully
- #121 (Jason Landbridge): OpenCode MCP config format corrected —
  opencode.json with mcp/type:local/command array instead of the
  wrong .opencode/config.json with mcpServers

Version bumped across package.json, src/version.ts, types.ts,
export-import supportedVersions, plugin.json, shim package.json and
its dependency on the main package (~0.8.4). package-lock.json
regenerated. 684 tests passing, clean build.
2026-04-13 12:35:35 +01:00
Jason Landbridge 2a5cb123dc fix: persist memories to disk immediately after memory_save (#122)
* fix: persist memories to disk immediately after memory_save

Previously, kv.persist() was only called on SIGINT/SIGTERM. If the
process was killed with SIGKILL, crashed, or the host terminated it
forcefully (e.g. OpenCode session end), all saved memories were lost.

Fix: call kv.persist() immediately after kv.set() in the memory_save
handler so data is written to standalone.json on every save.

Also export handleToolCall with an injectable kv parameter to allow
unit testing, and add tests verifying that persist is called on save.

* refactor: use generateId() and single isoNow in memory_save handler

Replace ad-hoc ID/timestamp logic with project-standard helpers:
- generateId("mem") instead of manual Date.now()/Math.random() concatenation
- Single const isoNow = new Date().toISOString() shared by createdAt and updatedAt

fingerprintId is intentionally not used: memory_save always creates a new
unique entry (no dedup), so a content-addressable key would silently overwrite
duplicate content rather than append — matching existing project behaviour.
2026-04-13 12:08:01 +01:00
Rohit Ghumare 8a36fe7867 fix: retention scoring (#119) + npx agentmemory-mcp 404 (#120), release 0.8.3 (#123)
* fix: retention scoring (#119) + npx agentmemory-mcp 404 (#120), release 0.8.3

Issue #119 — retention score ignored agent-side reads

`mem::retention-score` previously hardcoded `accessCount=0` and
`accessTimestamps=[]` for episodic memories and used only a single-sample
`lastAccessedAt` for semantic memories, so the time-frequency decay
formula was a dead path. All read endpoints now record access events to
a new `mem:access` KV namespace via a keyed-mutex'd access tracker:

  - mem::search, mem::smart-search (compact + expand), mem::context,
    mem::timeline, mem::file-context, mem::get-related, mem::working-context
  - retention.ts pre-fetches the full access log in one kv.list call,
    normalizes every row defensively, and builds an O(1) lookup Map
  - recordAccessBatch uses Promise.allSettled so a slow keyed-lock on one
    id does not block the rest of the batch
  - Bounded ring buffer of the last 20 access timestamps per memory
  - Backwards-compat fallback: pre-0.8.3 semantic memories with only the
    legacy sem.lastAccessedAt still score correctly
  - Corrupt lastAccessedAt values are NaN-safe via Date.parse + isFinite
  - reinforcementBoost is reported as the raw formula output, not the
    clamped residual

Memory deletion sites (retention-evict, evict, auto-forget,
governance-delete, governance-bulk, forget, import replace) now call
deleteAccessLog to prevent mem:access from accumulating zombie entries.
mem::export / mem::import and mem::snapshot-create / mem::snapshot-restore
round-trip the new namespace so backup/restore cycles no longer zero out
reinforcement signals.

Issue #120 — npx agentmemory-mcp returned npm registry 404

The README instructed users to run `npx agentmemory-mcp`, but
`agentmemory-mcp` only existed as a `bin` entry inside
`@agentmemory/agentmemory`, not a real registry package. Two-part fix:

  - New sibling package `packages/agentmemory-mcp/` — a thin shim that
    depends on `@agentmemory/agentmemory` (~0.8.3, tilde to block 0.9.x
    supply-chain drift) and forwards to dist/standalone.mjs via the new
    `exports` field on the main package
  - Canonical `npx @agentmemory/agentmemory mcp` subcommand on the CLI
    for users who already have the main package installed
  - Removed the dead `agentmemory-mcp` bin from the main package so the
    shim owns the name unambiguously
  - publish.yml publishes both packages in order with idempotent
    guards and npm-view registry polling (no more fixed sleep)
  - All MCP install snippets in README + integrations/openclaw + hermes
    + shim README use `npx -y agentmemory-mcp` to skip install prompts

Release 0.8.3

  - 670 tests passing (665 + 11 new: access tracker, retention,
    smart-search integration, corrupt-input, kv.list failure path,
    Promise.allSettled resilience)
  - Version bumped across package.json, src/version.ts, types.ts,
    export-import supportedVersions, plugin.json
  - package-lock.json regenerated

* fix: address CodeRabbit review feedback on #123

Real issues caught and fixed:

- access-tracker: deleteAccessLog now takes the same mem:access:<id>
  keyed mutex used by recordAccess, eliminating the race where a
  concurrent delete could drop an in-flight RMW update and leave a
  stale access log for an evicted memory
- access-tracker: normalizeAccessLog now coerces count to a
  non-negative integer, drops non-finite recent[] entries, truncates
  recent[] to the last 20 on read (enforcing the ring-buffer invariant),
  and guarantees count >= recent.length so a malformed row can't produce
  NaN downstream. count is NOT capped at 20 — it is the lifetime access
  counter, while recent[] is the 20-entry window
- export-import: import path now rejects accessLogs arrays above
  MAX_ACCESS_LOGS (50_000), normalizes each entry via
  normalizeAccessLog, and drops entries whose memoryId is not in the
  imported memories set, so a crafted export can't blow up memory or
  resurrect zombie access rows for memories that don't exist
- publish.yml: added a post-publish npm view polling loop for
  agentmemory-mcp mirroring the one that already guards the main
  package, so the workflow only succeeds when `npx agentmemory-mcp` is
  actually visible on the registry
- CHANGELOG.md: added the missing [0.8.3] reference-style link target
  at the bottom to match the [0.8.2]/[0.8.1]/[0.8.0] pattern
- README.md: standalone MCP inline examples now use `npx -y` to match
  the MCP config snippets and skip the install confirmation prompt

Tests: 680/680 (+10 new — deleteAccessLog behavior, normalizeAccessLog
invariants, malformed mem:access row handling in retention scoring).

Findings deliberately not applied:

- auto-forget.ts / remember.ts / evict.ts recordAudit calls: existing
  pattern in the codebase only audits governance deletes (user-initiated
  admin actions), not automatic eviction. Adding audit everywhere is a
  policy change, out of scope for this PR
- evict.ts gating deleteAccessLog on memory delete success: current
  order is defensible, deleteAccessLog is already best-effort with its
  own try/catch, and calling it after a failed memory delete is harmless
- snapshot.ts fail-fast on kv.list failure: inconsistent with the
  existing .catch(() => []) pattern used for observations in the same
  function
- retention.ts semantic evict only deletes KV.memories rows: real bug
  but pre-existing on main (RetentionScore has no source/type field).
  Tracked separately — out of scope for this PR
- bin.mjs fallback command: already present in the existing catch
  handler
- Promise.all parallelization of delete+deleteAccessLog: micro
  optimization not worth the readability cost
2026-04-13 12:05:18 +01:00
Rohit Ghumare fa2aa980fb chore: bump version to 0.8.2 + add CHANGELOG (#117)
## Version bumped across
- package.json + package-lock.json
- plugin/.claude-plugin/plugin.json
- src/version.ts (union type)
- src/types.ts ExportData.version union
- src/functions/export-import.ts supportedVersions set
- test/export-import.test.ts assertion

Also fixed the ExportData version union syntax: prior releases used
commas (`| "0.7.9", "0.8.0", "0.8.1"`) instead of pipes, which would
not work as intended. Fixed to a proper pipe-separated union.

## CHANGELOG.md

New file documenting v0.8.2 in Keep-a-Changelog format. Sections:

**Security (6 fixes)** — addresses CVEs in default deployments:
- [CRITICAL] Stored XSS in viewer
- [CRITICAL] curl|sh in CLI startup
- [HIGH] Default 0.0.0.0 binding
- [HIGH] Unauthenticated mesh sync
- [MEDIUM] Path traversal in Obsidian export
- [MEDIUM] Incomplete secret redaction

**Added**:
- agentmemory demo CLI command
- benchmark/COMPARISON.md
- integrations/openclaw/ gateway plugin
- Token savings dashboard in CLI + viewer
- Paste-this-prompt blocks
- 60 custom SVG tags (30 dark + 30 light variants)
- Real agent logos in Supported Agents grid

**Changed**:
- README redesigned with SVG tags, brand palette
- Supported Agents grid reordered
- Default ports bound to 127.0.0.1
- Hero stat row uses custom SVG cards

**Fixed**:
- Viewer cost calculation 100x underreporting
- ObservationType union missing "image"
- Dynamic imports inside eviction loops
- OpenClaw /context payload contract
- Cursor cell missing label
- Codex logo 404

**Infrastructure**:
- 654 tests (up from 646), 8 new security tests
- All 60 SVGs validated
- README consistency check updated
2026-04-12 20:38:08 +01:00
eng1 cbaaf4fb44 security: harden defaults, viewer CSP, mesh auth, export confinement (#108)
Fixes 6 security issues in agentmemory's default deployment, viewer, mesh sync, export path, and startup flow.

## Findings Addressed

1. **Default REST/stream exposure on 0.0.0.0** — bind default REST and stream services to 127.0.0.1; restrict Docker port publishing to localhost; add dedicated iii-config.docker.yaml for Docker usage.

2. **Stored XSS via inline viewer handlers** — remove inline event handlers from the viewer; replace with delegated data-action event handling; switch to nonce-based CSP for viewer HTML; add script-src-attr 'none'.

3. **Arbitrary path writes in Obsidian export** — confine exports to AGENTMEMORY_EXPORT_ROOT (default ~/.agentmemory); reject vaultDir values outside the allowed root.

4. **Mesh sync without peer auth** — require AGENTMEMORY_SECRET for mesh endpoints and sync operations; send Authorization: Bearer <secret> on mesh push/pull requests.

5. **Secret redaction misses modern token formats** — add coverage for Bearer tokens, sk-proj-*, broader sk/pk/rk/ak variants, GitHub ghs_/ghu_ tokens.

6. **CLI executes remote shell script directly** — remove curl|sh installation pattern; use existing local iii-engine binary if available, otherwise fall back to Docker.

## Validation

- 654 tests passing (8 new security tests)
- npm run build succeeds
- Merged with main and resolved README conflicts to preserve the new benchmark/competitor table layout

Thanks @eng-pf for catching these and submitting the fixes.
2026-04-12 09:55:13 +01:00
Rohit Ghumare 7af05ecf78 chore: bump version to 0.8.1 2026-04-09 19:10:52 +01:00
Rohit Ghumare 798700f2a3 chore: bump version to 0.8.0 2026-04-09 09:07:57 +01:00
Rohit Ghumare 29cbaa7624 chore: bump version to 0.7.9 2026-04-08 10:52:30 +01:00
Rohit Ghumare 805620aca1 chore: bump version to 0.7.8 2026-04-08 10:28:11 +01:00
Rohit Ghumare 8704131745 chore: bump version to 0.7.7 2026-04-07 19:56:12 +01:00
Rohit Ghumare b81682da8b chore: bump version to 0.7.6 2026-04-07 19:43:17 +01:00
Rohit Ghumare 69bb787629 feat: cross-encoder reranking, working memory, skill extraction (#93)
* feat: cross-encoder reranking, working memory, skill extraction (#90, #58, #57)

- reranker.ts: opt-in cross-encoder rerank after hybrid search via
  RERANK_ENABLED=true, uses @xenova/transformers MiniLM-L-6-v2,
  graceful fallback when unavailable
- working-memory.ts: core memory (pinned facts always in context) +
  auto-paging of archival memories by importance/recency/access score,
  5 new functions (core-add, core-remove, core-list, working-context,
  auto-page)
- skill-extract.ts: auto-generate reusable procedural skills from
  completed sessions via LLM, with reinforcement on re-extraction,
  skill-match for querying relevant skills (3 new functions)
- ProceduralMemory type extended with expectedOutcome, tags, concepts,
  sourceObservationIds
- 19 new tests, 646 total passing

Closes #90, closes #58, closes #57

* fix: add 0.8.0 to supported import versions, bump plugin.json

* fix: address CodeRabbit review — audit, fingerprint, guards, archive

- skill-extract: reject non-completed sessions, fingerprint full
  procedure (title+trigger+steps) not just title, audit reinforcement
- working-memory: add recordAudit for core-add/core-remove/auto-page,
  auto-page now archives to KV.memories instead of deleting
- reranker: cache pipelineUnavailable to avoid repeated import retries
- hybrid-search: rerank over larger pool (max(limit,20)) then slice
- types: add skill_extract/core_add/core_remove/auto_page to AuditEntry

* fix: address remaining CodeRabbit review findings

- Parse RERANK_ENABLED with === "true" instead of truthy coercion
- Remove unused project param from mem::skill-list
- Remove unused sessionId/project/query params from mem::working-context
- Use generateId("mem") for archived core entries to avoid ID collision

* fix: address CodeRabbit round-2 findings

- Make skill reinforcement idempotent (skip if sessionId already present)
- Parallelize summary + observations fetch in skill-extract
- Use continue instead of break for oversized unpinned core entries
- Buffer access-counter writes with Promise.allSettled (non-blocking)
- Decouple rerank window (fixed 20) from retrieval depth
2026-04-07 19:42:07 +01:00
Rohit Ghumare ea2eddce83 chore: bump version to 0.7.5 2026-04-07 16:27:50 +01:00
Rohit Ghumare 1fa0dcefab chore: bump version to 0.7.4 2026-04-06 16:18:04 +01:00
Rohit Ghumare 9c27eff610 feat: implement reflect — auto-synthesize insights from memory clusters (#89)
Adds mem::reflect: traverses knowledge graph, groups related memories
by concept clusters, synthesizes higher-order insights via LLM.

New files:
- src/prompts/reflect.ts — LLM prompt for insight synthesis
- src/functions/reflect.ts — 4 functions: reflect, insight-list,
  insight-search, insight-decay-sweep
- test/reflect.test.ts — 13 tests

New type: Insight (confidence-scored, fingerprint-deduped, decayable)
New KV scope: mem:insights
New MCP tools: memory_reflect, memory_insight_list (in ESSENTIAL set)
New REST: POST /reflect, GET /insights, POST /insights/search
Hooks into consolidation pipeline as "reflect" tier after semantic

Review fixes applied:
- Fixed project filter no-op (was discarding filter result)
- Fixed BFS depth tracking (standard level-count pattern)
- Added attribute-order constraint to LLM prompt
- Whitelisted fields in api::insight-search (no raw body passthrough)
- Fixed Jaccard fallback to compare document-id sets not concept strings

43 MCP tools, 103 REST endpoints, 627 tests passing
2026-04-06 16:08:34 +01:00
Rohit Ghumare 034869b42c chore: bump version to 0.7.3 2026-04-06 15:38:10 +01:00
Rohit Ghumare 5510e94e39 fix: simplify review — temporal-graph name, test precision, stale counts
- Fix README: temporal-graph → temporal-graph-extract + temporal-query
- Fix test precision: toBeCloseTo(0.55, 1) → precision 2 (±0.005)
- Fix stale test counts: 581 → 614 across README and AGENTS.md
- Add obsidian export error-path test (errors undefined on success)

614 tests passing
2026-04-06 13:17:48 +01:00
Rohit Ghumare 45eb99d656 fix: CrystallizableAction type, npm package size, add lesson + obsidian tests
Fixes #84: Change CrystallizableAction to Action in crystallize.ts:157
Fixes #85: Add "files" field to package.json (40MB → 11.6MB)
Fixes #86: Add 22 tests for all 5 lesson functions
Fixes #87: Add 10 tests for obsidian-export

613 tests passing (was 581)
2026-04-06 12:20:20 +01:00
Rohit Ghumare 031eff7322 chore: bump version to 0.7.2 across all files 2026-04-05 11:32:15 +01:00
Rohit Ghumare e8f410b537 feat: v0.7.0 — lessons, tool visibility, auto-consolidation, obsidian export, npx bootstrap (#82)
* feat: v0.7.0 — lessons, tool visibility, auto-consolidation, obsidian export, npx bootstrap

Five DX improvements based on competitive research against Mem0, Engram, CodeMem:

1. `npx agentmemory` zero-config startup
   - New CLI bootstrap (src/cli.ts) auto-detects and starts iii-engine
   - Tries `iii` binary first, falls back to `docker compose up -d`
   - Bundles iii-config.yaml and docker-compose.yml in dist/

2. Simplified MCP tool surface (7 core tools by default)
   - AGENTMEMORY_TOOLS=all unlocks all 49 tools
   - Default: save, recall, consolidate, forget, sessions, diagnose, lesson_save
   - Call handler remains unfiltered — any tool callable by name

3. Auto-consolidation on session end
   - CONSOLIDATION_ENABLED defaults to true (was false)
   - Session-end hook: session/end → crystallize → consolidate → bridge sync
   - Consolidation pipeline always registered (timer gated by config)

4. First-class lesson memory type with confidence decay
   - Lesson interface: confidence (0-1), reinforcements, decayRate, source
   - 5 functions: lesson-save, lesson-recall, lesson-list, lesson-strengthen, lesson-decay-sweep
   - Dedup via SHA-256 fingerprint — duplicate saves strengthen existing
   - Crystal lessons auto-flow into lesson system at confidence 0.6
   - Daily decay sweep with parallel KV writes

5. Obsidian-compatible Markdown export
   - Export to ~/.agentmemory/vault/ with YAML frontmatter + wikilinks
   - MOC.md (Map of Content) index file
   - Parallel KV reads, auto-export via OBSIDIAN_AUTO_EXPORT=true

Stats: 49 MCP tools, 99 REST endpoints, 573 tests passing

* docs: add AGENTS.md, fix tool/endpoint counts across README, plugin, cli

- Create AGENTS.md with strict consistency rules for MCP tools, REST
  endpoints, versions, KV scopes, and audit operations
- Fix MCP tool count: 38 → 41 across README.md (4 occurrences)
- Fix REST endpoint count: 93/95 → 99 across README.md and index.ts
- Fix plugin.json: version 0.6.1 → 0.7.0, tool count 5 → 41
- Fix cli.ts help text: 48+ → 41 MCP tools
- Fix README api.ts path reference → triggers/api.ts

* fix: address code review findings — consolidation guard, decay bug, async fs, export-import lessons

Inline fixes:
- Revert CONSOLIDATION_ENABLED to opt-in (=== "true"), matching original behavior
- Add early-exit guard in consolidation-pipeline handler when disabled
- Gate session-end crystallize+consolidation calls on CONSOLIDATION_ENABLED
- Fix lesson decay over-decay bug: add lastDecayedAt to Lesson, compute
  incremental delta instead of reapplying full age every sweep run
- Add LESSON_DECAY_ENABLED flag (default true) to gate the sweep timer

Outside diff fixes:
- Add lessons to export-import (export + import + replace cleanup)
- Log warning instead of swallowing obsidian auto-export errors

Nitpick fixes:
- Switch obsidian-export to async fs/promises (mkdir, writeFile)
- Add per-item try/catch in obsidian-export, return errors array
- Replace governance_delete with smart_search in ESSENTIAL_TOOLS (non-destructive default)
- Fix CLI whichBinary for Windows (uses "where" on win32)
- Use dynamic port in CLI error message instead of hardcoded 3111
- Return 201 for newly created lessons, 200 for strengthened
- Wrap lesson audit calls in try/catch so audit failure doesn't surface
- Fix build script to not swallow tsdown failure
- Remove exact tool count from test, use >=41 + uniqueness + required names
- Add test/consistency.test.ts: validates version, tool count, README consistency
- Add isConsolidationEnabled mock to consolidation-pipeline test

579 tests passing (573 original + 6 new consistency checks)

* fix: guard remaining audit calls, correct endpoint count, add CI + npm publish

Review fixes:
- Wrap lesson_recall and lesson_strengthen audit calls in try/catch
- Fix REST endpoint count: 99 → 100 (verified via grep) across index.ts,
  README.md, and AGENTS.md
- Use regex in consistency test for README assertions (flexible phrasing)
- Add consolidation gate tests: disabled returns early, force=true bypasses

CI/CD:
- Add .github/workflows/ci.yml — test on Node 18/20/22
- Add .github/workflows/publish.yml — auto-publish to npm on GitHub release
  (uses NPM_TOKEN secret + provenance)

Nitpick:
- Single-char term filter (t.length > 1) kept intentionally — prevents noise
  from single-letter matches; documented in AGENTS.md if needed

581 tests passing

* fix(ci): add --legacy-peer-deps for zod v3/v4 peer conflict

@anthropic-ai/claude-agent-sdk@0.2.56 requires zod@^4.0.0 as a peer
dependency but the project uses zod@^3.23.0. The lock file resolves
this locally but npm ci is strict about peer deps in CI.

* fix(ci): drop Node 18 from matrix — tsdown requires Node 20+

tsdown/rolldown uses node:util.styleText which is only available in
Node 20.12+. Updated engines field to >=20.0.0 to match.

* fix(ci): add inlineOnly: false to tsdown config, target node20

tsdown errors on CI with "Consider adding inlineOnly option" when
dependencies are bundled. Setting inlineOnly: false suppresses this.
Also updated target from node18 to node20 to match engines field.
2026-04-04 17:57:01 +01:00
Rohit Ghumare 005b8c8087 feat: v0.6.1 — citations, cascading updates, expanded mesh (#79)
* feat: v0.6.1 — citations, cascading updates, expanded mesh (#53 #56 #59)

Add JIT verification with citation chains, self-organizing memory via
cascading staleness propagation, and expand mesh sync to 7 scopes
(semantic, procedural, relations, graph nodes/edges).

- mem::verify traces memory/observation provenance back to source
- mem::cascade-update flags stale graph items and sibling memories
- Mesh default scopes expanded from 2 to 7 with project-based filtering
- Memory.sourceObservationIds, CompressedObservation.confidence fields
- GraphNode.stale, GraphEdge.stale for staleness tracking
- MeshPeer.syncFilter for project-scoped action sync
- 573 tests passing across 49 files

* fix: address code review — stale filtering, LWW clock, validation, scoping

- Filter stale nodes/edges in graph-retrieval.ts and graph.ts traversals
- Use updatedAt (not createdAt) as LWW clock for graph node mesh sync
- Set updatedAt in cascade.ts when flagging nodes as stale
- Skip non-project scopes (semantic, procedural, relations, graph) when
  syncFilter.project is set to prevent leaking unscoped data
- Validate sourceObservationIds as array of strings in remember.ts
- Deduplicate observation IDs in consolidate.ts sourceObservationIds
- mesh-export endpoint uses updatedAt for graph nodes, accepts project param
- Extract shared test helpers into test/helpers/mocks.ts
- Assert memory_verify tool name in mcp-standalone.test.ts
2026-03-25 21:12:12 +00:00
Rohit Ghumare 857f71e3c6 feat: v0.6.0 advanced retrieval with real-world benchmarks (#76)
* feat: add 9 orchestration modules for v0.5.0

Add actions, frontier, leases, routines, signals, checkpoints,
flow-compress, mesh, and branch-aware modules with full MCP tools,
REST endpoints, and 170 new tests. Includes SSRF protection,
race-condition-safe keyed mutex locking, SHA-256 fingerprinting,
and fixes for 29 CodeRabbit review findings.

- 9 new source files (src/functions/*)
- 8 new test files (170 tests, total 386)
- 10 new MCP tools, 23 new REST endpoints
- 8 new KV scopes, new types for orchestration
- Version bump to 0.5.0, README and viewer updated

* feat: add sentinels, sketches, crystallize, diagnostics, facets modules

5 new modules inspired by beads patterns but with original naming and
iii-engine real-time streaming (no polling):

- sentinels: event-driven condition watchers (webhook, timer, threshold,
  pattern, approval) that auto-unblock gated actions via SSE
- sketches: ephemeral action graphs with auto-expiry, promote or discard
- crystallize: LLM-powered compaction of completed action chains into
  compact crystal digests with key outcomes and lessons
- diagnostics: self-diagnosis across 8 categories (actions, leases,
  sentinels, sketches, signals, sessions, memories, mesh) with auto-heal
- facets: multi-dimensional tagging (dimension:value) with AND/OR queries

- 5 new source files, 5 new test files (132 tests, total 518)
- 9 new MCP tools (total 37), 21 new REST endpoints (total 93)
- 4 new KV scopes (total 33), new types for all modules
- README stats and function table updated

* fix: address code review findings across v0.5.0 modules

- actions: validate edges before persisting, set blocked status for requires deps
- leases: use mem:action lock key, reject blocked actions, check expiry on release
- checkpoints: validate linkedActionIds exist, check requires edges in unblock
- mesh: add SSRF validation on peer registration
- routines: remove invalid "failed" action status check
- export-import: add v0.5.0 scope export/import (actions, sentinels, sketches, etc)
- mcp/server: validate CSV inputs are strings before splitting
- schema: replace runtime require with static import
- README: fix stale tool/endpoint counts (28→37, 72→93)

* fix: second round code review — mesh locks, routines DAG, MCP input validation, README counts

- mesh.ts: add withKeyedLock on action writes in receive path, add IPv6 private ranges to SSRF check
- routines.ts: validate DAG (duplicate orders, unknown deps), set dep actions to blocked, refresh stepStatus in routine-status
- checkpoints.ts: runtime type enum validation, set linked pending actions to blocked
- leases.ts: validate ttlMs is finite positive number
- export-import.ts: add skip strategy checks for all v0.5.0 import blocks
- mcp/server.ts: typeof guards on tags, config JSON.parse, actionIds, linkedActionIds, categories
- README.md: Tools 18→37, Functions 33→50, stats line updated
- test: update checkpoint test for new blocked-on-create behavior

* fix: third round review — lease renew/release safety, mesh locking, export replace cleanup, MCP input guards

- leases.ts: renew extends from max(now, existing expiry) instead of now; release verifies action ownership before mutation
- mesh.ts: withKeyedLock on memory writes in mesh-receive; applySyncData validates id/updatedAt and locks both memory and action writes
- routines.ts: stepStatus maps "blocked" to "pending" explicitly; progress includes blocked/cancelled counts; routine-freeze wrapped in withKeyedLock
- export-import.ts: remove unused RoutineRun import; replace strategy clears all orchestration namespaces; skip strategy for graphNodes/graphEdges/semantic/procedural
- mcp/server.ts: sentinel_trigger JSON.parse with typeof+try/catch; facet_query typeof guards on matchAll/matchAny; remove redundant requires cast; .filter(Boolean) on concepts/files/tags/requires CSV splits
- README.md: clarify API table is a representative subset

* fix: fourth round review — redirect SSRF, blocked-on-create, missing action handling, boolean normalization

- mesh.ts: add redirect:"error" to both outbound fetch calls to prevent SSRF via redirect
- routines.ts: create actions with status "blocked" directly when hasDeps (eliminates two-pass race); handle missing actions in routine-status as cancelled; progress.total uses run.actionIds.length
- mcp/server.ts: sentinel config accepts object values directly; normalize unreadOnly/dryRun for both JSON booleans and string values
- README.md: consistent bundle size (365KB) across both occurrences

* feat: v0.6.0 advanced retrieval — triple-stream search, stemming, real benchmarks

Search improvements:
- Porter stemmer for word normalization (authentication ↔ authenticating)
- 40+ coding-domain synonym groups (db ↔ database, k8s ↔ kubernetes)
- Binary-search prefix matching replaces O(n) full scan
- Session diversification (max 3 results per session)
- Co-occurrence graph edges between all concept pairs

New retrieval modules:
- Sliding window inference pipeline (context enrichment at ingestion)
- Adaptive query expansion (LLM-generated reformulations)
- Triple-stream search (BM25 + Vector + Graph with RRF fusion)
- Append-only temporal knowledge graph (versioned edges, point-in-time queries)
- Graph-augmented retrieval (entity search + neighborhood expansion)
- Ebbinghaus retention scoring (decay + tiered hot/warm/cold/evictable)

Real-world benchmarks (240 observations, 20 labeled queries):
- Quality eval: 64.1% recall@10 with Xenova embeddings (vs 55.8% grep)
- Scale eval: 92-100% token savings vs built-in memory at 240-50K observations
- Cross-session: 12/12 queries found vs 10/12 for 200-line MEMORY.md cap
- Token measurement uses actual search results (fixed fake constant bug)
- Removed old microbenchmarks (bench.ts, run-bench.ts, COMPARISON.md)
2026-03-18 08:47:35 +00:00
Rohit Ghumare 1ca0ec0414 feat: v0.5.0 orchestration layer — 14 modules, 518 tests (#74)
* feat: add 9 orchestration modules for v0.5.0

Add actions, frontier, leases, routines, signals, checkpoints,
flow-compress, mesh, and branch-aware modules with full MCP tools,
REST endpoints, and 170 new tests. Includes SSRF protection,
race-condition-safe keyed mutex locking, SHA-256 fingerprinting,
and fixes for 29 CodeRabbit review findings.

- 9 new source files (src/functions/*)
- 8 new test files (170 tests, total 386)
- 10 new MCP tools, 23 new REST endpoints
- 8 new KV scopes, new types for orchestration
- Version bump to 0.5.0, README and viewer updated

* feat: add sentinels, sketches, crystallize, diagnostics, facets modules

5 new modules inspired by beads patterns but with original naming and
iii-engine real-time streaming (no polling):

- sentinels: event-driven condition watchers (webhook, timer, threshold,
  pattern, approval) that auto-unblock gated actions via SSE
- sketches: ephemeral action graphs with auto-expiry, promote or discard
- crystallize: LLM-powered compaction of completed action chains into
  compact crystal digests with key outcomes and lessons
- diagnostics: self-diagnosis across 8 categories (actions, leases,
  sentinels, sketches, signals, sessions, memories, mesh) with auto-heal
- facets: multi-dimensional tagging (dimension:value) with AND/OR queries

- 5 new source files, 5 new test files (132 tests, total 518)
- 9 new MCP tools (total 37), 21 new REST endpoints (total 93)
- 4 new KV scopes (total 33), new types for all modules
- README stats and function table updated

* fix: address code review findings across v0.5.0 modules

- actions: validate edges before persisting, set blocked status for requires deps
- leases: use mem:action lock key, reject blocked actions, check expiry on release
- checkpoints: validate linkedActionIds exist, check requires edges in unblock
- mesh: add SSRF validation on peer registration
- routines: remove invalid "failed" action status check
- export-import: add v0.5.0 scope export/import (actions, sentinels, sketches, etc)
- mcp/server: validate CSV inputs are strings before splitting
- schema: replace runtime require with static import
- README: fix stale tool/endpoint counts (28→37, 72→93)

* fix: second round code review — mesh locks, routines DAG, MCP input validation, README counts

- mesh.ts: add withKeyedLock on action writes in receive path, add IPv6 private ranges to SSRF check
- routines.ts: validate DAG (duplicate orders, unknown deps), set dep actions to blocked, refresh stepStatus in routine-status
- checkpoints.ts: runtime type enum validation, set linked pending actions to blocked
- leases.ts: validate ttlMs is finite positive number
- export-import.ts: add skip strategy checks for all v0.5.0 import blocks
- mcp/server.ts: typeof guards on tags, config JSON.parse, actionIds, linkedActionIds, categories
- README.md: Tools 18→37, Functions 33→50, stats line updated
- test: update checkpoint test for new blocked-on-create behavior

* fix: third round review — lease renew/release safety, mesh locking, export replace cleanup, MCP input guards

- leases.ts: renew extends from max(now, existing expiry) instead of now; release verifies action ownership before mutation
- mesh.ts: withKeyedLock on memory writes in mesh-receive; applySyncData validates id/updatedAt and locks both memory and action writes
- routines.ts: stepStatus maps "blocked" to "pending" explicitly; progress includes blocked/cancelled counts; routine-freeze wrapped in withKeyedLock
- export-import.ts: remove unused RoutineRun import; replace strategy clears all orchestration namespaces; skip strategy for graphNodes/graphEdges/semantic/procedural
- mcp/server.ts: sentinel_trigger JSON.parse with typeof+try/catch; facet_query typeof guards on matchAll/matchAny; remove redundant requires cast; .filter(Boolean) on concepts/files/tags/requires CSV splits
- README.md: clarify API table is a representative subset

* fix: fourth round review — redirect SSRF, blocked-on-create, missing action handling, boolean normalization

- mesh.ts: add redirect:"error" to both outbound fetch calls to prevent SSRF via redirect
- routines.ts: create actions with status "blocked" directly when hasDeps (eliminates two-pass race); handle missing actions in routine-status as cancelled; progress.total uses run.actionIds.length
- mcp/server.ts: sentinel config accepts object values directly; normalize unreadOnly/dryRun for both JSON booleans and string values
- README.md: consistent bundle size (365KB) across both occurrences
2026-03-09 09:08:56 +00:00
Rohit Ghumare 70999c3f45 fix: address 38 system audit findings across security, correctness, and reliability (#68)
- Timing-safe HMAC auth in api.ts, mcp/server.ts (eliminates length leak)
- Keyed mutexes for race conditions in observe, remember, relations
- Write ordering: supersede before save to prevent dual-latest
- Single VERSION constant replacing 11 hardcoded strings
- Input validation: governance filter guard, team itemType, maxObs, commitHash regex
- Future-proof import version validation with VERSION in supported set
- Circuit breaker configurable thresholds with positiveFinite validation
- Health monitor interval.unref(), telemetry dead exports removed
- 3 new secret patterns (npm_, glpat-, dop_v1_), shared CSP constant
2026-03-04 07:09:22 +00:00
Rohit Ghumare 709905696b fix: package.json paths, standalone shebang, integration tests
- Fix main/bin/start to use .mjs extension (tsdown outputs ESM)
- Remove duplicate shebang banner from standalone build config
- Update integration test: health status "healthy" (v0.4.0), viewer HTML check
- Add POST body to pre-compact hook for claude-bridge sync
2026-03-01 23:53:46 +05:30
Rohit Ghumare 134cf96124 feat: agentmemory v0.4.0 — the memory layer for all AI coding agents (#9)
* feat: agentmemory v0.4.0 — the memory layer for all AI coding agents

7 new features: Claude Code memory bridge, standalone cross-agent MCP server,
knowledge graph with entity extraction, 4-tier memory consolidation pipeline,
team/shared memory, memory governance with audit trail, git-versioned snapshots.

33 functions, 18 MCP tools, 6 MCP resources, 3 MCP prompts, 49 REST endpoints,
21 KV scopes, 216 tests. All features opt-in via env vars.

* fix: address 28 CodeRabbit findings across v0.4.0 codebase

Critical: Fix bin path mismatch (dist/mcp-standalone.mjs -> dist/standalone.mjs)
Bugs: Fix procedural decay, parseFloat||0.5 for zero values, snapshot restore
missing graphNodes/observations, git catch too broad, N+1 graph query, BFS
duplicate edges, array mutation in audit sort, date validation
Improvements: Lazy readline in transport, JSON-RPC validation, persist error
handling, ID collision prevention, defensive null coalescing for concepts/files,
Windows backslash support in config, direction required for bridge sync tool,
try-catch for audit/governance MCP, team profile fallback teamId, POST body for
bridge sync hook, observations validation for graph-extract endpoint, await in test
2026-03-01 18:03:36 +00:00
Rohit Ghumare 8b21ae2bf6 feat: agentmemory v0.4.0 — MCP resources, prompts, enrichment, confidence (#7)
* feat: agentmemory v0.4.0 — MCP resources, prompts, enrichment, confidence

Add 4 MCP resources (status, project profile, recent sessions, latest memories),
3 MCP prompts (recall_context, session_handoff, detect_patterns), confidence-scored
memory relations, and a unified enrich endpoint that aggregates file context,
relevant observations, and past bug memories for PreToolUse hook injection.

- Add confidence field to MemoryRelation with auto-scoring from co-occurrence,
  recency, and relation type
- Add mem::enrich function aggregating 3 sources with resilient .catch() fallbacks
- Add POST /agentmemory/enrich REST endpoint
- Switch PreToolUse hook from file-context to enrich endpoint with search term extraction
- Add minConfidence filter and confidence-desc sorting to mem::get-related
- 27 new tests (171 total), all passing

* fix: address review findings — input validation, XML escaping, confidence scoring

- enrich.ts: Sort bug memories by recency before slicing top 3; add escapeXml()
  for narratives and bug content injected into XML tags
- relations.ts: Use filter+max instead of find() for matchingRelation to pick
  highest confidence when multiple edges exist; normalize minConfidence with
  Number.isFinite + clamp to [0,1]
- mcp/server.ts: Guard decodeURIComponent with try/catch returning 400 on
  malformed percent-encoding; use typeof checks for prompt args instead of
  truthy checks; normalize minConfidence/maxHops at MCP layer
- api.ts: Validate files[] and terms[] element types are strings before
  calling mem::enrich
- Tests: Add malformed URI and non-string prompt arg test cases (173 total)
2026-02-28 10:28:32 +00:00
Rohit Ghumare a6fabc77d2 feat: agentmemory v0.3.0 — semantic search, memory evolution, profiles
Add 10 major capabilities for production-grade agentic memory:

- Hybrid BM25 + vector semantic search with Reciprocal Rank Fusion
- 6 embedding providers (Gemini, OpenAI, Voyage, Cohere, OpenRouter, local)
- Memory versioning with relationships (supersedes/extends/derives/contradicts)
- Persistent BM25 + vector indices with debounced KV writes
- Progressive disclosure search (compact results → expandable full details)
- Project profiles (top concepts, files, conventions, common errors)
- Chronological timeline navigation around anchor points
- Auto-forget with TTL expiry and contradiction detection
- Ordered provider fallback chain with automatic failover
- Full JSON export/import round-trip (merge/replace/skip strategies)

17 new source files, 11 new test files, 14 modified files.
144 tests pass, build 39.88 KB. 10 MCP tools, 28 REST endpoints, 21 functions.
2026-02-27 11:33:48 +05:30
Rohit Ghumare 57d6f087ad feat: v0.3.0 — self-evaluating agentic memory system
Add production-grade self-evaluation, health monitoring, and resilience:

- Zod input/output validation for all 11 functions with quality scoring (0-100)
- Self-correcting LLM retry on validation failure
- Per-function metrics tracking (success rate, latency, quality) in KV
- Circuit breaker for LLM providers (closed→open→half-open state machine)
- ResilientProvider wrapper with automatic circuit breaker integration
- Periodic health monitoring (CPU, memory, event loop lag, connection state)
- Health threshold evaluation (healthy/degraded/critical with alerts)
- Local observation queue for engine disconnection recovery
- SHA-256 content-hash deduplication with 5min TTL window
- Memory lifecycle eviction (stale sessions, low-importance obs, per-project caps)
- BM25 search scoring replacing basic TF (k1=1.2, b=0.75, IDF weighting)
- OTEL telemetry setup with counters and histograms
- Enhanced /health endpoint returning real metrics, function stats, circuit state
- New /evict endpoint for memory lifecycle management
- 82 tests passing (37 new: eval schemas, quality scoring, circuit breaker)
2026-02-27 11:33:48 +05:30
Rohit Ghumare feffc5a362 add integration tests, polish README, simplify code
- Add integration test suite covering all 11 API endpoints
- Rewrite README for clarity and user-friendliness
- Extract VIEWER_CSP constant, remove dead IndexEntry.terms field
- Consolidate SIGINT/SIGTERM handlers
2026-02-27 11:33:48 +05:30
Rohit Ghumare c85ee6d1e5 fix: address all code review findings
- XML tag validation: reject invalid tag names before regex construction
- API auth: optional bearer token (AGENTMEMORY_SECRET) on POST endpoints
- Conservative token estimation: length/3 for code-heavy content
- XML-escape project name in context output
- Prefix-only search matching (startsWith vs includes)
- Dynamic viewer URLs from window.location
- CSP header on viewer endpoint
- Importance class sanitization in viewer
- 45 tests: privacy, XML parsing, search index, schema
2026-02-27 11:32:40 +05:30