119 Commits

Author SHA1 Message Date
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
v0.8.6
2026-04-14 00:31:10 +01:00
Rohit Ghumare 3935aecdae chore: bump version to 0.8.5 + add CHANGELOG (#133) v0.8.5 2026-04-13 20:03:04 +01:00
Rohit Ghumare c1a63b08d7 Merge pull request #131 from rohitg00/fix/mcp-notification-no-response-129
fix(mcp): never respond to JSON-RPC notifications (#129)
2026-04-13 19:25:23 +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 9bee06760a Merge pull request #130 from rohitg00/fix/windows-cli-followups-128
fix(cli): capture signal kills + guard empty env paths (#128 followups)
2026-04-13 17:46:02 +01:00
Rohit Ghumare 397a0857e9 fix(cli): capture signal kills + guard empty env paths (PR #128 followups)
CodeRabbit flagged two remaining minor issues on the Windows diagnostics
PR #128 that landed before they were addressed:

1. src/cli.ts:161 — the exit handler only treated non-zero numeric
   codes as abnormal. Signal-killed processes have code === null and
   signal !== null (e.g., SIGSEGV, SIGABRT, SIGKILL). Those crashes
   were silently dropped from startupFailure so the user got the
   generic "did not become ready" timeout instead of a real diagnosis.
   On Windows this rarely fires (abnormal exits usually carry codes)
   but on Unix a segfault in iii-engine would be invisible.

   Fix: widen the guard to `(code !== null && code !== 0) || (code ===
   null && signal !== null)` so signal-only exits are captured too.
   Also generate a clearer fallback message when stderr is empty:
   "process killed by signal SIGSEGV" rather than the old "process
   exited with code null (SIGSEGV)".

2. src/cli.ts:114 — when USERPROFILE (Windows) or HOME (Unix) is
   unset, `join("", ".local", "bin", "iii.exe")` produces a relative
   path like `.local/bin/iii.exe`. Harmless today (the path is checked
   via existsSync which fails silently), but theoretically it could
   match an unintended file in the user's current working directory.

   Fix: guard the env var first, return an empty list (Windows) or
   skip the per-user path (Unix) when the env var is missing. Keep
   the absolute /usr/local/bin/iii fallback on Unix since it's valid
   regardless of HOME.

No test changes — whichBinary and fallbackIiiPaths are CLI side-effect
paths not covered by unit tests. Tests: 684/684. Build clean.
2026-04-13 17:06:15 +01:00
Rohit Ghumare a477f46536 Merge pull request #128 from rohitg00/fix/windows-startup-diagnostics-127
fix(cli): surface real engine startup errors, Windows support (#127)
2026-04-13 16:12:42 +01:00
Rohit Ghumare e2ee04ffa0 fix(cli): normalize whichBinary output for Windows CRLF (PR #128 review)
CodeRabbit caught: `execFileSync(...).trim().split("\n")[0]` leaves a
trailing \r on the first path whenever `where` on Windows returns
multiple matches. `.trim()` only strips leading/trailing whitespace —
the CRLFs between the matches stay, so split("\n")[0] yields
"C:\path\one.exe\r" which spawn() rejects as an invalid path.

Single-match outputs worked by accident because .trim() ate the final
\r\n before the split. The bug only fired when a user had iii installed
in two places simultaneously (e.g. a WSL install alongside a native
Windows install), which is a plausible but non-default setup.

Fix: split on /\r?\n/, trim each line, find the first non-empty one.
Also now returns `null` on empty output instead of the empty string
(behavior is identical through the caller's truthy check, but it
matches the documented Promise<string | null> contract exactly).
2026-04-13 16:06:49 +01:00
Rohit Ghumare ffca536990 fix(cli): correct iii install commands — there is no cargo install iii-engine
Caught during PR #128 review: the install hints I added showed
`cargo install iii-engine` as the recommended path on both Windows
and Unix. That crate does not exist on crates.io. Verified via:

  - https://crates.io/api/v1/crates?q=iii   (no iii-engine result)
  - https://crates.io/api/v1/crates/iii-engine   (404)

The actual install methods per github.com/iii-hq/iii releases:

  - macOS / Linux: curl -fsSL https://install.iii.dev/iii/main/install.sh | sh
    (downloads the prebuilt binary into ~/.local/bin/iii)
  - Windows: download iii-x86_64-pc-windows-msvc.zip from the GitHub
    release page, extract iii.exe, add to PATH or place at
    %USERPROFILE%\.local\bin\iii.exe (which our fallback already checks)
  - Docker: docker pull iiidev/iii:latest (already used by docker-compose)

There is no PowerShell installer (https://install.iii.dev/iii/main/install.ps1
returns 404) and no scoop / winget / cargo path on Windows. The previous
README "From source" line (`cargo install iii-engine`) was already wrong
on main — fixed at the same time so we have one correct source of truth.

Changes:

- src/cli.ts installInstructions(): rewrite both Windows and Unix
  branches to show the correct upstream commands. Add link to
  https://iii.dev/docs at the bottom of each
- src/cli.ts troubleshooting note: "iii-engine version mismatch" line
  no longer references cargo
- src/cli.ts fallbackIiiPaths(): drop the .cargo/bin/iii.exe fallbacks
  on both platforms — they were dead paths since the crate doesn't
  exist. Keep .local/bin/iii.exe (matches where the sh installer puts
  it on Unix and where the README tells Windows users to drop iii.exe)
- README.md "Windows" section: rewrite Option A as "download the
  prebuilt MSVC zip from GitHub releases", add explicit disclaimer
  note that there is no cargo install iii-engine path
- README.md "From source" line: replace stale cargo command with the
  correct sh-installer / Windows-zip / Docker matrix

Same test count (684 / 684), build clean.
2026-04-13 15:30:27 +01:00
Rohit Ghumare 4beb35ab9e fix(cli): surface real engine startup errors, Windows support (#127)
Root cause: when the iii-engine binary crashes on startup or isn't
installed at all, the CLI spawned with `stdio: "ignore"` and swallowed
stderr entirely. 15 seconds later it reported "Check that ports 3111,
3112, 49134 are available" — which pointed users at the wrong problem.
On Windows this was the most common failure mode because most users
don't have Rust/cargo installed and nothing tells them they need it.

Changes:

- Capture engine stderr via `stdio: ["ignore", "ignore", "pipe"]` with
  a 16KB cap, surface it on startup failure or in --verbose mode.
  Processes still spawn detached/unref'd so the parent can exit cleanly.
- `windowsHide: true` so spawning a console app doesn't pop a window.
- Platform-aware iii binary fallback paths: on Windows, search
  %USERPROFILE%\.cargo\bin\iii.exe, %LOCALAPPDATA%\cargo\bin\iii.exe,
  and %USERPROFILE%\.local\bin\iii.exe. On Unix, add ~/.cargo/bin/iii
  alongside the existing paths.
- Use `path.delimiter` instead of hardcoded `:` when prepending to PATH.
- Three-way diagnostic when the engine never becomes ready:
  1. Process crashed → show the captured stderr + common causes
  2. Process never started → platform-specific install instructions
  3. Running but port not responding → platform-specific port check
     command (netstat on Windows, lsof/ss on Unix)
- New `--verbose` / `-v` flag echoes spawn commands and surfaces engine
  stderr even on success. Useful for diagnosing #127-style reports
  across any platform.
- Docker compose lookup searches three candidate paths (was two), fixing
  a latent bug where npm-installed docker-compose.yml at the package
  root wasn't always found.
- README: new `### Windows` section in the install area documenting
  Option A (rustup + cargo install iii-engine), Option B (Docker
  Desktop), and Option C (standalone MCP only, no engine), plus a
  symptoms→fix troubleshooting table.

No test changes needed — engine startup is a side-effect path exercised
only via the CLI binary itself, not imported by any unit test. Verified
via `npm test` (684/684) and `npm run build` (clean).
2026-04-13 15:14:57 +01:00
Rohit Ghumare 3bac0855d6 Merge pull request #126 from rohitg00/chore/release-0.8.4
chore: release 0.8.4
2026-04-13 12:44:07 +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
Rohit Ghumare 61bdcf2494 Merge pull request #121 from JasonLandbridge/fix/standalone-mcp-npx-command
fix: correct standalone MCP invocation to use --package flag
2026-04-13 12:23:35 +01:00
Rohit Ghumare 2665981341 Merge remote-tracking branch 'origin/main' into fix/standalone-mcp-npx-command
# Conflicts:
#	README.md
#	integrations/hermes/README.md
#	integrations/openclaw/README.md
#	src/cli.ts
2026-04-13 12:22:36 +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
JasonLandbridge 54c32c71ac fix: correct standalone MCP help text to use --package flag 2026-04-13 11:54:03 +02:00
JasonLandbridge e83bb112ff fix: correct OpenCode MCP config format and add dedicated example
OpenCode uses a different MCP config format than other tools:
- Config file is opencode.json (not .opencode/config.json)
- Uses "type": "local" with "command" array (not mcpServers format)
- Does not use separate "command"/"args" fields

Also added an OpenCode-specific config block in the Standalone MCP
section alongside the generic JSON example so it's easy to find.
2026-04-13 11:48:00 +02:00
JasonLandbridge 401666a8b6 fix: correct standalone MCP invocation to use --package flag
npx agentmemory-mcp fails because there is no standalone npm package
named 'agentmemory-mcp'. The binary is registered inside the
@agentmemory/agentmemory package and must be invoked with:

  npx --package @agentmemory/agentmemory agentmemory-mcp

Updated all documentation examples across README.md and integration
guides (openclaw, hermes) to use the correct invocation. This fixes
MCP clients that followed the docs and got an npm 404 error.
2026-04-13 11:42:54 +02: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
v0.8.2
2026-04-12 20:38:08 +01:00
Rohit Ghumare 649e6e44c5 feat: light-mode SVG variants for GitHub dark theme compatibility (#115)
Adds a full set of light-background SVG tags in assets/tags/light/
that mirror the existing dark-background tags in assets/tags/.

GitHub <picture> element auto-swaps based on the reader's theme:
- GitHub LIGHT theme  → dark-bg SVG (original, stands out on white)
- GitHub DARK theme   → light-bg SVG (new, stands out on dark)

## 30 light variants generated

Same dimensions, same orange #FF6B35 brand accent, same fonts. Only
the backgrounds and text colors change:

- Background: white → light gray gradient (#FFFFFF → #F8F9FB)
- Border: #E5E7EB (GitHub-style neutral border)
- Title text: #0F172A (slate-900)
- Subtitle text: #64748B (slate-500)

Stat values are slightly darkened for better contrast on white:
- Green: #00D26A → #16A34A
- Orange: #FF6B35 → #EA580C
- Purple: #B5A4FF → #7C3AED

## README changes

All 26 tag references now use <picture> elements:

  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/foo.svg">
    <img src="assets/tags/foo.svg" alt="..." height="..." />
  </picture>

Covers: 14 section headers (both stat rows × 6 = 12 stat cards).

No visual changes for light-theme readers — the original dark SVGs
still show. Dark-theme readers now get proper contrast instead of
dark-on-dark blend.

All 30 light SVGs validated with xmllint. 654/654 tests passing.
2026-04-12 20:28:29 +01:00
Rohit Ghumare b317433211 Adjust image heights in README statistics section
Updated image heights for various statistics in README.
2026-04-12 11:47:47 +01:00
Rohit Ghumare 79a7a8ec04 feat: real agent logos + paste-this-prompt blocks for integrations (#114)
* feat: flashy README with real agent logos + paste-this-prompt blocks for integrations

## Main README — real logos in Supported Agents grid

Replaced plain text cells with real brand logos for all 16 supported agents:

- simple-icons CDN for: Claude Code (Anthropic), Cursor, Gemini CLI
  (Google Gemini), Codex CLI (OpenAI), Windsurf, Claude Desktop, Claude SDK
- GitHub org avatars for: OpenClaw, OpenCode (opencode-ai), Cline,
  Hermes (NousResearch), Goose (block), Kilo Code (kilo-org), Aider
  (Aider-AI), Roo Code (RooCodeInc)
- Shield badge for the generic "Any agent" cell

Each logo is clickable and links to the upstream project. The OpenClaw and
Hermes cells now link directly to integrations/openclaw and integrations/hermes
so users can find the deeper plugin integration.

Added tagline footer below the grid reinforcing the cross-agent story.

## Integration READMEs — paste-this-prompt blocks

Following the gstack pattern, both integration READMEs now open with a
visual hero (upstream logo + agentmemory logo) and a copy-pasteable text
block the user can drop into their agent. The agent handles the entire
setup — start server, update MCP config, verify health, open viewer.

This matches the "paste this into Claude Code" block we already have in
the main README for Claude Code users.

### openclaw/README.md
- Centered hero: OpenClaw org avatar + agentmemory icon
- Shield badges: 43 MCP tools, 4 lifecycle hooks, 95.2% R@5, self-hosted
- "Install it in 30 seconds" section with the paste-this prompt

### hermes/README.md
- Centered hero: NousResearch avatar + agentmemory icon
- Shield badges: 43 MCP tools, 6 lifecycle hooks, 95.2% R@5, self-hosted
- "Install it in 30 seconds" section with the paste-this prompt

All 654 tests still passing.

* fix: reorder agents, replace broken logos, add OpenClaw/Hermes paste blocks, cleaner hero

## Main README

### Supported Agents grid — 3 fixes

1. **Reorder**: OpenClaw and Hermes now in positions 2 and 3 (right after
   Claude Code), since they have first-class gateway plugins in
   integrations/. Users shouldn't have to scroll to find them.

2. **Fix broken Codex logo**: simple-icons CDN returned 404 for the
   OpenAI slug with black color. Switched ALL logos to GitHub org
   avatars (github.com/<org>.png?size=120) which are bulletproof and
   always return real images. Verified 7/7 resolve to actual PNGs.

3. **Bigger logos**: bumped from 40px to 48px for more visual weight.

### Paste-this-prompt toggles

Added two collapsible <details> blocks after the Claude Code paste
prompt: one for OpenClaw, one for Hermes. Each contains a complete
copy-pasteable setup prompt that the agent can execute, plus a link
to the full integration guide.

## Integration README heroes — redesigned

The old hero had two logos separated by an ugly gray "+" shield badge
that looked cheap. Replaced with:

- agentmemory banner.png as the centered hero image
- H1 title with a small inline upstream logo (28px) next to the title
- Bolded tagline + subtitle with upstream link
- Shield badge row (MCP tools, hooks, R@5, self-hosted, license)

Much cleaner and follows the main README's visual pattern.

Verified: 654/654 tests passing.

* Update README.md

* feat: custom SVG tags for section headers (no emojis)

Replaces emoji section headers with custom SVG badges matching the
agentmemory brand style (orange #FF6B35 accent on dark #1A1A1A).
Inspired by shanraisshan/claude-code-best-practice's custom tag
approach in its !/ directory.

## Custom SVG tags created (30 total in assets/tags/)

### 14 section headers (section-*.svg)
Each is a 44px-tall dark rounded badge with:
- Orange gradient accent strip on the left (brand color #FF6B35 → #FF8F5E)
- Uppercase title in white, 800 weight, 2.2 letter-spacing
- Light gray subtitle (#9CA3AF) with section context
- Subtle #2A2A2A border on dark #1A1A1A → #0F0F0F gradient

Sections: works-with-every-agent, benchmarks, vs-competitors, quick-start,
why, how-it-works, search, mcp-server, real-time-viewer, configuration,
api, architecture, development, license.

### 6 hero stat blocks (stat-*.svg)
Big numbers with small uppercase labels, replacing the shield.io badge
row in two places (hero + benchmarks section):
- stat-recall: 95.2% R@5 (green)
- stat-tokens: 92% fewer tokens (green)
- stat-tools: 43 MCP tools (orange)
- stat-hooks: 12 auto hooks (orange)
- stat-deps: 0 external DBs (purple)
- stat-tests: 654 tests passing (green)

### 8 pill tags (pill-*.svg)
Rounded pills with colored dot indicator for inline status tags:
MCP, AUTO HOOK, SKILL, NEW, BETA, STABLE, PLUGIN, SECURE.

### 1 "New in v0.8.2" version tag
Dark pill with orange v0.8.2 version marker.

### 1 section divider
Horizontal line with orange diamond in the middle (unused for now,
available for future sections).

## README changes

- All <h2> section headers now use <img> tags pointing to the SVG
- Hero stats row replaced with stat-*.svg row (same visual position)
- Benchmarks stats row replaced with the same stat-*.svg row
- Nav links updated to match the new h2 anchor IDs
- "New in v0.8.2" callout uses new-v082.svg tag + note
- Cursor grid cell fixed (was missing <strong>Cursor</strong> label)
- Zero emojis in the entire README

All 30 SVGs validated with xmllint, 654/654 tests passing.

* Remove version 0.8.2 image from README

Removed image tag for version 0.8.2 from README.
2026-04-12 11:46:45 +01:00
Rohit Ghumare ae8f061cd6 feat: demo command, benchmark comparison, OpenClaw integration (#113)
* feat: add demo command, benchmark comparison, OpenClaw integration, token cost in viewer

Product & ecosystem improvements surfaced from the last30days research
and competitive analysis of the AI agent memory space.

## New

### agentmemory demo command
Seeds 3 realistic sessions (JWT auth, N+1 query fix, rate limiting)
and runs smart-search queries against them. Shows token-aware semantic
search finding "N+1 query fix" when you search "database performance
optimization" — proof that keyword matching can't do that.

  npx @agentmemory/agentmemory demo

Surfaces the "show don't tell" moment in 30 seconds without requiring
the user to integrate anything.

### benchmark/COMPARISON.md
Head-to-head comparison vs mem0 (53K stars, 68.5% LoCoMo),
Letta/MemGPT (22K stars, 83.2% LoCoMo), Khoj (34K stars),
claude-mem (46K stars), and Hippo. Feature matrix across 18
dimensions. Token efficiency table. Honest caveats about LongMemEval
vs LoCoMo apples-vs-oranges. Lets users compare without trusting our
README.

### integrations/openclaw/
OpenClaw gateway plugin following the same pattern as the Hermes
integration. README, plugin.yaml with hooks config, and plugin.mjs
implementing the 4 lifecycle hooks (on_session_start, on_pre_llm_call,
on_post_tool_use, on_session_end). Gets agentmemory into the OpenClaw
ecosystem for distribution.

## Improved

### Viewer token savings card
Now shows tokens saved AND dollar cost saved (using $0.30/1K as a
reasonable mid-tier model rate) instead of just raw numbers. Makes
the ROI immediately tangible.

### README additions
- "Try it in 30 seconds" section featuring the new demo command
- Competitor comparison link in benchmarks section
- OpenClaw integration link in supported agents table

* refactor: simplify demo command and OpenClaw plugin

- Extract postJson helper in cli.ts runDemo (4x repeated fetch boilerplate → single call site)
- Break runDemo into buildDemoSessions, seedDemoSession, runDemoSearch for single-responsibility
- Replace three-branch if/else command dispatch with a commands map (single error handler)
- Extract typed DemoSession/DemoObservation/SearchResult interfaces
- Simplify OpenClaw plugin.mjs: collapse headers() + fetchJson() into a single postJson method
  Each hook is now ~5 lines instead of ~10

No behavior change. 654/654 tests passing, CLI help and error paths verified.

* fix: address CodeRabbit review on growth changes

## plugin.mjs
- Honor the enabled config flag: constructor now sets this.enabled and
  all four hooks (onSessionStart, onPreLlmCall, onPostToolUse,
  onSessionEnd) return early when disabled
- Fail-fast on non-OK HTTP: previously !res.ok returned null regardless
  of fallbackOnError. Now throws with status/statusText/body when
  fallbackOnError is false
- Update header JSDoc to use the real hook names instead of the
  fictional prefetch/capture/consolidate

## openclaw README.md
- Replace stale hook names (prefetch/capture/consolidate) with the
  actual onSessionStart/onPreLlmCall/onPostToolUse/onSessionEnd names
  matching plugin.mjs
- Add 'text' language identifier to the Project profile code fence to
  satisfy markdownlint MD040

## cli.ts
- Replace ad-hoc Date.now()-based session IDs with generateId("demo")
  from src/state/schema.ts, matching the rest of the codebase
  (snapshot.ts, migrate.ts, consolidation-pipeline.ts)
- Add postJsonStrict helper that throws on non-OK with status + body
- seedDemoSession now uses postJsonStrict for session/start and
  session/end (critical lifecycle calls that should fail fast)
- The observation POST in the loop now inlines the fetch to surface
  HTTP errors via p.log.warn with status/body, still only incrementing
  the stored counter on success

## viewer/index.html
- Fix token-to-dollar conversion that was 100x underreporting:
  tokensSaved / 1000 * 0.3 returns DOLLARS, not cents. Now computes
  dollars first, then cents = Math.round(dollars * 100)
- 100K tokens saved now correctly displays $30.00, not 30ct

All 654 tests still passing.

* fix: address 2 more CodeRabbit findings on plugin.mjs

- Use nullish coalescing (??) for config defaults so valid falsy
  values like min_confidence: 0 or timeout_ms: 0 aren't overwritten
  by defaults. || would clobber them.

- Fix /agentmemory/context payload to match the server contract at
  src/triggers/api.ts:115. The handler expects { sessionId, project,
  budget? } but the plugin was sending { sessionId, query, tokenBudget,
  minConfidence }. Three issues:
  1. Missing required 'project' field
  2. Wrong field name: 'tokenBudget' should be 'budget'
  3. 'query' and 'minConfidence' are not part of this endpoint's
     contract (probably belong on /smart-search instead)
2026-04-12 11:05:21 +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 dd17801adc Merge pull request #112 from rohitg00/feat/readme-redesign-benchmarks
feat: redesign README with benchmarks, competitor comparison, agent grid
2026-04-12 00:32:18 +01:00
Rohit Ghumare de068324ab feat: redesign README with benchmark tables, competitor comparison, and agent logos
- Add prominent benchmark table (LongMemEval 95.2% R@5 + token savings side-by-side)
- Add competitor comparison table (agentmemory vs mem0 vs Letta vs built-in)
- Add visual agent grid showing all 16 supported agents
- Add stats row (95.2% R@5, 92% fewer tokens, 43 tools, 12 hooks, 0 deps, 646 tests)
- Collapse verbose tool lists and API endpoints into expandable sections
- Remove 34-row KV scopes table and 123-function breakdown (internal details)
- Remove lengthy env var comments and inline code examples
- Simplify "How It Works" with 4-tier consolidation table
- Add token savings estimate to CLI status command
- Reduce README from ~900 lines to ~540 lines while adding more visual impact
2026-04-12 00:29:30 +01:00
Rohit Ghumare 7af05ecf78 chore: bump version to 0.8.1 v0.8.1 2026-04-09 19:10:52 +01:00
Rohit Ghumare be24ef72ed fix: viewer not found when installed via npx (#109)
Build script now copies src/viewer/index.html to dist/viewer/.
Also added more candidate paths for index.html resolution so
the viewer works from dist/ (npx), src/ (tsx dev), and repo root.
2026-04-09 19:09:37 +01:00
Rohit Ghumare 122efdeb44 docs: add all major agents to README, prioritized by popularity
Add OpenClaw (345K stars), Codex CLI (62K), Cline (59K), Aider (42K),
Goose (33K), Kilo Code (1.5M users) to both Quick Start table and
Supported Agents section. Ordered by GitHub stars/user count.
2026-04-09 13:48:20 +01:00
Rohit Ghumare e88de77f98 Merge pull request #107 from rohitg00/feat/hermes-integration
feat: Hermes Agent memory provider plugin
2026-04-09 13:43:58 +01:00
Rohit Ghumare 9173b090f4 fix: address review findings on Hermes plugin
- SSRF prevention: validate URL scheme (http/https only) before urlopen
- on_pre_compress: inject fetched context into messages list (was no-op)
- Remove unused self._secret; _api reads from env directly
2026-04-09 13:43:34 +01:00
Rohit Ghumare 112e6f4bc0 feat: add Hermes Agent memory provider plugin
Two integration paths:
1. MCP server (zero code) - add to ~/.hermes/config.yaml
2. Memory provider plugin (deeper) - hooks into Hermes agent loop

Plugin implements the full MemoryProvider ABC:
- prefetch() injects relevant memories before each LLM call
- sync_turn() captures conversation turns in background (non-blocking)
- on_session_end() marks sessions for summarization
- on_pre_compress() re-injects context before compaction
- on_memory_write() mirrors MEMORY.md writes
- system_prompt_block() injects project profile
- 3 tools: memory_recall, memory_save, memory_search

Uses only stdlib (urllib, json, threading). No new dependencies.
2026-04-09 13:33:10 +01:00
Rohit Ghumare 699549ddea Merge pull request #106 from rohitg00/docs/readme-polish
docs: README polish — badges, cost table, architecture diagram
2026-04-09 13:08:29 +01:00
Rohit Ghumare 6fd22d3b1d fix: remove emdashes and AI-sloppy phrasing from README 2026-04-09 13:08:05 +01:00
Rohit Ghumare e602f6e58a docs: README polish — badges, cost table, flow diagram, methodology note
- Add npm version, CI status, license, and stars badges
- Add stats table below intro (95.2% R@5, 92% fewer tokens, 43 tools, 12 hooks, 0 deps)
- Add cost comparison table ($500/yr extraction-based vs $10/yr agentmemory vs $0 local)
- Add memory flow diagram (observe → compress → index → inject)
- Add methodology transparency note on benchmark section
- Update nav links (add Benchmarks, shorten labels)
2026-04-09 13:05:55 +01:00
Rohit Ghumare 15250b3bed docs: move Quick Start to top of README, right after intro 2026-04-09 11:26:40 +01:00
Rohit Ghumare 8a32a4b50a docs: gstack-style Quick Start — paste one block, agent does the rest
Replace numbered steps with a single copy-pasteable instruction block
for Claude Code. The agent reads it and handles: engine startup, plugin
install, hook registration, and verification.

Other agents consolidated into a clean table (Cursor, Gemini CLI,
OpenCode, Claude Desktop, SkillKit, REST API) with inline config.
2026-04-09 11:22:16 +01:00
Rohit Ghumare 798700f2a3 chore: bump version to 0.8.0 v0.8.0 2026-04-09 09:07:57 +01:00
Rohit Ghumare 6894843a92 docs: add MiniMax provider, ANTHROPIC_BASE_URL, search project filter
- LLM Providers table: add MiniMax, note ANTHROPIC_BASE_URL support
- Env vars: add MINIMAX_API_KEY, MINIMAX_MODEL, ANTHROPIC_BASE_URL
- Search endpoint: note optional project/cwd filters
- Fallback chain example: include minimax
2026-04-09 09:06:56 +01:00
Rohit Ghumare cdb06bb5a5 Merge pull request #103 from Garygaoxiang/feat/minimax-provider-and-anthropic-base-url
feat: add MiniMax provider and fix ANTHROPIC_BASE_URL not passed to SDK
2026-04-09 09:04:39 +01:00
Rohit Ghumare 7d644491d1 Merge pull request #105 from Getty/feat/search-project-filter
feat(search): add optional project/cwd filter to mem::search and /agentmemory/search
2026-04-09 09:04:37 +01:00
Rohit Ghumare 6614d0c9d7 Merge pull request #102 from rohitg00/feat/dx-improvements
feat: DX improvements — dark mode, status command, memory previews
2026-04-09 08:58:54 +01:00
Rohit Ghumare 4c1184b185 fix: address review findings on DX improvements
- README: add `text` language tag to fenced code blocks (MD040)
- cli.ts: sessions endpoint returns {sessions: [...]}, not a raw array
- viewer: token budget from URL param instead of hardcoded 2000
- viewer: applyTheme takes persist param, auto-detection doesn't save to
  localStorage (prevents OS preference from being overridden on first load)
2026-04-09 08:53:40 +01:00
Torsten Raudssus d145b0e3ab perf(search): load observations in parallel after session filter
Address CodeRabbit nitpick on #105: split the result-building loop into
two phases. First filter sequentially (benefits from the per-call
session cache), then batch the kv.get(observations) calls through
Promise.all instead of awaiting them one at a time.
2026-04-09 05:17:32 +02:00
Torsten Raudssus 26fea3a675 fix(search): validate inputs and avoid logging raw paths
Address CodeRabbit review on #105:

- mem::search now validates query (non-empty string), limit
  (positive integer, capped at MAX_LIMIT=100), project and cwd
  (must be strings if provided). Throws on invalid input instead
  of silently coercing.
- Renamed local 'limit' to 'effectiveLimit' to avoid shadowing.
- ctx.logger no longer emits raw cwd/project (host paths) — logs
  only hasProjectFilter/hasCwdFilter booleans.
- api::search whitelists request body fields, returns 400 on
  malformed input, and constructs an explicit payload for
  sdk.trigger instead of forwarding req.body.
2026-04-09 05:01:56 +02:00
Torsten Raudssus a732ad1e23 feat(search): add optional project/cwd filter to mem::search and /agentmemory/search
Closes #104

The /agentmemory/search HTTP endpoint and the underlying mem::search
function previously accepted only { query, limit }, returning hits
across all projects on the host. Sessions are already created with
{ project, cwd } via session::start, so this just exposes that scope
on search.

- mem::search now accepts optional project and cwd. When set, results
  are filtered by looking up each hit's owning Session.
- To keep the post-filter from starving the result set, the index
  fetch is over-fetched (max(limit*10, 100)) when filtering, then
  trimmed to limit after filter.
- Session lookups are cached per call.
- api::search forwards the new params; fully backward compatible.
2026-04-09 04:29:46 +02:00
翔 高 ab0901f25d feat: add MiniMax provider and fix ANTHROPIC_BASE_URL not passed to SDK
- Add `MinimaxProvider` (`src/providers/minimax.ts`) that calls MiniMax's
  Anthropic-compatible API via raw `fetch` instead of the Anthropic SDK.
  The SDK auto-injects `x-stainless-*` headers that MiniMax rejects with 403;
  using `fetch` directly avoids this entirely.

- Fix `AnthropicProvider` constructor to accept an optional `baseURL` and
  forward it to `new Anthropic({ apiKey, baseURL })`.  Previously the provider
  always connected to `api.anthropic.com` even when `ANTHROPIC_BASE_URL` was
  set in `.env`, because `getMergedEnv()` returns a plain JS object that the
  Anthropic SDK never sees.

- `detectProvider()` in `config.ts`:
  - Checks `MINIMAX_API_KEY` first and returns `provider: "minimax"`.
  - Propagates `ANTHROPIC_BASE_URL` as `baseURL` in the Anthropic config.

- Update `ProviderConfig` in `types.ts` to include optional `baseURL` field.
- Update `ProviderType` union to include `"minimax"`.
- Update `VALID_PROVIDERS` set in `config.ts` to include `"minimax"`.
2026-04-09 09:11:03 +08:00
Rohit Ghumare 75a2d35ed6 feat: DX improvements — dark mode, status command, memory previews, token savings
Viewer:
- Dark mode toggle (persists to localStorage, respects prefers-color-scheme)
- Fix hardcoded canvas colors for dark theme (grid, labels, tooltips)
- Memory search shows 2-line content preview with search term highlighting
- Concept tags shown inline on memory cards (max 4)
- Token Savings stat card on dashboard (estimates savings vs full context)

CLI:
- New `agentmemory status` command — shows connection, health, sessions,
  graph stats, viewer URL without opening browser

README:
- SkillKit universal install: `npx skillkit install agentmemory` (32+ agents)
- "First Steps After Install" section with worked Session 1 → Session 2 example
- Shows actual compressed observation format and context injection
- "How to verify" checklist
2026-04-09 00:18:27 +01:00