Skip to main content
Glama

codemem

CI npm version npm downloads per month License: MIT

The code is still there. The reasoning usually isn’t.

codemem is persistent coding memory across sessions, machines, and teammates for OpenCode, Claude Code, and Codex. It captures decisions, dead ends, and repository-specific traps, then automatically brings relevant context into later prompts.

  • Automatic context injection — relevant memories reach the agent without asking it to search; unchanged memories already in OpenCode context are not repeated

  • Optional sync and sharing — peer-to-peer sync carries selected project memory across machines; share project knowledge with a teammate or Team when it helps

  • Local-first storage — memories live in SQLite on your machine; observer processing uses your configured model provider and can incur costs or consume plan usage

  • Hybrid retrieval — FTS5 BM25 lexical search + sqlite-vec semantic search, merged and re-ranked

  • Automatic injection for OpenCode 1 and 2 — the plugin injects context into every prompt, no manual steps; the OpenCode 2 integration is beta

  • Claude Code plugin support — install from the codemem marketplace source

  • Built-in viewer — browse memories, sessions, and observer output in a local web UI

  • Remote MCP access — advanced single-user self-hosting can expose an OAuth-protected Streamable HTTP MCP endpoint to configured remote clients; keep the localhost viewer private (guide)

Synthetic project memories, not real session data. Explore the Feed, Facts, and Projects walkthrough to see how to inspect what was captured.

Quick start

Prerequisites: Node.js 24.15+ and npm (or pnpm). Native database support covers macOS x64/arm64, Linux x64/arm64 (glibc 2.34+ or musl), and Windows x64. 32-bit targets, including Linux armv7, are not supported.

Linux: set ONNXRUNTIME_NODE_INSTALL=skip in your shell and the environment that launches OpenCode, Claude Code, or Codex before the first package install. This avoids downloading the unused ONNX Runtime GPU provider while keeping CPU inference. Setup-managed npx launchers cannot set it themselves.

OpenCode

Codemem requires OpenCode 1.18.29 or newer. One installed @codemem/opencode-plugin package serves both host generations: OpenCode 1 calls its server() entrypoint and OpenCode 2 calls its setup() entrypoint. OpenCode 2 support is validated against the exact stable @opencode/cli@2.0.2 and @opencode/plugin@2.0.2 releases; Codemem labels its OpenCode 2 integration beta until it has shipped through a full release cycle.

On OpenCode 2 the plugin captures user and assistant messages, terminal usage, tool results, and session lifecycle events, and exposes the same mem-status, mem-recent, and mem-stats tools. Automatic recall runs through session.context: the latest user-message ID is required, and a missing or blank ID skips recall safely. Each identified turn performs one fresh retrieval; retries and tool continuations replay retained context byte-for-byte. Compaction, title, and generate hooks stay isolated. Both the default message surface and legacy CODEMEM_INJECT_SURFACE=system surface work. See OpenCode host support, troubleshooting, and rollback.

  1. Install the OpenCode plugin and MCP config:

npx -y codemem setup --opencode-only
  1. Restart OpenCode.

npx uses a downloaded or cached package to configure the OpenCode host; it does not create a durable codemem CLI installation. The configured plugin manages backend execution independently on both hosts, so no global install is required for automatic capture and context injection.

Setup writes the singular plugin key on purpose. OpenCode 1 requires that key, and OpenCode 2 translates it into its native plugins configuration, so one config entry works on both hosts. Keep one Codemem entry; if OpenCode loads Codemem twice for one project, the first registration wins and later copies skip their hooks with a warning.

  1. Verify:

# Works on fresh installs (no global codemem needed)
npx -y codemem stats
npx -y codemem db raw-events-status

That's it. On either host, the plugin captures activity, builds memories, and injects relevant context from here on.

Try a fresh-session recall

After completing a task, check that its decision appears in the local viewer at http://localhost:38888. Start a new OpenCode session in the same project and ask about that decision without supplying the answer. For example, if your task involved a database migration:

What decision did we make about the database migration, and why?

Verify the answer against the stored decision and the original task evidence. If capture is still pending or recall is empty, inspect the local state:

npx -y codemem status
npx -y codemem db raw-events-status

Observer access and external-model costs

The observer is the model that turns captured activity into memories. It needs a configured runtime and usable authentication: api_http uses your provider credentials; sidecar runtimes use Claude or Codex authentication. Local storage does not mean local-only processing: captured context is sent to the configured model, and calls can incur charges or consume plan usage. See configuration for options.

codemem keeps one minimum Node.js version across published packages and workspace tooling.

If you want codemem on your PATH for manual commands and semantic retrieval, install the CLI globally. The CLI installs its matching embedding runtime by default:

# Linux: skip the unused ONNX Runtime GPU provider download
env ONNXRUNTIME_NODE_INSTALL=skip npm install -g codemem

# Apple silicon macOS and Windows
npm install -g codemem

For a smaller keyword-only install, use npm install -g codemem --omit=optional and set CODEMEM_EMBEDDING_DISABLED=1 in every Codemem process. The flag is required because npm also omits sqlite-vec's optional platform package; the CLI then remains functional with FTS5.

An npm-capable manager, such as pnpm or mise's npm:codemem backend, can also provide the durable CLI. Ensure codemem is on your PATH, then run codemem setup --opencode-only. For a pnpm-global CLI, codemem update check reports the exact paired pnpm add -g codemem@<version> @codemem/embeddings@<version> command. Canonical pnpm virtual-store detection provides guidance but does not prove ownership. An explicit codemem update install re-checks the active package and global-root ownership with bounded, neutral-directory pnpm root -g, pnpm bin -g, and pnpm list -g --depth 0 --json calls before it mutates anything; it accepts pnpm 9–11's <list-root>/node_modules root and pnpm 12's <list-root> root only. It then installs exact matching packages with default and @codemem registry pins and verifies registered package state plus the specific pnpm-bin launcher. The updater never runs a build-approval command: pnpm 9 still runs install scripts by default, while newer pnpm releases apply their configured build-script policy. For a mise-managed CLI, codemem update check reports the exact global update command. An explicit codemem update install confirms from bounded mise ls --json output that the active tool source matches a global source under the user's home directory and that its install path owns the running entry. It writes the exact release into mise's primary global config, confirms the global configured version, and runs the configured tool through mise exec outside the invoking project rather than through a possibly stale or locally overridden PATH entry.

Upgrade a durable CLI with the package manager that installed it, then rerun the corresponding setup command for an existing setup-managed integration. Setup replaces its old managed npx -y codemem mcp launcher and codemem MCP entries detected as UV/UVX-based so both packages share one runtime; other custom MCP commands remain unchanged. The host plugin is managed independently. Claude marketplace installs use the plugin's bundled MCP configuration and do not require a separate setup --claude-only step.

Generated MCP configurations use the global codemem binary when available. Otherwise, setup-managed npx launchers request both packages in one temporary environment. Restart the updated host and any codemem serve process after an installation change. An already-running Claude or Codex MCP host keeps lexical-only recall until it restarts; restarting codemem serve does not restart that child.

The semantic runtime is pinned to CPU inference on every platform. ONNX Runtime 1.24.3 does not ship a macOS x64 binary, so Intel Macs continue with FTS5 keyword retrieval when semantic runtime initialization fails.

OpenCode plugin and CLI are now split intentionally:

  • @codemem/opencode-plugin — OpenCode plugin package

  • codemem — CLI and MCP commands

  • @codemem/embeddings — optional semantic embedding runtime installed by the CLI

OpenCode treats configured npm plugins and checkout-local .opencode/plugins/ files as separate sources. The repository wrapper loads the checkout source on OpenCode 1 and acts as a no-op on OpenCode 2. Before dogfooding OpenCode 1 source changes, temporarily remove the configured npm plugin so it cannot initialize before the checkout wrapper; restore the npm entry after testing. On OpenCode 2, the configured npm plugin remains the only active Codemem instance and loads the package's ./tui companion, which displays injection, compatibility, persistence, and update notices emitted by the server plugin. Notices remain best-effort and never affect capture or recall.

When dogfooding unpublished TUI changes from a source checkout, add the checkout's packages/opencode-plugin directory to the OpenCode 2 cli.json plugins list, temporarily remove the configured npm plugin, restart the TUI, and restore the npm entry after testing.

OpenCode 2 support needs no storage change. Both hosts write the same raw-event stream and SQLite database, so switching between OpenCode 1 and OpenCode 2, or setting CODEMEM_PLUGIN_IGNORE=1 in the OpenCode 2 environment to stop the V2 path, requires no database migration.

Capture follows the OpenCode 1.18.29 runtime contract: completed assistant messages use info.time.completed, token usage comes from info.tokens, and successful and failed tool executions are both recorded. OpenCode reports successful tools through tool.execute.after and failed tools through errored tool parts; Codemem normalizes both into the shared raw-event stream without double-counting repeated failure updates.

OpenCode 1 also preserves verified delegation provenance for individual task briefs. A proven brief-only batch stays in raw storage without an observer call or learned memory; later findings recover bounded earlier instructions from the same raw stream. Recovered instructions follow new evidence so observer clipping does not replace current findings with old task briefs.

Missing or ambiguous provenance retains normal extraction. See delegated brief capture for matching rules and limits. Restart OpenCode after updating the plugin.

Automatic OpenCode recall carries the host session ID through Viewer or CLI into Core assembly. Summary memories are eligible only from the exact mapped session; durable facts from other sessions remain eligible. If the mapping is not ready, automatic recall omits summary continuity rather than guessing from project, a missing host identity, or sibling IDs. Explicit pack and MCP requests keep their existing behavior. See the requester-session contract.

Claude Code (marketplace install)

  1. In Claude Code, add the codemem marketplace source and install the plugin:

/plugin marketplace add kunickiaj/codemem
/plugin install codemem
  1. Restart Claude Code.

The plugin bundles its MCP configuration and capture/context-injection hooks, and starts MCP with the TS CLI (codemem mcp). No preliminary codemem setup --claude-only command or global CLI install is required. The prerequisites and observer-access requirements above still apply.

Claude and Codex plugins normalize native hooks at the plugin edge and send the resulting envelope to the canonical POST /api/raw-events endpoint. New ingestion requests include the intended database path and runtime identity target; Viewer rejects a mismatch before writing, and the client uses its existing identity-correct command fallback. On a retryable Viewer failure, Codex persists that exact envelope before attempting command fallbacks and removes the spool only after a fallback succeeds; Claude uses the command fallbacks without a file spool. Claude SessionEnd asks Viewer to finish boundary extraction best-effort inside the host's 1.5-second default exit budget, reserving command-fallback time after preprocessing and across both HTTP attempts. Stop flushing remains opt-in and uses a 130-second host timeout for its 125-second internal extraction budget. Transcript fallback reads at most the final 16 MiB: it preserves the first record when the tail starts immediately after a newline, but discards the first fragment when the tail starts in the middle of a record. The checked-in dependency-free normalizers are generated from the TypeScript implementations in packages/core/src/claude-hooks.ts and packages/core/src/codex-hooks.ts. Named Viewer hook routes remain compatibility aliases/callers for older packaged and plugin-free CLI paths; requests that omit targeting fields remain accepted for 0.41 compatibility.

Claude and Codex UserPromptSubmit hooks are dependency-free direct Viewer clients. They perform a payload-free compatible-profile check, retrieve an identity-gated POST /api/pack response, return host-compatible additionalContext, and record delivery best-effort (capped at 500 ms). Healthy retrieval starts no codemem or npx child. Retryable Viewer/version/profile failures—including structured request errors before a compatible handshake—use one local compatibility chain. Validated request errors after compatibility is established, plus policy, authorization, and compatible-profile contract failures, fail closed. Prompt and event HTTP reject non-loopback Viewer hosts without fetching them. Codex reserves a total 4.5-second prompt-output budget within its 5-second host timeout.

Codex

Codex installs through its own plugin marketplace:

  1. Add the codemem marketplace and install the plugin:

codex plugin marketplace add https://github.com/kunickiaj/codemem.git
codex plugin add codemem@codemem
  1. Restart Codex.

The Codex plugin bundles its MCP config (codemem mcp), hooks, and generated normalizer. Healthy hook ingestion uses Viewer HTTP directly and starts no codemem or npx child; those commands are fallback-only. A global install remains optional and reduces fallback latency. Validated targets are Codex CLI 0.135+ and current Desktop builds.

API-key Codex Desktop (marketplace unavailable): When plugin installation is greyed out (non-subscription / API-key Desktop), configure codemem without the plugin surface:

npx -y codemem setup --codex-only

This merges [mcp_servers.codemem] into ~/.codex/config.toml and writes ~/.codex/hooks.json (SessionStart, UserPromptSubmit, PostToolUse, Stop) — backing up existing files and preserving unrelated entries. Restart Codex and approve the one-time prompt to trust the codemem hooks. MCP recall works immediately. If codemem is on your PATH the hooks call it directly; otherwise they use an npx launcher that requests both codemem and @codemem/embeddings. Honors CODEX_HOME; re-runnable (use --force to refresh).

Codex hook ingestion shares the same raw-event pipeline as Claude and OpenCode through normalized POST /api/raw-events. After a retryable HTTP failure it writes the exact envelope to ~/.codemem/codex-raw-event-spool, attempts the codemem enqueue-raw-event command fallbacks, and removes the spooled envelope only after success. That spool is separate from the legacy native-hook spool. UserPromptSubmit runs capture ingest in the background and injects memory context via additionalContext; disable injection with CODEMEM_INJECT_CONTEXT=0. See docs/plugin-reference.md for details and troubleshooting.

Was this repository previously installed as opencode-mem? See the rename migration guide. It covers this repository's former name, not importing data from tickernelz/opencode-mem.

Related MCP server: Cortex

How it works

Adapters hook into runtime event systems (the OpenCode 1 plugin and Claude hooks). They capture tool calls and conversation messages, flush them through an observer pipeline that produces typed memories, and surface retrieval context for future prompts.

The workflow below illustrates the OpenCode 1 hook names. OpenCode 2.0.2 uses session.context for the same automatic recall behavior, with the latest user-message ID required for safe turn identity.

sequenceDiagram
participant OC as OpenCode 1
participant PL as codemem plugin
participant VW as viewer HTTP
participant ST as MemoryStore
participant DB as SQLite

OC->>PL: tool.execute.after events
OC->>PL: experimental.chat.messages.transform
PL->>VW: POST /api/pack with shaped query
VW->>ST: build_memory_pack
ST->>DB: FTS5 BM25 lexical search
ST->>DB: sqlite vec semantic search
ST->>ST: merge rerank and section assembly
ST-->>VW: pack text
VW-->>PL: pack JSON
PL->>OC: inject codemem context

Retrieval combines two strategies: keyword search via SQLite FTS5 with BM25 scoring and semantic similarity via sqlite-vec embeddings. In the pack-building path, results from both are merged, exactly deduplicated, and re-ranked using recency and memory-kind boosts. Near-related memories stay fully rendered by default; use compact rendering or CODEMEM_PACK_COMPRESSION=ids only when you intentionally want ID-based expansion via memory_get_observations.

Injection happens automatically. The plugin builds a query from the current session context (first prompt, latest prompt, project, recently modified files), asks the long-lived local viewer to build the pack, and appends the result to the latest user message via experimental.chat.messages.transform. Before sending prompt-derived POST data, it performs a payload-free viewer/profile handshake and rejects redirects. Retryable viewer transport, version, database-target, effective identity/config-target, compression-setting, embedding-setting mismatch, or pre-handshake structured request failures fall back to the existing CLI path; structured request errors become terminal only after compatibility is established. Prior injected message blocks are replayed byte-for-byte on later turns so provider prompt caches can keep the stable prefix. Set CODEMEM_INJECT_SURFACE=system to use the legacy system-prompt surface. Raw-event capture uses a separate queue-first path: Viewer durably accepts the envelope before SQLite ingestion and returns 202; if Viewer is unavailable, OpenCode saves the exact envelope to a private local spool and retries it over HTTP without launching a per-event CLI process. Bounded database, identity, contract, and connection notices omit target values, paths, payloads, subprocess output, and addresses. Each retrieval and current-request cache reuse is recorded through the viewer-backed local evidence ledger with bounded memory identities, machine-readable reason codes, delivery status, and safe repository-relative working-set paths; retryable ledger transport failures retain the CLI fallback. Repository-contained absolute tool paths are converted to repository-relative / paths before retrieval; outside-repository, traversing, blank, and overlong paths are omitted. Prompts, pack text, memory content, and absolute paths are not copied into the ledger, historical message reconstruction creates no new attempts, and recording failures never block injection. After a plugin restart, usable context also remains fail-open when fresh ledger-identity repair fails; fallback bytes are injected without attributing delivery to either the conflicted or failed attempt.

Raw-event degradation logs identify the Viewer stage and safe cause without exposing endpoints, paths, payloads, or subprocess output. Successfully spooled events do not show a user-facing warning; persistence failures and capacity exhaustion still do.

OpenCode defaults to an approximate 800-token injection budget and reserves room for its [codemem context] prefix before requesting the pack. The estimate is ceil(characters / 4), not the provider's tokenizer. Set CODEMEM_INJECT_TOKEN_BUDGET to a positive override; unset, zero, negative, and invalid values use the default. A positive override too small to leave pack capacity injects nothing instead of forwarding 0, which means unlimited to the generic pack CLI.

Automatic message recall has an opt-in retained-context ceiling, off by default. Set CODEMEM_INJECT_RETAINED_TOKEN_BUDGET to a positive safe integer such as 8000 to enable it; unset, zero, or invalid values leave it off. The per-pack default remains 800 tokens. Present historical blocks, including reconstructed blocks after restart, stay byte-identical even above a lowered ceiling. Allowance and local measurements count only blocks from the current hook session; foreign-session entries are preserved but do not consume its budget. Only actual message removal releases allowance; a compaction notification does not. The legacy system surface remains per-pack only, and explicit MCP recall is unaffected. See retained recall lifecycle.

New automatic message blocks omit unchanged memories already retained using renderer-owned IDs, content fingerprints, and spans. Changed facts remain eligible; missing legacy metadata defaults to eligibility rather than guessing from Markdown.

Exact continuation prompts can skip new injection when working context and retrieved facts are unchanged. Retrieval still checks for changed facts; explicit recall and substantive short prompts are not classified as continuations.

Named-topic continuations keep their topic query: next, continue, and resume alone no longer request a broad backlog pack. Automatic topical misses stay empty instead of adding unrelated recent memories or summaries; existing conversation context can stand without a fresh block. Explicit task browsing retains recent-memory fallback; explicit automatic recap may fall back only to the requester's own summary, while manual packs still support recent-memory browsing. See topical retrieval and limits.

Automatic non-task requests reject a semantic-only batch when scoped keyword retrieval finds no support. This deliberately misses useful paraphrases rather than treating nearest neighbors as confidence-qualified matches; manual semantic retrieval, supported hybrid batches, and direct file-reference retrieval remain available. All automatic requests skip timeline neighbor expansion; manual timeline browsing remains supported.

A bare Continue also produces no automatic items when ordinary retrieval has no eligible match. This is the result of retrieval without broadening or fallback, not a phrase denylist; an explicit topic query can still retrieve eligible facts under the same access rules.

With local plugin logging enabled, inject.recall records new/retained token estimates, duplicate counts, and bounded reason codes without content or identifiers. These measurements describe hook delivery, not provider usage or answer quality. Empty packs inject no headings; their artifact identity still distinguishes changed evaluations in Health. Rejected recall measurements do not trigger CLI fallback or mark a healthy Viewer unavailable.

Health's collapsed Automatic recall (advanced) panel shows durable local duplicate hit rates, estimated injection tokens avoided, and metadata gaps. It summarizes at most the newest 1,000 eligible OpenCode retrieval attempts from the last 30 days, filtered to currently visible selected memories. Only recorded fresh evaluations enter the hit-rate denominator; old clients and failed recording mean unknown coverage, not zero savings. When host IDs are missing, evaluation identity uses local turn information rather than prompt text alone and resets at each reported session creation. See measurement definitions and limits.

The profile response advertises a closed compatibility range from min_supported_protocol_version through protocol_version. OpenCode accepts overlapping ranges, including legacy single-version profiles. Database/runtime identity mismatch falls back locally once without reading or retrying that Viewer. Validated request, policy, and authorization failures after a compatible handshake fail closed without a CLI child. A delivery receipt rejected specifically as viewer_contract_unsupported retries once against the same Viewer without optional measurement fields; other contract failures remain terminal.

Memories are typed — bugfix, feature, refactor, change, discovery, decision, exploration — with structured fields like facts, concepts, files_read, and files_modified that improve retrieval relevance. Low-signal events are filtered at multiple layers before persistence.

For architecture details, see docs/architecture.md.

CLI

Group

Command

Description

Core

codemem status

Local operational roll-up (--json supported)

codemem stats

Database statistics

codemem stats --attribution

Bounded local retrieval-attribution diagnostics (--json supported)

codemem recent

Recent memories

codemem search <query>

Search memories

codemem pack <context>

Build a context-aware memory pack

codemem pack trace <context>

Inspect retrieval and pack assembly for a manual query

codemem distill

Mine recurring memories into reviewable context candidates

codemem embed

Backfill semantic embeddings

Memory

codemem memory show <id>

Print a memory item as JSON

codemem memory forget <id>

Deactivate a memory item

codemem memory remember

Manually add a memory

codemem memory inject <context>

Raw pack text for prompt injection

codemem memory export <output>

Export memories by project

codemem memory import <file>

Import memories (idempotent)

Viewer

codemem serve [start|stop|restart]

Launch / manage the web viewer

Sync

codemem sync enable|disable

Enable or disable peer-to-peer sync

codemem sync status

Device info and peer health

codemem sync pair

Advanced/legacy device pairing

codemem sync once

Run one immediate sync pass

codemem sync doctor

Diagnose sync configuration issues

codemem sync bootstrap

Bootstrap sync from a peer snapshot

Updates

codemem update install

Install an eligible release from the installed channel

codemem update check

Check npm for a newer release on the installed channel (--json and --refresh supported)

Coordinator

codemem coordinator

Self-hosted coordinator admin (groups, devices, invites)

Database

codemem db prune-memories

Deactivate low-signal memories (--dry-run to preview)

codemem db prune-observations

Deactivate low-signal observations

codemem db backfill-tags

Populate missing tags_text values

codemem db raw-events-status

Show raw-event queue status

Config

codemem config

View or update configuration

codemem setup

Interactive first-run setup

Plumbing

codemem mcp

MCP stdio server; best-effort starts the local viewer unless CODEMEM_VIEWER=0 or CODEMEM_VIEWER_AUTO=0 is set

codemem mcp http

Local Streamable HTTP MCP server (POST /mcp, loopback-only by default)

Run codemem --help for the human-facing command list. Adapter plumbing commands (claude-hook-*, codex-hook-*, enqueue-raw-event, and prompt-pack-ledger) remain executable for packaged-plugin and stale-client compatibility but are hidden from help and shell completion. show, forget, and remember still work as hidden top-level aliases. export-memories and import-memories remain visible but are deprecated — they warn on stderr and will be hidden from help and completion in a future release; use codemem memory export / codemem memory import.

Use codemem status to answer whether the local database, viewer, sync, maintenance, semantic index, raw-event ingestion, and observer need attention. It is observational: it does not create a missing database, repair state, inspect credentials, or contact peers, coordinators, registries, or non-loopback hosts. Use codemem status --json for the stable machine-readable report. codemem stats remains the inventory and usage command; use sync status/sync doctor, maintenance status, and db raw-events-status for subsystem detail.

codemem update check is read-only: it derives alpha, beta, rc, or latest from the installed version and reports the latest validated release on that same channel with installation-specific guidance. Results are cached for six hours; pass --refresh to force a registry request or --json for one channel-aware status object. The Viewer Health page reads the same status from /api/update-status. The OpenCode plugin checks it after startup and shows at most one best-effort notification for each newly discovered same-channel release. notify is the default. codemem update install performs the explicit, fail-closed installation for proven npm-global, pnpm-global, and mise-managed CLIs. pnpm-global detection uses canonical virtual-store evidence only, so the installer re-proves root and active-package ownership with bounded neutral-directory pnpm queries before installing exact paired packages from the public npm registry; it verifies both package state and the exact pnpm-bin launcher and never approves package builds. Mise updates require matching active and global machine-readable source records under the user's home directory plus matching install-path evidence. A recognized user-level ~/.config/mise.toml source may instead migrate when the bounded global query succeeds with an empty result. Updates pin public default and @codemem npm registries, run mise use -g npm:codemem@<exact-version> without a shell to write the exact release into the primary global config, and verify with an exact target in the post-update global version or requested_version, followed by mise exec -- codemem version outside the invoking project. Linux also sets ONNXRUNTIME_NODE_INSTALL=skip. Bare codemem update remains non-mutating. Explicit plugin auto policy may run a paired, version-pinned public-registry install of codemem and @codemem/embeddings only after the CLI reports a fresh, validated same-channel npm release observed for at least 24 hours and an installation whose npm-global origin can be proven. Mise is never eligible for background auto-update because changing its global tool configuration requires a direct user command. pnpm-global is also never eligible for plugin background auto-install; use the direct codemem update install command. Pinned, cross-channel, unsupported-channel, downgrade, repository-development, stale, Docker, and unknown installs refuse execution. Set CODEMEM_BACKEND_UPDATE_POLICY=off to disable release checks. On Linux, plugin-owned auto-updates preserve the OpenCode environment and set ONNXRUNTIME_NODE_INSTALL=skip for the install to avoid the unused GPU-provider download. Docker guidance is always rebuild-and-restart guidance, never an in-container update.

Pack rendering defaults to self-contained context. For token-constrained experiments, codemem pack <context> --compact renders an index plus top details. Near-related compression is controlled by --compression-mode off|compact|ids (or CODEMEM_PACK_COMPRESSION); MCP memory_pack exposes the same setting as compression_mode. Use ids only when the agent can follow up with memory_get_observations.

Distill recurring lessons

codemem distill finds repeated discoveries and decisions that may be worth promoting into project or user context.

codemem distill --explain               # ranked candidates + evidence
codemem distill --all-projects --json   # machine-readable
codemem distill --no-judge              # skip the observer-model worthiness judgment
codemem distill --draft                 # draft an AGENTS.md rule for the top candidate and show a diff
codemem distill --draft --apply         # write it after confirmation

Candidate mining is deterministic, and by default an observer-model worthiness pass then drops clusters of recurring routine activity (release/CI status, review passes with no findings, context lookups) that recurrence scoring cannot distinguish from real lessons. Without a configured observer model the command falls back to unjudged output with a warning; --no-judge opts out entirely. --draft uses your configured observer model to turn the top candidate into a single AGENTS.md rule and renders a unified diff; nothing is written. --apply writes that rule into a codemem-managed ## Distilled lessons block (delimited by <!-- codemem:distilled:begin/end --> markers, so all distilled edits stay in one place) after prompting for confirmation.

MCP tools

To give the LLM direct access to memory tools (search, timeline, pack, distill candidates, remember, forget):

codemem setup --opencode-only

This updates your OpenCode config to install the plugin and register the MCP server. Restart OpenCode to activate.

The standalone codemem-mcp-ts binary runs the same stdio server used by codemem mcp. Viewer autostart is on by default for both invocation paths; set CODEMEM_VIEWER=0 or CODEMEM_VIEWER_AUTO=0 to disable. MCP autostart and the serve start/stop/restart lifecycle identify a running viewer through GET /api/health (service discriminator codemem-viewer), with one bounded GET /api/stats compatibility probe when an older viewer returns 404.

For local HTTP transport testing, run codemem mcp http. It listens on 127.0.0.1:38889 by default and exposes Streamable HTTP at POST /mcp; use --host, --port, and --db-path to override those values. OAuth discovery metadata and Dynamic Client Registration are available at /.well-known/oauth-authorization-server, /.well-known/oauth-protected-resource/mcp, and /register; set --public-url or CODEMEM_MCP_HTTP_PUBLIC_URL to the externally reachable /mcp URL so advertised endpoints use the public origin. /authorize redirects through a configured upstream OIDC provider before issuing public-client authorization codes, /token supports PKCE S256 exchange, and /oauth/revoke revokes access tokens. When a public URL or OIDC configuration is present, POST /mcp requires a valid bearer token; local-only HTTP mode remains unauthenticated for development and still applies loopback Host/Origin checks. Non-loopback binds are rejected unless you explicitly pass --unsafe-public or set CODEMEM_MCP_HTTP_UNSAFE_PUBLIC=1.

Configuration

Config resolution precedence for runtime commands is:

  1. explicit CODEMEM_CONFIG

  2. workspace-scoped config derived from CODEMEM_RUNTIME_ROOT or CODEMEM_WORKSPACE_ID

  3. legacy global config at ~/.config/codemem/config.json{c}

Environment variables still override file values once a config file has been selected.

Codemem config mutations use a same-directory lock and atomic replacement. Concurrent Codemem writers fail with a retryable conflict instead of silently losing an update; malformed or unreadable existing config is left unchanged. External editors do not participate in the lock, so Codemem checks that the file has not changed again immediately before replacement. Existing mode, owner, and group metadata is retained on POSIX systems. Atomic replacement also retains ACLs and extended attributes on macOS and on GNU/Linux systems whose /bin/cp supports explicit metadata preservation; a metadata-copy failure on those systems aborts the save before rename. Windows, non-GNU Linux, and other platforms retain the existing mode behavior, but Node does not provide a portable API for preserving their extended ACL metadata.

Common overrides:

Variable

Purpose

CODEMEM_DB

SQLite database path

CODEMEM_INJECT_CONTEXT

0 to disable automatic context injection

CODEMEM_INJECT_SURFACE

message (default) to inject near the latest OpenCode user message; system for the legacy OpenCode system-prompt surface

CODEMEM_INJECT_TOKEN_BUDGET

Positive approximate token cap for OpenCode's complete injected context (default 800); unset, zero, negative, and invalid values use the default

CODEMEM_VIEWER_HOST, CODEMEM_VIEWER_PORT

Host/port the plugin-managed viewer should start, probe, and restart

CODEMEM_VIEWER_AUTO

0 to disable auto-starting the viewer

CODEMEM_MCP_HTTP_HOST, CODEMEM_MCP_HTTP_PORT

Host/port for codemem mcp http

CODEMEM_MCP_HTTP_PUBLIC_URL

Public /mcp URL advertised in MCP OAuth metadata

CODEMEM_MCP_OIDC_ISSUER_URL, CODEMEM_MCP_OIDC_CLIENT_ID, CODEMEM_MCP_OIDC_CLIENT_SECRET

Upstream OIDC provider used before MCP OAuth code issuance

CODEMEM_MCP_OAUTH_ALLOWED_SUBJECT, CODEMEM_MCP_OAUTH_ALLOWED_EMAIL

Single-user allowlist for upstream OIDC identity; at least one is required when OIDC is configured

CODEMEM_MCP_HTTP_UNSAFE_PUBLIC

1, true, or yes to allow non-loopback MCP HTTP binds

Viewer note:

  • The plugin manages one explicit viewer target per runtime. If you run multiple viewers, give each one its own DB/runtime folder instead of sharing viewer.pid state next to the same SQLite file.

  • The OpenCode plugin monitors viewer liveness through GET /api/health. When an older viewer returns 404, it makes one compatibility probe to the legacy raw-event status endpoint; raw-event ingest preflight remains separate and is bounded by a 5-second timeout.

The viewer includes a grouped Settings modal (Connection, Processing, Device Sync) with shell-agnostic labels and an advanced-controls toggle for technical fields.

  • Settings show effective values (configured or default) and only persist changed fields on save.

  • The viewer HTTP service is intended for localhost-only use. It does not currently provide a general-purpose auth/session layer for safe public exposure.

Observer runtime/auth:

  • Runtime options: api_http, claude_sidecar, and codex_sidecar.

  • api_http defaults to gpt-5.1-codex-mini (OpenAI path) unless you set observer_model.

  • Anthropic direct API calls accept Anthropic model IDs/aliases. codemem maps the common Claude shorthand claude-4.5-haiku to Anthropic's direct API alias claude-haiku-4-5; you can also set a pinned snapshot like claude-haiku-4-5-20251001 explicitly.

  • claude_sidecar defaults to claude-4.5-haiku; if the selected observer_model is unsupported by Claude CLI, codemem retries once with Claude's CLI default model.

  • codex_sidecar uses the local Codex CLI's authentication and defaults to gpt-5.1-codex-mini unless observer_model is set. See observer auth modes for configuration and automatic selection rules.

  • claude_sidecar command is configurable with claude_command (CODEMEM_CLAUDE_COMMAND) as a JSON argv array.

    • Config file example: "claude_command": ["wrapper", "claude", "--"]

    • Env var example: CODEMEM_CLAUDE_COMMAND='["wrapper","claude","--"]'

  • Auth sources: auto, env, file, command, none.

  • observer_auth_command must be a JSON string array (argv), not a space-separated string.

    • Config file example: "observer_auth_command": ["iap-auth", "--audience", "example"]

    • Env var example: CODEMEM_OBSERVER_AUTH_COMMAND='["iap-auth","--audience","example"]'

  • Header templates support ${auth.token}, ${auth.type}, and ${auth.source} (for example Authorization: Bearer ${auth.token}).

  • Queue cadence is configurable with raw_events_sweeper_interval_s (seconds) in Settings/config.

Export and import

Share project knowledge with teammates or back up memories across machines.

# Export current project
codemem memory export project.json

# Import on another machine (idempotent, safe to re-run)
codemem memory import project.json --remap-project ~/workspace/myproject

See codemem memory export --help and codemem memory import --help for full options. The legacy top-level export-memories / import-memories forms still work but emit a deprecation warning.

Sharing and devices

Share selected project memories with a teammate, or use the same Project-first model to understand your own devices. The viewer's normal workflow is Projects → Sharing → Devices → Health; open Sharing → Teams to manage ongoing Team membership and inherited Project access. Sync internals live under Advanced.

Share projects with a teammate

For ongoing collaboration:

  1. Assign exact Projects to a Team.

  2. Invite people to join it.

Team onboarding links Identities and devices. The invitation does not assign Projects to the Team, but a new member inherits every current and future Project assigned to it. Review the Team's Projects before sending or accepting the invitation. Use Share exact Projects to send a separate direct Project invitation to one Identity. Team sharing must already be configured, but accepting the direct invitation does not add the recipient to the Team.

For a legacy Team that needs setup, finish the reviewed setup on any upgraded device. The first valid finish becomes the Team's shared result; other upgraded devices apply it locally and stop showing that setup task. To finish setup, the device must list the Team's coordinator group in sync_coordinator_groups; scope-backed discovery can show a Team for review but cannot complete its setup. See Set up an existing Team for recovery and compatibility details.

For a direct share, choose Create an invitation → Share exact Projects:

  1. Choose or enter the teammate's Identity display name.

  2. Select the exact projects to share and review each existing-memory count.

  3. Confirm that existing memories and future activity from those projects will share, then send the one expiring invite.

  4. The recipient reviews and accepts the invitation, then confirms their Identity and device display names. Codemem establishes trust and Project access, then starts the first sync.

Only the reviewed canonical projects are shared—similarly named or sibling projects are not included. A memory marked Only me stays local even when its project is shared. Removing access stops future sharing; memories already copied to another device may remain there.

Add, disable, or restore devices

When an Identity adds another device, codemem shows the exact Projects it will inherit from direct shares and Team policies. Existing exclusions stay excluded. Review that list before sending the add-device invitation; acceptance links the new device to the same Identity without widening Project access.

Disabling a device's enrollment for one coordinator group revokes future delivery only for that group's Projects. The global identity device stays active in Devices and can retain access through other groups. In Advanced → Team administration, re-enable that group enrollment; the next owner reconciliation pass then restores only the Projects currently authorized through direct shares and Team policies for that group. An offline device simply waits: it keeps its access and catches up when it reconnects. A separate global identity-device revocation removes the device from the active Devices list. Neither action remotely erases copied memories.

Check devices and health

Devices is read-only. Each card shows the device's Owning Identity, whether it is available, and the Projects it receives:

  • Direct — the Project was shared with that Identity.

  • Team — the Identity receives the Project through a Team policy.

  • Waiting — acceptance, setup, or delivery is waiting; an offline device resumes on reconnect.

  • Needs attention — setup reached a terminal failure; use the displayed retry action.

Use Health for the current status. Globally revoked identity devices are omitted from the active Devices list. A device disabled only for one coordinator group remains listed; use Advanced → Team administration to review or re-enable that group enrollment. Removing access prevents future delivery, but cannot erase a copy already delivered to another device.

Advanced and compatibility

Manual pairing, actor assignment, Spaces, grants, project mappings, and coordinator administration remain available for same-person devices, existing integrations, and diagnostics. They are not required for normal teammate sharing. Existing #sync and #sync/diagnostics links remain supported as Advanced compatibility routes. See the user guide.

Advanced and legacy device pairing

Use manual pairing only for a same-person device, an existing integration, or a compatibility workflow:

codemem sync enable        # generate device keys
codemem sync pair          # generate pairing payload
codemem serve start        # start it; use serve stop/restart for lifecycle management
codemem sync once          # run one immediate sync pass

Legacy pairing and legacy coordinator invitations do not grant project access by themselves. For advanced access details, compatibility, and recovery, see the user guide.

For cross-network setups where peer addresses change frequently or mDNS does not cross VPN/network boundaries, codemem also supports optional coordinator-backed discovery with a self-hosted coordinator. The preferred deployment path is the built-in codemem coordinator service; see docs/coordinator-discovery.md.

Semantic recall

Embeddings are stored in sqlite-vec and written automatically when memories are created. Use codemem embed to backfill existing memories. A custom CODEMEM_EMBEDDING_MODEL requires CODEMEM_EMBEDDING_REVISION; mutable branches and tags resolve to their canonical commit before vectors are labeled. Set CODEMEM_EMBEDDING_OFFLINE=1 with an explicit 40-character commit to load only cached model files without a Hub request. Changing the model or revision triggers a background rebuild and uses keyword search until incompatible migrations finish. If sqlite-vec cannot load, keyword search still works.

Alternative install methods

Local development

pnpm install
pnpm build
pnpm run codemem --help

Via npx (no install)

npx -y codemem stats

Plugin for development

On OpenCode 1, temporarily remove the configured npm plugin, then start OpenCode inside the codemem repo directory to auto-load the V1 plugin source from .opencode/plugins/; restore the npm entry after testing. On OpenCode 2, that repository wrapper is a no-op: keep the configured npm plugin for normal use, or follow the source-checkout steps above to load packages/opencode-plugin explicitly while testing unpublished changes.

The repository's .opencode/plugins/lint-feedback.js auto-loads contributor-only OpenCode 1 and OpenCode 2 adapters backed by the shared lint-feedback implementation in packages/opencode-plugin/src/. The repository-owned entrypoint pins the local Biome command, runs it before and after JavaScript or TypeScript edits covered by biome.json, appends only new or worsened diagnostics to successful edit, write, or patch results, and preserves edits with one warning if linting fails or times out. OpenCode 2 shell commands have no post-execution hook, so changes made through shell commands require an explicit pnpm lint:delta -- --base <ref> checkpoint. Use --staged to inspect only the Git index, as the pre-commit hook does; the hook uses --base auto to compare from the merge base of a local remote-default ref, falling back to HEAD. --staged cannot be combined with --head. The wrapper and lint-feedback sources are excluded from @codemem/opencode-plugin; installing codemem does not enable this feedback hook.

Documentation

Available Tools

14 tools
memory_distill_candidatesA
Read-only

Mine recurring memories into reviewable context candidates. Reads project/user context files without modifying them and can call the optional observer when judge=true.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindNoFilter by memory kind
judgeNoJudge candidates with the observer model and drop routine-activity clusters (on by default; falls back to unjudged output when no observer model is configured)
limitNoMax candidates
projectNoFilter by project scope (matches sessions.project)
scope_idNoFilter by a single sharing domain scope_id
trust_biasNo
visibilityNo
all_projectsNoMine memories across all projects
min_recurrenceNoMinimum member count per candidate
personal_firstNo
ownership_scopeNo
exclude_actor_idsNo
exclude_scope_idsNoSharing domain scope_ids to exclude
include_actor_idsNo
include_scope_idsNoSharing domain scope_ids to include
exclude_visibilityNo
include_documentedNoInclude candidates already represented in context files
include_visibilityNo
max_evidence_itemsNoEvidence snippets per candidate
exclude_trust_statesNo
include_trust_statesNo
exclude_workspace_idsNo
include_workspace_idsNo
widen_shared_when_weakNo
exclude_workspace_kindsNo
include_workspace_kindsNo
widen_shared_min_personal_scoreNo
widen_shared_min_personal_resultsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
versionYes
metadataYes
candidatesYes

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, and the description adds that it reads files without modifying them. It also discloses the conditional side-effect of calling the observer model when judge=true, which goes beyond the annotation structure. This is useful behavioral context beyond the structured hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences front-load the primary purpose and then add the key behavioral note. No redundant wording or recitation of schema fields. Every sentence earned its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has 28 optional parameters and an output schema exists, so return format does not need explanation. The description covers the core purpose and safety profile. However, with many filter options and no direction on how to combine or prioritize them, an agent may struggle to use the tool effectively. Adequate at a high level but missing meaningful usage depth.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 28 parameters and only 39% schema description coverage, the description must compensate, but it only explains the judge option. It gives no guidance for trust_bias, ownership_scope, visibility filters, exclude/include groups, widen_shared options, or other ambiguous parameters. The single judge clarification is marginal but insufficient for the parameter complexity.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb-resource pair ('Mine recurring memories') and the outcome ('reviewable context candidates'), which clearly distinguishes this from search/explain/remember siblings. An agent can infer this is a discovery/distillation tool, not a lookup or mutation tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus siblings like memory_search or memory_pack, and no when-not conditions. The purpose statement implies it's for recurring-pattern mining, but the description does not describe scenarios where an alternative would be more appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_expandC
Read-only

Fetch memories by ID with surrounding timeline context.

ParametersJSON Schema
NameRequiredDescriptionDefault
idsYesMemory IDs to expand
kindNoFilter by memory kind
projectNoFilter by project scope (matches sessions.project)
scope_idNoFilter by a single sharing domain scope_id
trust_biasNo
visibilityNo
depth_afterNoTimeline items after
depth_beforeNoTimeline items before
personal_firstNo
ownership_scopeNo
exclude_actor_idsNo
exclude_scope_idsNoSharing domain scope_ids to exclude
include_actor_idsNo
include_scope_idsNoSharing domain scope_ids to include
exclude_visibilityNo
include_visibilityNo
exclude_trust_statesNo
include_observationsNoInclude full observation details
include_trust_statesNo
exclude_workspace_idsNo
include_workspace_idsNo
widen_shared_when_weakNo
exclude_workspace_kindsNo
include_workspace_kindsNo
widen_shared_min_personal_scoreNo
widen_shared_min_personal_resultsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorsYes
anchorsYes
metadataYes
timelineYes
missing_idsYes
observationsYes

TDQS

C2.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, so the description's 'Fetch' is consistent. The description adds a behavioral detail by stating the output includes 'surrounding timeline context', which goes beyond the read-only hint. However, it does not disclose details like depth controls, filtering behavior, or what 'surrounding' means in practice. Given the annotations, this is acceptable but minimal.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is one sentence, which is concise and front-loaded. However, for a tool with 26 parameters and an output schema, this brevity borders on under-specification. It is not verbose, but it fails to earn its place by providing only a trivial summary that could apply to any memory-related tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This tool is complex (26 params, output schema present), yet the description only states a bare function. It does not explain the timeline context behavior, the meaning of depth_before/after, or how the output relates to the input. An agent would need to inspect the schema and output schema to understand the tool's purpose and behavior, making the description nearly useless for effective invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 26 parameters and only 35% schema description coverage, the description was expected to compensate by explaining key parameters. It mentions none of them – not the required 'ids', nor the depth controls, filters, or the 'include_observations' flag. The description adds zero semantic value beyond the schema, which is already sparse for many parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear verb ('Fetch') and resource ('memories by ID'), and adds 'surrounding timeline context' which hints at differentiating from sibling tools like memory_get (which likely fetches without context) and memory_timeline (which might show a timeline without specific IDs). It is specific enough to convey the core function, though it does not explicitly name alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to use this tool versus memory_get, memory_timeline, or other siblings. No conditions, exclusions, or alternatives are mentioned. An agent must infer the appropriate use case solely from the phrase 'surrounding timeline context', which is insufficient given the variety of sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_explainB
Read-only

Explain search results with detailed scoring breakdown.

ParametersJSON Schema
NameRequiredDescriptionDefault
idsNoSpecific memory IDs to explain
kindNoFilter by memory kind
limitNoMax results
queryNoSearch query
projectNoFilter by project scope (matches sessions.project)
scope_idNoFilter by a single sharing domain scope_id
trust_biasNo
visibilityNo
personal_firstNo
ownership_scopeNo
exclude_actor_idsNo
exclude_scope_idsNoSharing domain scope_ids to exclude
include_actor_idsNo
include_scope_idsNoSharing domain scope_ids to include
exclude_visibilityNo
include_visibilityNo
exclude_trust_statesNo
include_pack_contextNoInclude formatted pack context
include_trust_statesNo
exclude_workspace_idsNo
include_workspace_idsNo
widen_shared_when_weakNo
exclude_workspace_kindsNo
include_workspace_kindsNo
widen_shared_min_personal_scoreNo
widen_shared_min_personal_resultsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
errorsYes
metadataYes
missing_idsYes

TDQS

B3.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already establish readOnlyHint=true and openWorldHint=false, so the description does not need to re-assert safety. It adds the 'detailed scoring breakdown' behavior, which is useful context, but it does not disclose how results are selected or whether a prior search is required.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single efficient sentence with no filler and the core idea is front-loaded. It is concise, though for a tool with 26 parameters it could afford a second clause to clarify usage without becoming verbose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the high parameter count, low schema coverage, and many sibling tools, a one-sentence description is insufficient. It does not explain how to supply 'search results' (via ids vs query vs filters), how parameters combine, or how the scoring breakdown is structured, leaving too much to guesswork.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 35% across 26 parameters, and the description names none of them. The agent gets no help understanding how 'ids', 'query', 'kind', or the many filter parameters behave, so the description does not compensate for the poorly documented schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: it explains search results and provides a detailed scoring breakdown. This distinguishes it from memory_search, which would return the results themselves, though it does not explicitly name any sibling or contrast with them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'Explain search results' implies this tool is for post-search analysis rather than for finding memories, but there is no explicit guidance about when to use it versus memory_search, memory_get, or memory_expand. The intended workflow is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_forgetA
DestructiveIdempotent

Soft-delete a memory by exact ID so it no longer appears in normal retrieval; this is not secure erasure. Does not inherit the default project; optional filters must match or the tool returns not_found.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindNoFilter by memory kind
projectNoFilter by project scope (matches sessions.project)
scope_idNoFilter by a single sharing domain scope_id
memory_idYesMemory ID to forget
trust_biasNo
visibilityNo
personal_firstNo
ownership_scopeNo
exclude_actor_idsNo
exclude_scope_idsNoSharing domain scope_ids to exclude
include_actor_idsNo
include_scope_idsNoSharing domain scope_ids to include
exclude_visibilityNo
include_visibilityNo
exclude_trust_statesNo
include_trust_statesNo
exclude_workspace_idsNo
include_workspace_idsNo
widen_shared_when_weakNo
exclude_workspace_kindsNo
include_workspace_kindsNo
widen_shared_min_personal_scoreNo
widen_shared_min_personal_resultsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool as destructive and idempotent, but the description adds meaningful behavioral context: the delete is soft, it is not a secure erasure, it does not inherit the default project, and optional filters must match or the call returns not_found. This genuinely helps predict side effects beyond the schema and annotations alone.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded: it states the core soft-delete behavior first, then the safety-relevant distinction from secure erasure, then the project/filter condition. There is no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 23 parameters and 26% schema coverage, the description is not fully complete: it is enough for the minimal call 'memory_id only', and an output schema exists, but it does not explain the rich filter parameter space. This leaves gaps for any agent that needs to scope the delete with project, visibility, trust, actor, or workspace parameters in a meaningful way.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is very low at 26%, so the description should compensate. It only clarifies memory_id and the general behavior of 'optional filters must match'; it does not explain the many filter parameters such as ownership_scope, visibility, trust_bias, workspace filters, or the include/exclude arrays. Thus it leaves most parameters functionally undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a precise verb and resource: 'soft-delete a memory by exact ID' and immediately clarifies its effect ('no longer appears in normal retrieval') and limits ('not secure erasure'). This is enough for an agent to distinguish the tool from its read/search siblings without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies the usage: call it when you want to forget a specific memory by ID. It adds useful caveats about the default project and optional filters matching, but it never gives explicit when-to-use versus alternatives or when-not-to-use guidance, so it relies on the agent to infer selection criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_getA
Read-only

Fetch one memory by exact ID. Does not inherit the default project; optional filters constrain the lookup, and a mismatch returns not_found.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindNoFilter by memory kind
projectNoFilter by project scope (matches sessions.project)
scope_idNoFilter by a single sharing domain scope_id
memory_idYesMemory ID
trust_biasNo
visibilityNo
personal_firstNo
ownership_scopeNo
exclude_actor_idsNo
exclude_scope_idsNoSharing domain scope_ids to exclude
include_actor_idsNo
include_scope_idsNoSharing domain scope_ids to include
exclude_visibilityNo
include_visibilityNo
exclude_trust_statesNo
include_trust_statesNo
exclude_workspace_idsNo
include_workspace_idsNo
widen_shared_when_weakNo
exclude_workspace_kindsNo
include_workspace_kindsNo
widen_shared_min_personal_scoreNo
widen_shared_min_personal_resultsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
kindYes
titleYes
body_textYes
confidenceNo
created_atNo
session_idNo
updated_atNo
metadata_jsonNo

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With readOnlyHint=true already covering the safety profile, the description adds meaningful behavioral detail: it does not inherit the default project, optional filters constrain the lookup, and a mismatch returns not_found. These are non-obvious behaviors that an agent cannot derive from the annotations alone.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences, front-loaded with the core operation and immediately followed by the two most important behavioral constraints (default project behavior, not_found on mismatch). No filler or repetition of the input schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the core invocation, the not_found outcome, and a key project-scoping gotcha, and an output schema exists so return values do not need explanation. Still, given the high parameter count and low schema coverage, an agent receives very little guidance on when or how to use the many filtering parameters. It is minimally viable but not complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 26%, so the description must compensate for the many undocumented parameters. It does not: it only says 'optional filters constrain the lookup' without explaining specific parameters like trust_bias, widen_shared_when_weak, personal_first, or the include/exclude filter families. Property names are partially self-explanatory, but the description provides almost no semantic help for the 23-parameter surface.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Fetch one memory by exact ID.' This clearly distinguishes the tool from sibling search/recent tools that perform broader lookups, and the exact-ID emphasis makes its narrow purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage context – an agent should call this when it has a specific memory ID – and it provides a useful caveat about not inheriting the default project. However, it does not explicitly say when to prefer this over memory_search, memory_get_observations, or other siblings, nor does it give exclusion criteria. Usage guidance is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_get_observationsA
Read-only

Fetch multiple memories by exact IDs. Does not inherit the default project. Missing or filtered-out IDs are omitted from results, not reported as not_found.

ParametersJSON Schema
NameRequiredDescriptionDefault
idsYesMemory IDs to fetch
kindNoFilter by memory kind
projectNoFilter by project scope (matches sessions.project)
scope_idNoFilter by a single sharing domain scope_id
trust_biasNo
visibilityNo
personal_firstNo
ownership_scopeNo
exclude_actor_idsNo
exclude_scope_idsNoSharing domain scope_ids to exclude
include_actor_idsNo
include_scope_idsNoSharing domain scope_ids to include
exclude_visibilityNo
include_visibilityNo
exclude_trust_statesNo
include_trust_statesNo
exclude_workspace_idsNo
include_workspace_idsNo
widen_shared_when_weakNo
exclude_workspace_kindsNo
include_workspace_kindsNo
widen_shared_min_personal_scoreNo
widen_shared_min_personal_resultsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds valuable behavioral context: it does not inherit the default project, and missing/filtered-out IDs are silently omitted rather than reported as not_found. This goes beyond the annotations and helps an agent predict result behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the primary action and resource, followed by two critical behavioral caveats. No wasted words; every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has 23 parameters and an output schema, and the description covers the core fetch-by-IDs behavior plus two important caveats. However, with 26% schema coverage and many filter parameters, an agent may not know how filters interact with the ID-based fetch or what the output schema contains. The description is adequate for the primary use case but incomplete for advanced filtering scenarios.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 26%, so the description carries some burden for parameter meaning. The description clarifies the key 'ids' parameter semantics (exact IDs, omission behavior) and the 'project' parameter (does not inherit default). However, most of the 23 parameters remain undocumented in both schema and description, so the description only partially compensates for the low coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Fetch') and resource ('multiple memories by exact IDs'), and distinguishes itself from a default-project behavior. It is clear enough to separate from siblings like memory_get (singular) and memory_search (query-based), though it does not explicitly name those siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage: use this when you have exact memory IDs and want to fetch multiple memories. It notes that it does not inherit the default project, which is a useful context signal. However, it does not explicitly state when to prefer this over memory_get or memory_search, nor does it mention alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_learnA
Read-only

Learn how to use codemem memory tools. Call this first if unfamiliar.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
introYes
forgetYes
recallYes
client_hintYes
persistenceYes
prompt_hintYes
recommended_system_promptYes

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, and the description doesn't contradict them. The description adds that it is a learning/instruction tool, which is mild behavioral context, but does not specify what the agent will actually receive from it. Given annotations, this is acceptable.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, zero fluff. The purpose is in the first line and the usage guidance in the second. This is as lean as a description can be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has no parameters and has an output schema, the description is sufficient for a call-first help tool. It could mention what the output format is, but the presence of a schema covers that, and the simple nature of this tool does not demand more.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has 0 parameters, so the input schema carries no information to enhance. Per the rubric, a no-parameter tool starts at 4, and the description doesn't need to add parameter details that simply don't exist.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Learn how to use codemem memory tools'. The verb 'learn' plus resource and the specific 'first if unfamiliar' hint distinguish it from the sibling tools like memory_search and memory_schema, although it doesn't explicitly name a non-overlap.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says 'Call this first if unfamiliar', giving a clear condition for when to invoke this tool. It does not list alternatives or state when not to use it, but the 'first' ordering provides enough guidance for a meta/help tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_packA
Read-only

Build a formatted context block for a concept or task using keyword and semantic search when embeddings are available, with automatic keyword-only fallback. Use for conceptually relevant context; use memory_search or memory_search_index for exact identifiers.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindNoFilter by memory kind
limitNoMax items to include
compactNoWhen true, render a scannable index of all items with full detail only for the top N (default 3). Saves tokens when broad overview matters more than per-item detail.
contextYesContext description to search for
projectNoFilter by project scope (matches sessions.project)
scope_idNoFilter by a single sharing domain scope_id
trust_biasNo
visibilityNo
personal_firstNo
ownership_scopeNo
compression_modeNoNear-related compression mode: off disables it, compact applies only to compact rendering, ids applies in all modes. Defaults to CODEMEM_PACK_COMPRESSION or compact.
exclude_actor_idsNo
exclude_scope_idsNoSharing domain scope_ids to exclude
include_actor_idsNo
include_scope_idsNoSharing domain scope_ids to include
exclude_visibilityNo
include_visibilityNo
compact_detail_countNoNumber of items to show in full detail in compact mode (default 3)
exclude_trust_statesNo
include_trust_statesNo
exclude_workspace_idsNo
include_workspace_idsNo
widen_shared_when_weakNo
exclude_workspace_kindsNo
include_workspace_kindsNo
widen_shared_min_personal_scoreNo
widen_shared_min_personal_resultsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
contextYes
metricsYes
item_idsYes
pack_textYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds meaningful behavioral context beyond annotations: it discloses the automatic fallback from semantic to keyword-only search when embeddings are unavailable, and the compact mode's token-saving behavior. This is useful operational transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences and front-loads the core purpose and fallback behavior before the routing guidance. It is efficient, though the second sentence could arguably be more specific about which sibling to use for what. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (27 parameters, output schema present), the description is adequate but not complete. It explains the search strategy and routing, but an agent would still be uncertain about what the output block looks like, how the many filter parameters interact, and what 'formatted context block' means concretely. The output schema helps, but the description doesn't bridge the gap for the large parameter surface.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 37%, so the description carries some burden for parameter meaning. The description explains the core 'context' parameter and the 'compact' behavior, but most of the 27 parameters (e.g., trust_bias, personal_first, widen_shared_when_weak) are undocumented in both schema and description. The description adds value for the main parameters but doesn't compensate for the large undocumented surface.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Build') and resource ('formatted context block for a concept or task'), and distinguishes it from siblings by naming memory_search and memory_search_index for exact identifiers. It could be slightly clearer about what 'formatted context block' means, but the core purpose is clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says 'Use for conceptually relevant context; use memory_search or memory_search_index for exact identifiers,' which provides a clear when-to-use and alternative. It doesn't enumerate all sibling alternatives (e.g., memory_recent, memory_timeline), but the primary routing guidance is present.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_recentC
Read-only

Return recent memories, newest first.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindNoFilter by memory kind
limitNoMax results
projectNoFilter by project scope (matches sessions.project)
scope_idNoFilter by a single sharing domain scope_id
trust_biasNo
visibilityNo
personal_firstNo
ownership_scopeNo
exclude_actor_idsNo
exclude_scope_idsNoSharing domain scope_ids to exclude
include_actor_idsNo
include_scope_idsNoSharing domain scope_ids to include
exclude_visibilityNo
include_visibilityNo
exclude_trust_statesNo
include_trust_statesNo
exclude_workspace_idsNo
include_workspace_idsNo
widen_shared_when_weakNo
exclude_workspace_kindsNo
include_workspace_kindsNo
widen_shared_min_personal_scoreNo
widen_shared_min_personal_resultsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes

TDQS

C2.6/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish readOnlyHint=truecars, so the read-only nature is covered. The description adds 'newest first' ordering, which is useful, but it does not disclose defaults, time-window semantics, filtering behavior, or pagination, leaving significant behavioral gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence with no filler. It efficiently states the action and ordering, though it is so brief it edges toward under-specification rather than ideal conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 23 parameters and a complex filtering surface, a one-sentence description leaves much unsaid about intended usage. The presence of an output schema helps, but the description alone does not adequately orient the agent to the tool's full context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is very low (roughly 3 of 23 properties have descriptions), and the tool description adds no parameter meaning. Most parameters, including visibility, trust, workspace, and widening controls, are undocumented in both description and schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description 'Return recent memories, newest first' uses a specific verb and states the ordering behavior, making the core purpose clear. It does not explicitly differentiate from sibling tools like memory_search or memory_get, so it loses a point for lacking sibling contrast.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for fetching recent memories but provides no guidance on when to use this tool instead of alternatives, nor any exclusions or context. No sibling tool comparisons or use-case nuances are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_rememberA

Create a new memory. Use for milestones, decisions, and notable facts.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyYesBody text (high-signal content)
kindYesMemory kind
titleYesShort title
projectNoProject identifier
confidenceNoConfidence 0-1

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false and idempotentHint=false, and the description's 'Create a new memory' is consistent with those. The description adds little behavioral detail beyond that—no mention of persistence, side effects, or availability—though the existing annotations carry most of the safety burden.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with a clear verb-first structure; the core action is front-loaded and there is no filler. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple create tool with full schema coverage, an output schema, and annotations, the description is nearly complete. The main gap is that it never addresses the related memory_learn tool, which could leave an agent unsure which creation route to use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all five parameters, including the kind enum and confidence range. The description's use cases hint at suitable memory content but do not add meaningful parameter-level detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('Create a new memory') and gives concrete use cases ('milestones, decisions, and notable facts'). It is clear, but it does not explicitly distinguish itself from the similarly named sibling memory_learn, so it falls short of full sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides explicit usage context: 'Use for milestones, decisions, and notable facts.' However, it does not say when not to use this tool or name an alternative such as memory_learn or memory_get, so the when-not guidance is missing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_schemaA
Read-only

Return the memory schema — kinds, fields, and available filters.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
kindsYes
fieldsYes
filtersYes
kind_descriptionsYes

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations include readOnlyHint=true, indicating this is a safe read operation. The description adds that the tool returns schema, which is useful context. However, it doesn't disclose additional behavioral aspects such as whether the schema reflects the latest state or if there is any caching. With annotations covering safety, the description adds some value but not rich detail, so a 3 is appropriate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, clear sentence that efficiently conveys the tool's purpose. It is appropriately concise and front-loads the key information. No redundancy or fluff, so it earns a 4. Could potentially be slightly more specific but is already effective.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has zero parameters and an output schema exists, the description need not detail return values. The description clearly states the content of the schema (kinds, fields, filters) which is the main information an agent needs. It is complete for a metadata-retrieval tool, though it could mention if it's the full or partial schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the schema provides no parameter definitions. The description explains what the tool returns (kinds, fields, filters), which is the core semantic information. Since there are no parameters to describe, the description is effective at conveying the purpose, earning a baseline of 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states it returns the memory schema with kinds, fields, and filters. This is clear and specific about what the tool does. However, it doesn't distinguish it from siblings like memory_explain, which might also provide schema-related information. The description is clear but not fully oriented against siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies that this tool is used to retrieve schema information, which is a common first step before using other memory tools. It doesn't explicitly mention when to use it over alternatives like memory_explain, or when not to use it. There is clear context but no explicit exclusions or alternatives, so the guidance is implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_search_indexB
Read-only

Keyword-search memories when you know exact terms or identifiers. Returns compact entries with IDs and titles, without bodies; expand selected IDs with memory_get or memory_get_observations.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindNoFilter by memory kind
limitNoMax results
queryYesSearch query
projectNoFilter by project scope (matches sessions.project)
scope_idNoFilter by a single sharing domain scope_id
trust_biasNo
visibilityNo
personal_firstNo
ownership_scopeNo
exclude_actor_idsNo
exclude_scope_idsNoSharing domain scope_ids to exclude
include_actor_idsNo
include_scope_idsNoSharing domain scope_ids to include
exclude_visibilityNo
include_visibilityNo
exclude_trust_statesNo
include_trust_statesNo
exclude_workspace_idsNo
include_workspace_idsNo
widen_shared_when_weakNo
exclude_workspace_kindsNo
include_workspace_kindsNo
widen_shared_min_personal_scoreNo
widen_shared_min_personal_resultsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, so the description doesn't need to restate safety. It adds useful behavioral context: returns compact entries without bodies, and suggests follow-up expansion. However, it doesn't explain filtering semantics, trust_bias, or how the 24 parameters affect results, which would be valuable for a search tool with many filters.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core purpose and a clear follow-up action. Every word earns its place; no fluff or repetition of schema details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having an output schema, the tool has 24 parameters with only 29% schema coverage and no enums. The description does not explain the filtering model, trust/visibility semantics, or how to combine parameters. For a complex search tool, this is incomplete: an agent cannot reliably know what filters exist or how they interact.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 29%, and the description does not compensate. It mentions query and the compact return format, but does not explain the many filter parameters (kind, project, scope_id, visibility, trust_bias, ownership_scope, include/exclude lists, widen_shared_*). With 24 parameters and most undocumented, the description leaves the agent guessing about how to construct effective searches.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool performs keyword search over memories and returns compact entries with IDs and titles, which distinguishes it from memory_get and memory_get_observations. It does not explicitly name sibling search tools like memory_search or memory_recent, but the focus on exact terms/identifiers and compact results gives reasonable differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description says to use it when you know exact terms or identifiers, and tells the agent to expand selected IDs with memory_get or memory_get_observations. It does not explicitly say when not to use it or name alternative search tools like memory_search, but the guidance is clear enough for basic selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_timelineB
Read-only

Get a chronological window of memories around an anchor (by ID or query).

ParametersJSON Schema
NameRequiredDescriptionDefault
kindNoFilter by memory kind
queryNoSearch query to find anchor
projectNoFilter by project scope (matches sessions.project)
scope_idNoFilter by a single sharing domain scope_id
memory_idNoAnchor memory ID
trust_biasNo
visibilityNo
depth_afterNoItems after anchor
depth_beforeNoItems before anchor
personal_firstNo
ownership_scopeNo
exclude_actor_idsNo
exclude_scope_idsNoSharing domain scope_ids to exclude
include_actor_idsNo
include_scope_idsNoSharing domain scope_ids to include
exclude_visibilityNo
include_visibilityNo
exclude_trust_statesNo
include_trust_statesNo
exclude_workspace_idsNo
include_workspace_idsNo
widen_shared_when_weakNo
exclude_workspace_kindsNo
include_workspace_kindsNo
widen_shared_min_personal_scoreNo
widen_shared_min_personal_resultsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds the behavioral constraint of a chronological window around an anchor, which is useful context beyond the annotations. However, it does not disclose behaviors like default depth (depth_before/depth_after default 3), ordering direction, or how anchor selection resolves when both memory_id and query are provided. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single 13-word sentence with no filler. It front-loads the core operation ('Get a chronological window') and then adds the key modifier ('around an anchor (by ID or query)'). Every word earns its place, and the structure is immediately scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having an output schema and read-only annotations, this is a highly complex tool (26 parameters, many filters, 0 required). The description fails to explain how to invoke it correctly: whether memory_id or query is required, how they interact, what the default window sizes are, or how filtering parameters shape results. An agent would need substantial external knowledge to call this tool effectively, so the description is not complete for the tool's complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 35%, so the description must compensate for the many undocumented parameters (26 total, 0 required). It only clarifies that the anchor can be specified 'by ID or query', which maps to memory_id and query. It says nothing about depth_before/depth_after, filters (visibility, trust, scope, workspace), or the many include/exclude arrays. This is minimal added meaning over the schema and leaves most parameters semantically unexplained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb ('Get'), resource ('memories'), and a distinctive scoping concept ('chronological window around an anchor'). It differentiates from siblings like memory_recent and memory_search through the anchor/window framing, though it does not explicitly name any sibling. This is clear but slightly below a 5 because the differentiation is implicit rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use the tool: when you need memories around a specific anchor in chronological order. However, it gives no explicit guidance about when to prefer this over alternatives such as memory_search or memory_recent, and no exclusions or prerequisites. Usage context is present only by inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 14 tool updatesv0.44.2
    • Changedmemory_distill_candidates1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "candidates": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "artifact_kind": {
        +            "enum": [
        +              "context_fact",
        +              "skill"
        +            ],
        +            "type": "string"
        +          },
        +          "concepts": {
        +            "items": {
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "draft_text": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "evidence": {
        +            "items": {
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "member_ids": {
        +            "items": {
        +              "maximum": 9007199254740991,
        +              "minimum": -9007199254740991,
        +              "type": "integer"
        +            },
        +            "type": "array"
        +          },
        +          "projects": {
        +            "items": {
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "recurrence": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "representative_id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "scope": {
        +            "enum": [
        +              "project",
        +              "user"
        +            ],
        +            "type": "string"
        +          },
        +          "score": {
        +            "type": "number"
        +          },
        +          "suggested_target": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          }
        +        },
        +        "required": [
        +          "scope",
        +          "suggested_target",
        +          "score",
        +          "recurrence",
        +          "projects",
        +          "member_ids",
        +          "representative_id",
        +          "concepts",
        +          "artifact_kind",
        +          "evidence",
        +          "draft_text"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "metadata": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "candidate_count": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "cluster_count": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "context_document_count": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "corpus_count": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "corpus_limit": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "documented_cluster_count": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "include_documented": {
        +          "type": "boolean"
        +        },
        +        "min_recurrence": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        }
        +      },
        +      "required": [
        +        "candidate_count",
        +        "cluster_count",
        +        "context_document_count",
        +        "corpus_count",
        +        "corpus_limit",
        +        "documented_cluster_count",
        +        "include_documented",
        +        "min_recurrence"
        +      ],
        +      "type": "object"
        +    },
        +    "version": {
        +      "const": 1,
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "version",
        +    "candidates",
        +    "metadata"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_expand1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "anchors": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "body_text": {
        +            "type": "string"
        +          },
        +          "confidence": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "created_at": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "kind": {
        +            "type": "string"
        +          },
        +          "metadata_json": {
        +            "additionalProperties": {},
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          },
        +          "session_id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "title": {
        +            "type": "string"
        +          },
        +          "updated_at": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "kind",
        +          "title",
        +          "body_text"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "errors": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "code": {
        +            "type": "string"
        +          },
        +          "field": {
        +            "type": "string"
        +          },
        +          "ids": {
        +            "items": {
        +              "type": [
        +                "string",
        +                "number"
        +              ]
        +            },
        +            "type": "array"
        +          },
        +          "message": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "code",
        +          "field",
        +          "message"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "metadata": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "include_observations": {
        +          "type": "boolean"
        +        },
        +        "project": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "requested_ids_count": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "returned_anchor_count": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "timeline_count": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        }
        +      },
        +      "required": [
        +        "project",
        +        "requested_ids_count",
        +        "returned_anchor_count",
        +        "timeline_count",
        +        "include_observations"
        +      ],
        +      "type": "object"
        +    },
        +    "missing_ids": {
        +      "items": {
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "type": "array"
        +    },
        +    "observations": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "body_text": {
        +            "type": "string"
        +          },
        +          "confidence": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "created_at": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "kind": {
        +            "type": "string"
        +          },
        +          "metadata_json": {
        +            "additionalProperties": {},
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          },
        +          "session_id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "title": {
        +            "type": "string"
        +          },
        +          "updated_at": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "kind",
        +          "title",
        +          "body_text"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "timeline": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "body_text": {
        +            "type": "string"
        +          },
        +          "confidence": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "created_at": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "kind": {
        +            "type": "string"
        +          },
        +          "metadata_json": {
        +            "additionalProperties": {},
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          },
        +          "session_id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "title": {
        +            "type": "string"
        +          },
        +          "updated_at": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "kind",
        +          "title",
        +          "body_text"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "anchors",
        +    "timeline",
        +    "observations",
        +    "missing_ids",
        +    "errors",
        +    "metadata"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_explain1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "errors": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "code": {
        +            "type": "string"
        +          },
        +          "field": {
        +            "type": "string"
        +          },
        +          "ids": {
        +            "items": {
        +              "type": [
        +                "string",
        +                "number"
        +              ]
        +            },
        +            "type": "array"
        +          },
        +          "message": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "code",
        +          "field",
        +          "message"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "items": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "created_at": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "kind": {
        +            "type": "string"
        +          },
        +          "matches": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "project_match": {
        +                "type": [
        +                  "boolean",
        +                  "null"
        +                ]
        +              },
        +              "query_terms": {
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            },
        +            "required": [
        +              "query_terms",
        +              "project_match"
        +            ],
        +            "type": "object"
        +          },
        +          "pack_context": {
        +            "anyOf": [
        +              {
        +                "additionalProperties": {},
        +                "properties": {
        +                  "included": {
        +                    "type": [
        +                      "boolean",
        +                      "null"
        +                    ]
        +                  },
        +                  "section": {
        +                    "type": [
        +                      "string",
        +                      "null"
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "included",
        +                  "section"
        +                ],
        +                "type": "object"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ]
        +          },
        +          "project": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "retrieval": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "rank": {
        +                "anyOf": [
        +                  {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  {
        +                    "type": "null"
        +                  }
        +                ]
        +              },
        +              "source": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "source",
        +              "rank"
        +            ],
        +            "type": "object"
        +          },
        +          "role": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "inferred": {
        +                "type": "string"
        +              },
        +              "reason": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "inferred",
        +              "reason"
        +            ],
        +            "type": "object"
        +          },
        +          "score": {
        +            "additionalProperties": {},
        +            "properties": {
        +              "components": {
        +                "additionalProperties": {},
        +                "properties": {
        +                  "base": {
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  },
        +                  "kind_bonus": {
        +                    "type": "number"
        +                  },
        +                  "personal_bias": {
        +                    "type": "number"
        +                  },
        +                  "recency": {
        +                    "type": "number"
        +                  },
        +                  "semantic_boost": {
        +                    "type": [
        +                      "number",
        +                      "null"
        +                    ]
        +                  }
        +                },
        +                "required": [
        +                  "base",
        +                  "recency",
        +                  "kind_bonus",
        +                  "personal_bias",
        +                  "semantic_boost"
        +                ],
        +                "type": "object"
        +              },
        +              "total": {
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              }
        +            },
        +            "required": [
        +              "total",
        +              "components"
        +            ],
        +            "type": "object"
        +          },
        +          "title": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "kind",
        +          "title",
        +          "created_at",
        +          "project",
        +          "retrieval",
        +          "score",
        +          "role",
        +          "matches",
        +          "pack_context"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "metadata": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "include_pack_context": {
        +          "type": "boolean"
        +        },
        +        "project": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "query": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "requested_ids_count": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "returned_items_count": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "sanitized_query": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "query",
        +        "project",
        +        "requested_ids_count",
        +        "returned_items_count",
        +        "include_pack_context"
        +      ],
        +      "type": "object"
        +    },
        +    "missing_ids": {
        +      "items": {
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "items",
        +    "missing_ids",
        +    "errors",
        +    "metadata"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_forget1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "status": {
        +      "const": "ok",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "status"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_get1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": {},
        +  "properties": {
        +    "body_text": {
        +      "type": "string"
        +    },
        +    "confidence": {
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "created_at": {
        +      "type": "string"
        +    },
        +    "id": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "kind": {
        +      "type": "string"
        +    },
        +    "metadata_json": {
        +      "additionalProperties": {},
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "session_id": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "title": {
        +      "type": "string"
        +    },
        +    "updated_at": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "id",
        +    "kind",
        +    "title",
        +    "body_text"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_get_observations1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "items": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "body_text": {
        +            "type": "string"
        +          },
        +          "confidence": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "created_at": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "kind": {
        +            "type": "string"
        +          },
        +          "metadata_json": {
        +            "additionalProperties": {},
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          },
        +          "session_id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "title": {
        +            "type": "string"
        +          },
        +          "updated_at": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "kind",
        +          "title",
        +          "body_text"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "items"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_learn1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "client_hint": {
        +      "type": "string"
        +    },
        +    "forget": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "examples": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "how": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "when": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "required": [
        +        "when",
        +        "how",
        +        "examples"
        +      ],
        +      "type": "object"
        +    },
        +    "intro": {
        +      "type": "string"
        +    },
        +    "persistence": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "examples": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "how": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "when": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "required": [
        +        "when",
        +        "how",
        +        "examples"
        +      ],
        +      "type": "object"
        +    },
        +    "prompt_hint": {
        +      "type": "string"
        +    },
        +    "recall": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "examples": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "how": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "when": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "required": [
        +        "when",
        +        "how",
        +        "examples"
        +      ],
        +      "type": "object"
        +    },
        +    "recommended_system_prompt": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "intro",
        +    "client_hint",
        +    "recall",
        +    "persistence",
        +    "forget",
        +    "prompt_hint",
        +    "recommended_system_prompt"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_pack1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "context": {
        +      "type": "string"
        +    },
        +    "item_ids": {
        +      "items": {
        +        "maximum": 9007199254740991,
        +        "minimum": -9007199254740991,
        +        "type": "integer"
        +      },
        +      "type": "array"
        +    },
        +    "items": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "body": {
        +            "type": "string"
        +          },
        +          "confidence": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "kind": {
        +            "type": "string"
        +          },
        +          "metadata": {
        +            "additionalProperties": {},
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          },
        +          "title": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "kind",
        +          "title",
        +          "body",
        +          "confidence",
        +          "metadata"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "metrics": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "fallback_used": {
        +          "type": "boolean"
        +        },
        +        "limit": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "pack_item_ids": {
        +          "items": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "type": "array"
        +        },
        +        "pack_tokens": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "project": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "total_items": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        }
        +      },
        +      "required": [
        +        "total_items",
        +        "pack_tokens",
        +        "fallback_used",
        +        "limit",
        +        "project",
        +        "pack_item_ids"
        +      ],
        +      "type": "object"
        +    },
        +    "pack_text": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "context",
        +    "items",
        +    "item_ids",
        +    "pack_text",
        +    "metrics"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_recent1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "items": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "body_text": {
        +            "type": "string"
        +          },
        +          "confidence": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "created_at": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "kind": {
        +            "type": "string"
        +          },
        +          "metadata_json": {
        +            "additionalProperties": {},
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          },
        +          "session_id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "title": {
        +            "type": "string"
        +          },
        +          "updated_at": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "kind",
        +          "title",
        +          "body_text"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "items"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_remember1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "id": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "id"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_schema1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "fields": {
        +      "additionalProperties": {
        +        "type": "string"
        +      },
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "filters": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "kind_descriptions": {
        +      "additionalProperties": {
        +        "type": "string"
        +      },
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "kinds": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "kinds",
        +    "kind_descriptions",
        +    "fields",
        +    "filters"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_search1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "items": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "body": {
        +            "type": "string"
        +          },
        +          "confidence": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "kind": {
        +            "type": "string"
        +          },
        +          "metadata": {
        +            "additionalProperties": {},
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          },
        +          "score": {
        +            "type": "number"
        +          },
        +          "session_id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "title": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "kind",
        +          "title",
        +          "body"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "items"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_search_index1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "items": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "created_at": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "kind": {
        +            "type": "string"
        +          },
        +          "metadata": {
        +            "additionalProperties": {},
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          },
        +          "score": {
        +            "type": "number"
        +          },
        +          "session_id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "title": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "kind",
        +          "title",
        +          "score",
        +          "created_at",
        +          "session_id",
        +          "metadata"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "items"
        +  ],
        +  "type": "object"
        +}
    • Changedmemory_timeline1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "items": {
        +      "items": {
        +        "additionalProperties": {},
        +        "properties": {
        +          "body_text": {
        +            "type": "string"
        +          },
        +          "confidence": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "created_at": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "kind": {
        +            "type": "string"
        +          },
        +          "metadata_json": {
        +            "additionalProperties": {},
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          },
        +          "session_id": {
        +            "maximum": 9007199254740991,
        +            "minimum": -9007199254740991,
        +            "type": "integer"
        +          },
        +          "title": {
        +            "type": "string"
        +          },
        +          "updated_at": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "kind",
        +          "title",
        +          "body_text"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "items"
        +  ],
        +  "type": "object"
        +}
  2. 14 tool updates
    • First observedmemory_distill_candidates
    • First observedmemory_expand
    • First observedmemory_explain
    • First observedmemory_forget
    • First observedmemory_get
    • First observedmemory_get_observations
    • First observedmemory_learn
    • First observedmemory_pack
    • First observedmemory_recent
    • First observedmemory_remember
    • First observedmemory_schema
    • First observedmemory_search
    • First observedmemory_search_index
    • First observedmemory_timeline

TDQS

B3.3/5.0

Scored across 14 tools

Disambiguation4/5

Most tools are clearly distinct: memory_search vs memory_search_index differ by return format, memory_get vs memory_get_observations differ by cardinality, and memory_pack is explicitly for context building. A couple of retrieval tools could be confused, particularly memory_timeline and memory_expand, which both involve surrounding context.

Naming Consistency4/5

All tools share the memory_ prefix and use lowercase snake_case, making the set feel predictable. Minor inconsistency exists in mixing verb forms (memory_search, memory_expand, memory_get) with noun or adjective forms (memory_schema, memory_recent, memory_timeline), but the overall pattern is still coherent.

Tool Count4/5

14 tools is on the higher end of the well-scoped range, and most tools serve a distinct retrieval or lifecycle purpose. The count is slightly heavy due to many specialized read/search variants, but it remains reasonable for a memory-management server.

Completeness3/5

The core memory lifecycle is mostly covered: create via memory_remember, read via memory_get/get_observations/search/recent, and soft-delete via memory_forget. However, there is no memory_update or memory_edit tool, which is a notable gap for managing evolving memories.

Maintenance

ActivityActive
ResponsivenessSlow

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    C
    maintenance
    MCP server that provides cross-session persistent memory for AI coding assistants using local vector database and semantic search, enabling automatic recall of project context, issues, and tasks.
    9
    22 PyPI
    91
    Apache 2.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    Persistent memory MCP server for Claude Code that captures and recalls project context across sessions, eliminating the need to re-explain architecture and decisions daily.
    280 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A persistent memory MCP server for Claude Code that enables long-term recall across sessions via hybrid search, code intelligence, and tools for reading/writing memory.
    5 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server that captures and recalls coding session memory (failures, decisions, diffs) for AI agents, enabling cross-agent continuity and preventing repeated mistakes.
    41 npm
    MIT